Esempio n. 1
0
        internal static bool CanDeriveFact <TFactWork, TFactRule, TWantAction, TFactContainer>(IRuntimeConditionFact conditionFact, IFactType searchFactType, TFactWork factWork, IFactRulesContext <TFactRule, TWantAction, TFactContainer> context)
            where TFactWork : IFactWork
            where TFactRule : IFactRule
            where TWantAction : IWantAction
            where TFactContainer : IFactContainer
        {
            if (context.SingleEntity.CanExtractFact(searchFactType, factWork, context))
            {
                return(true);
            }

            var rulesWithoutConditionFact = context.FactRules
                                            .FindAll(rule => rule.InputFactTypes
                                                     .All(factType => !factType.EqualsFactType(context.Cache.GetFactType(conditionFact))));

            var request = new BuildTreeForFactInfoRequest <TFactRule, TWantAction, TFactContainer>
            {
                WantFactType = searchFactType,
                Context      = new FactRulesContext <TFactRule, TWantAction, TFactContainer>
                {
                    Cache        = context.Cache,
                    Container    = context.Container,
                    FactRules    = rulesWithoutConditionFact,
                    SingleEntity = context.SingleEntity,
                    TreeBuilding = context.TreeBuilding,
                    WantAction   = context.WantAction,
                    Engine       = context.Engine,
                },
            };

            try
            {
                return(context.TreeBuilding.TryBuildTreeForFactInfo(request, out var _, out var _));
            }
            catch (InvalidDeriveOperationException ex)
            {
                if (ex.Details != null && ex.Details.Count == 1)
                {
                    DeriveErrorDetail detail = ex.Details.First();

                    if (detail.Code == ErrorCode.RuleNotFound || detail.Code == ErrorCode.EmptyRuleCollection)
                    {
                        return(false);
                    }
                }

                throw;
            }
        }
        /// <inheritdoc/>
        public bool TryBuildTreesForWantAction <TFactRule, TWantAction, TFactContainer>(BuildTreesForWantActionRequest <TFactRule, TWantAction, TFactContainer> request, out BuildTreesForWantActionResult <TFactRule, TWantAction, TFactContainer> result)
            where TFactRule : IFactRule
            where TWantAction : IWantAction
            where TFactContainer : IFactContainer
        {
            var context = request.Context;
            var deriveFactErrorDetails = new List <DeriveFactErrorDetail>();
            var wantActionInfo         = new WantActionInfo <TWantAction, TFactContainer>
            {
                BuildFailedConditions  = new List <IBuildConditionFact>(),
                BuildSuccessConditions = new List <IBuildConditionFact>(),
                RuntimeConditions      = new List <IRuntimeConditionFact>(),
                Context = context,
            };

            result = new BuildTreesForWantActionResult <TFactRule, TWantAction, TFactContainer>
            {
                TreesResult    = new List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> >(),
                WantActionInfo = wantActionInfo,
            };

            foreach (var needFactType in context.SingleEntity.GetRequiredTypesOfFacts(context.WantAction, context))
            {
                if (needFactType.IsFactType <IBuildConditionFact>())
                {
                    if (wantActionInfo.BuildSuccessConditions.Exists(fact => context.Cache.GetFactType(fact).EqualsFactType(needFactType)) || wantActionInfo.BuildFailedConditions.Exists(fact => context.Cache.GetFactType(fact).EqualsFactType(needFactType)))
                    {
                        continue;
                    }

                    var condition = Factory.CreateObject(
                        type => type.CreateBuildConditionFact <IBuildConditionFact>(),
                        needFactType
                        );

                    if (condition.Condition(context.WantAction, context, ct => ct.WantAction.GetCompatibleRulesEx(request.FactRules, context)))
                    {
                        result.WantActionInfo.BuildSuccessConditions.Add(condition);
                    }
                    else
                    {
                        result.WantActionInfo.BuildFailedConditions.Add(condition);
                        deriveFactErrorDetails.Add(new DeriveFactErrorDetail(needFactType, null));
                    }

                    continue;
                }

                if (needFactType.IsFactType <IRuntimeConditionFact>())
                {
                    var condition = Factory.CreateObject(
                        type => type.CreateRuntimeConditionFact <IRuntimeConditionFact>(),
                        needFactType);

                    result.WantActionInfo.RuntimeConditions.Add(condition);

                    continue;
                }

                var requestFactType = new BuildTreeForFactInfoRequest <TFactRule, TWantAction, TFactContainer>
                {
                    WantFactType = needFactType,
                    Context      = new FactRulesContext <TFactRule, TWantAction, TFactContainer>
                    {
                        Cache     = context.Cache,
                        Container = context.Container,
                        FactRules = context
                                    .WantAction
                                    .GetCompatibleRulesEx(request.FactRules, context),
                        SingleEntity = context.SingleEntity,
                        TreeBuilding = context.TreeBuilding,
                        WantAction   = context.WantAction,
                        Engine       = context.Engine,
                    },
                };

                if (context.TreeBuilding.TryBuildTreeForFactInfo(requestFactType, out var resultTree, out var errorList))
                {
                    result.TreesResult.Add(resultTree);
                }
        /// <inheritdoc/>
        public virtual bool TryBuildTreeForFactInfo <TFactRule, TWantAction, TFactContainer>(BuildTreeForFactInfoRequest <TFactRule, TWantAction, TFactContainer> request, out TreeByFactRule <TFactRule, TWantAction, TFactContainer> treeResult, out List <DeriveFactErrorDetail> deriveFactErrorDetails)
            where TFactRule : IFactRule
            where TWantAction : IWantAction
            where TFactContainer : IFactContainer
        {
            var context = request.Context;

            treeResult             = null;
            deriveFactErrorDetails = null;

            // find the rules that can calculate the fact
            List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > treesByWantFactType = request.GetTreesByRequest();
            var treeReady = treesByWantFactType.FirstOrDefault(tree => tree.Status == TreeStatus.Built);

            if (treeReady != null)
            {
                treeResult = treeReady;
                return(true);
            }

            List <List <IFactType> > notFoundFactSet = treesByWantFactType.ConvertAll(item => new List <IFactType>());
            var allFinichedNodes = new Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> >();

            while (true)
            {
                for (int i = treesByWantFactType.Count - 1; i >= 0; i--)
                {
                    var treeByWantFactType = treesByWantFactType[i];

                    if (treeByWantFactType.Status != TreeStatus.BeingBuilt)
                    {
                        continue;
                    }

                    int lastlevelNumber = treeByWantFactType.Levels.Count - 1;

                    // If after synchronization we can calculate the tree.
                    if (TrySyncTreeLevelsAndFinishedNodes(treeByWantFactType, lastlevelNumber, allFinichedNodes))
                    {
                        treeByWantFactType.Built();
                        continue;
                    }

                    List <NodeByFactRule <TFactRule> > lastTreeLevel = treeByWantFactType.Levels[lastlevelNumber];

                    // If in the last level there are no nodes for calculation, then the tree can be calculated.
                    if (lastTreeLevel.Count == 0)
                    {
                        treeByWantFactType.Built();
                        continue;
                    }

                    // Next level nodes.
                    var  nextTreeLevel             = new List <NodeByFactRule <TFactRule> >();
                    var  currentLevelFinishedNodes = new Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> >();
                    bool cannotDerived             = false;

                    for (int j = 0; j < lastTreeLevel.Count; j++)
                    {
                        NodeByFactRule <TFactRule>     node     = lastTreeLevel[j];
                        NodeByFactRuleInfo <TFactRule> nodeInfo = node.Info;
                        Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> > copatibleAllFinishedNodes = nodeInfo.GetCompatibleFinishedNodes(allFinichedNodes, context);
                        List <IFactType> needFacts = nodeInfo
                                                     .RequiredFactTypes
                                                     .FindAll(needFactType => !CanRemoveFromNeedFactTypes(needFactType, node, context, copatibleAllFinishedNodes));

                        // If the rule can be calculated from the parameters in the container, then add the node to the list of complete.
                        if (needFacts.IsNullOrEmpty())
                        {
                            allFinichedNodes.Add(node.Info, node);
                            currentLevelFinishedNodes.Add(node.Info, node);
                            continue;
                        }

                        bool canTryRemoveNode = false;
                        foreach (var needFact in needFacts)
                        {
                            if (needFact.IsFactType <ISpecialFact>())
                            {
                                if (!canTryRemoveNode)
                                {
                                    canTryRemoveNode = true;
                                }

                                notFoundFactSet[i].Add(needFact);
                                continue;
                            }

                            var needRules = nodeInfo
                                            .CompatibleRules
                                            .FindAll(rule => rule.OutputFactType.EqualsFactType(needFact) && !rule.RuleContainBranch(node));

                            if (needRules.Count > 0)
                            {
                                List <NodeByFactRule <TFactRule> > nodes = needRules.GetNodesByRules(node, treeByWantFactType);
                                nextTreeLevel.AddRange(nodes);
                                node.Childs.AddRange(nodes);
                            }
                            else
                            {
                                if (!canTryRemoveNode)
                                {
                                    canTryRemoveNode = true;
                                }

                                notFoundFactSet[i].Add(needFact);
                            }
                        }

                        if (canTryRemoveNode)
                        {
                            // Is there a neighboring node capable of deriving this fact.
                            cannotDerived = TryRemoveRootNode(node, treeByWantFactType, lastlevelNumber);
                            j--;
                        }
                    }

                    if (cannotDerived)
                    {
                        treeByWantFactType.Cencel();
                    }
                    else if (currentLevelFinishedNodes.Count > 0)
                    {
                        if (TrySyncTreeLevelsAndFinishedNodes(treeByWantFactType, lastlevelNumber, currentLevelFinishedNodes))
                        {
                            treeByWantFactType.Built();
                        }
                        else if (nextTreeLevel.Count > 0)
                        {
                            SyncTreeLevelAndFinishedNodes(nextTreeLevel, currentLevelFinishedNodes, context);
                            treeByWantFactType.Levels.Add(nextTreeLevel);
                        }
                    }
                    else if (nextTreeLevel.Count > 0)
                    {
                        treeByWantFactType.Levels.Add(nextTreeLevel);
                    }
                    else
                    {
                        treeByWantFactType.Built();
                    }
                }

                List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > builtTrees = treesByWantFactType
                                                                                             .FindAll(tree => tree.Status == TreeStatus.Built);

                if (builtTrees.Count != 0)
                {
                    var countRuleByBuiltTrees = builtTrees.ToDictionary(tree => tree, tree => tree.GetUniqueRulesFromTree().Count);
                    int minRuleCount          = countRuleByBuiltTrees.Min(item => item.Value);
                    var suitableTree          = countRuleByBuiltTrees.First(item => item.Value == minRuleCount).Key;

                    foreach (var tree in treesByWantFactType)
                    {
                        if (tree != suitableTree && tree.Status != TreeStatus.Cencel && tree.GetUniqueRulesFromTree().Count >= minRuleCount)
                        {
                            tree.Cencel();
                        }
                    }

                    if (treesByWantFactType.All(tree => tree.Status != TreeStatus.BeingBuilt))
                    {
                        treeResult = suitableTree;
                        return(true);
                    }
                }

                if (treesByWantFactType.All(tree => tree.Status == TreeStatus.Cencel))
                {
                    break;
                }
            }

            deriveFactErrorDetails = new List <DeriveFactErrorDetail>();

            foreach (var factSet in notFoundFactSet)
            {
                if (factSet.Count != 0)
                {
                    deriveFactErrorDetails.Add(new DeriveFactErrorDetail(request.WantFactType, factSet.AsReadOnly()));
                }
            }

            return(false);
        }
        /// <summary>
        /// Get <see cref="TreeByFactRule{TFactRule, TWantAction, TFactContainer}"/> by <paramref name="request"/>.
        /// </summary>
        /// <typeparam name="TFactRule"></typeparam>
        /// <typeparam name="TWantAction"></typeparam>
        /// <typeparam name="TFactContainer"></typeparam>
        /// <param name="request"></param>
        /// <returns></returns>
        internal static List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > GetTreesByRequest <TFactRule, TWantAction, TFactContainer>(this BuildTreeForFactInfoRequest <TFactRule, TWantAction, TFactContainer> request)
            where TFactRule : IFactRule
            where TWantAction : IWantAction
            where TFactContainer : IFactContainer
        {
            var context   = request.Context;
            var factRules = request.Context.FactRules;

            if (factRules.IsNullOrEmpty())
            {
                throw CommonHelper.CreateDeriveException(ErrorCode.EmptyRuleCollection, "Rules cannot be null.");
            }

            var needRules = factRules
                            .Where(rule => rule.OutputFactType.EqualsFactType(request.WantFactType))
                            .ToList();

            if (needRules.IsNullOrEmpty())
            {
                throw CommonHelper.CreateDeriveException(ErrorCode.RuleNotFound, $"No rules found able to calculate fact {request.WantFactType.FactName}.");
            }

            var nodeInfos = needRules.ConvertAll(rule => new NodeByFactRuleInfo <TFactRule>
            {
                BuildSuccessConditions = new List <IBuildConditionFact>(rule.InputFactTypes.Count(type => type.IsFactType <IBuildConditionFact>())),
                BuildFailedConditions  = new List <IBuildConditionFact>(),
                RuntimeConditions      = new List <IRuntimeConditionFact>(rule.InputFactTypes.Count(type => type.IsFactType <IRuntimeConditionFact>())),
                Rule = rule,
                RequiredFactTypes = context.SingleEntity.GetRequiredTypesOfFacts(rule, context).ToList(),
                CompatibleRules   = rule.GetCompatibleRulesEx(context.FactRules, context),
            });

            return(nodeInfos.ConvertAll(info =>
            {
                var node = new NodeByFactRule <TFactRule>
                {
                    Childs = new List <NodeByFactRule <TFactRule> >(),
                    Info = info,
                };

                var tree = new TreeByFactRule <TFactRule, TWantAction, TFactContainer>
                {
                    Levels = new List <List <NodeByFactRule <TFactRule> > >
                    {
                        new List <NodeByFactRule <TFactRule> > {
                            node
                        },
                    },
                    NodeInfos = nodeInfos,
                    Root = node,
                    Context = context,
                };

                if (info.RequiredFactTypes.Count == 0)
                {
                    tree.Built();
                }

                return tree;
            }));
        }