<commit_before>﻿namespace Serviceable.Objects.Composition.Graph
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Dependencies;
    using Exceptions;
    using Microsoft.CSharp.RuntimeBinder;
    using Stages.Configuration;

    public sealed class GraphContext : Context<GraphContext> // TODO: IDisposable
    {
        internal readonly Container Container;
        internal readonly List<GraphNodeContext> InputNodes = new List<GraphNodeContext>();
        internal readonly List<GraphVertexContext> Vertices = new List<GraphVertexContext>();
        internal readonly List<GraphNodeContext> Nodes = new List<GraphNodeContext>();

        public GraphContext(Container container = null)
        {
            this.Container = container ?? new Container();
        }

        // TODO: break public methods to commands

        public void AddInput(Type type, string id)
        {
            Check.ArgumentNull(type, nameof(type));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var abstractContext = Container.CreateObject(type) as AbstractContext;
            Check.ArgumentNull(abstractContext, nameof(type), "Type should be derived from Context");

            AddInput(abstractContext, id);
        }

        public void AddInput(AbstractContext context, string id)
        {
            Check.ArgumentNull(context, nameof(context));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var node = new GraphNodeContext(context, this, id);
            InputNodes.Add(node);
            Nodes.Add(node);
        }

        public void AddNode(Type type, string id)
        {
            Check.ArgumentNull(type, nameof(type));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var abstractContext = Container.CreateObject(type) as AbstractContext;
            Check.ArgumentNull(abstractContext, nameof(type), "Type should be derived from Context");

            AddNode(abstractContext, id);
        }

        public void AddNode(AbstractContext context, string id)
        {
            Check.ArgumentNull(context, nameof(context));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var node = new GraphNodeContext(context, this, id);
            Nodes.Add(node);
        }

        public void ConnectNodes(string fromId, string toId)
        {
            Check.ArgumentNullOrWhiteSpace(fromId, nameof(fromId));
            Check.ArgumentNullOrWhiteSpace(toId, nameof(toId));

            var parentNode = Nodes.FirstOrDefault(x => x.Id == fromId);
            Check.ArgumentNull(parentNode, nameof(fromId), $"Parent node with id '${fromId}' could not be found");

            var childNode = Nodes.FirstOrDefault(x => x.Id == toId);
            Check.ArgumentNull(childNode, nameof(toId), $"Parent node with id '${toId}' could not be found");

            Check.Argument(Vertices.Any(x => x.FromId == fromId && x.ToId == toId), nameof(fromId), "Vertex already exists in this graph");

            Vertices.Add(new GraphVertexContext
            {
                FromId = fromId,
                ToId = toId,
            });
        }

        public void Configure()
        {
            var configurationSource = Container.Resolve<IConfigurationSource>();
            Nodes.ForEach(x => x.Configure(configurationSource));
        }

        public void Initialize()
        {
            Nodes.ForEach(x => x.Initialize());
        }

        public IEnumerable<Stack<EventResult>> Execute(dynamic command)
        {
            Check.ArgumentNull(command, nameof(command));

            var allResultStacks = new List<Stack<EventResult>>(InputNodes.Count);
            var oneHasRun = false;
            foreach (var inputNode in InputNodes)
            {
                try
                {
                    var resultExecutionStack = new Stack<EventResult>();
                    inputNode.Execute(command, resultExecutionStack);
                    allResultStacks.Add(resultExecutionStack);
                    oneHasRun = true;
                }
                catch (NotSupportedException)
                {
                    // Only apply to the ones that support that
                }
            }

            if (!oneHasRun)
            {
                throw new NotSupportedException("No context found that support this command");
            }

            return allResultStacks;
        }

        public Stack<EventResult> Execute(dynamic command, string uniqueId)
        {
            Check.ArgumentNull(command, nameof(command));
            Check.ArgumentNullOrWhiteSpace(uniqueId, nameof(uniqueId));

            try
            {
                var resultExecutionStack = new Stack<EventResult>();
                InputNodes.First(x => x.Id == uniqueId).Execute(command, resultExecutionStack);
                return resultExecutionStack;
            }
            catch (RuntimeBinderException ex)
            {
                throw new NotSupportedException(
                    "This type of command is not supported by context (Tip: Only one implementation of ICommand<,> can be inferred automatically)",
                    ex);
            }
        }

        public IEnumerable<GraphNodeContext> GetChildren(string id)
        {
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            return Vertices.Where(x => x.FromId == id).Select(x => Nodes.First(y => y.Id == x.ToId));
        }
    }
}
<commit_msg>Self register to container when creating a graph so it can be injectable from the bottom stack<commit_after>﻿namespace Serviceable.Objects.Composition.Graph
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Dependencies;
    using Exceptions;
    using Microsoft.CSharp.RuntimeBinder;
    using Stages.Configuration;

    public sealed class GraphContext : Context<GraphContext> // TODO: IDisposable
    {
        internal readonly Container Container;
        internal readonly List<GraphNodeContext> InputNodes = new List<GraphNodeContext>();
        internal readonly List<GraphVertexContext> Vertices = new List<GraphVertexContext>();
        internal readonly List<GraphNodeContext> Nodes = new List<GraphNodeContext>();

        public GraphContext(Container container = null)
        {
            this.Container = container ?? new Container();
            this.Container.Register(this);
        }

        // TODO: break public methods to commands

        public void AddInput(Type type, string id)
        {
            Check.ArgumentNull(type, nameof(type));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var abstractContext = Container.CreateObject(type) as AbstractContext;
            Check.ArgumentNull(abstractContext, nameof(type), "Type should be derived from Context");

            AddInput(abstractContext, id);
        }

        public void AddInput(AbstractContext context, string id)
        {
            Check.ArgumentNull(context, nameof(context));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var node = new GraphNodeContext(context, this, id);
            InputNodes.Add(node);
            Nodes.Add(node);
        }

        public void AddNode(Type type, string id)
        {
            Check.ArgumentNull(type, nameof(type));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var abstractContext = Container.CreateObject(type) as AbstractContext;
            Check.ArgumentNull(abstractContext, nameof(type), "Type should be derived from Context");

            AddNode(abstractContext, id);
        }

        public void AddNode(AbstractContext context, string id)
        {
            Check.ArgumentNull(context, nameof(context));
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            var node = new GraphNodeContext(context, this, id);
            Nodes.Add(node);
        }

        public void ConnectNodes(string fromId, string toId)
        {
            Check.ArgumentNullOrWhiteSpace(fromId, nameof(fromId));
            Check.ArgumentNullOrWhiteSpace(toId, nameof(toId));

            var parentNode = Nodes.FirstOrDefault(x => x.Id == fromId);
            Check.ArgumentNull(parentNode, nameof(fromId), $"Parent node with id '${fromId}' could not be found");

            var childNode = Nodes.FirstOrDefault(x => x.Id == toId);
            Check.ArgumentNull(childNode, nameof(toId), $"Parent node with id '${toId}' could not be found");

            Check.Argument(Vertices.Any(x => x.FromId == fromId && x.ToId == toId), nameof(fromId), "Vertex already exists in this graph");

            Vertices.Add(new GraphVertexContext
            {
                FromId = fromId,
                ToId = toId,
            });
        }

        public void Configure()
        {
            var configurationSource = Container.Resolve<IConfigurationSource>();
            Nodes.ForEach(x => x.Configure(configurationSource));
        }

        public void Initialize()
        {
            Nodes.ForEach(x => x.Initialize());
        }

        public IEnumerable<Stack<EventResult>> Execute(dynamic command)
        {
            Check.ArgumentNull(command, nameof(command));

            var allResultStacks = new List<Stack<EventResult>>(InputNodes.Count);
            var oneHasRun = false;
            foreach (var inputNode in InputNodes)
            {
                try
                {
                    var resultExecutionStack = new Stack<EventResult>();
                    inputNode.Execute(command, resultExecutionStack);
                    allResultStacks.Add(resultExecutionStack);
                    oneHasRun = true;
                }
                catch (NotSupportedException)
                {
                    // Only apply to the ones that support that
                }
            }

            if (!oneHasRun)
            {
                throw new NotSupportedException("No context found that support this command");
            }

            return allResultStacks;
        }

        public Stack<EventResult> Execute(dynamic command, string uniqueId)
        {
            Check.ArgumentNull(command, nameof(command));
            Check.ArgumentNullOrWhiteSpace(uniqueId, nameof(uniqueId));

            try
            {
                var resultExecutionStack = new Stack<EventResult>();
                InputNodes.First(x => x.Id == uniqueId).Execute(command, resultExecutionStack);
                return resultExecutionStack;
            }
            catch (RuntimeBinderException ex)
            {
                throw new NotSupportedException(
                    "This type of command is not supported by context (Tip: Only one implementation of ICommand<,> can be inferred automatically)",
                    ex);
            }
        }

        public IEnumerable<GraphNodeContext> GetChildren(string id)
        {
            Check.ArgumentNullOrWhiteSpace(id, nameof(id));

            return Vertices.Where(x => x.FromId == id).Select(x => Nodes.First(y => y.Id == x.ToId));
        }
    }
}

{'fraction_non_alphanumeric': 0.09119440459110474, 'fraction_numerical': 0.0, 'mean_word_length': 2.020855904658722, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5320611', 'n_tokens_mistral': 2788, 'n_tokens_neox': 2683, 'n_words': 673}