/*
         * this method is to create virtual nodes where a certain node has 'AND' or 'MANDATORY_AND', and 'OR' children at the same time.
         * when a virtual node is created, all 'AND' children should be connected to the virtual node as 'AND' children
         * and the virtual node should be a 'OR' child of the original parent node
         */
        public Dictionary <string, Node> HandlingVirtualNode(List <Dependency> dependencyList)
        {
            Dictionary <string, Node> virtualNodeMap = new Dictionary <string, Node>();


            nodeSet.GetNodeMap().Values.ToList().ForEach((node) => {
                virtualNodeMap.Add(node.GetNodeName(), node);
                List <Dependency> dpList = dependencyList.Where(dp => node.GetNodeName().Equals(dp.GetParentNode().GetNodeName())).ToList();


                /*
                 * need to handle Mandatory, optionally, possibly NodeOptions
                 */
                int and          = 0;
                int mandatoryAnd = 0;
                int or           = 0;
                if (dpList.Count != 0)
                {
                    foreach (Dependency dp in dpList) //can this for each loop be converted to dpList.stream().forEachOrdered() ?
                    {
                        if ((dp.GetDependencyType() & DependencyType.GetAnd()) == DependencyType.GetAnd())
                        {
                            and++;
                            if (dp.GetDependencyType() == (DependencyType.GetMandatory() | DependencyType.GetAnd()))
                            {
                                mandatoryAnd++;
                            }
                        }
                        else if ((dp.GetDependencyType() & DependencyType.GetOr()) == DependencyType.GetOr())
                        {
                            or++;
                        }
                    }
                    bool hasAndOr = (and > 0 && or > 0) ? true : false;
                    if (hasAndOr)
                    {
                        string parentNodeOfVirtualNodeName = node.GetNodeName();
                        Node virtualNode = new ValueConclusionLine("VirtualNode-" + parentNodeOfVirtualNodeName, Tokenizer.GetTokens("VirtualNode-" + parentNodeOfVirtualNodeName));
                        this.nodeSet.GetNodeIdMap().Add(virtualNode.GetNodeId(), "VirtualNode-" + parentNodeOfVirtualNodeName);
                        virtualNodeMap.Add("VirtualNode-" + parentNodeOfVirtualNodeName, virtualNode);
                        if (mandatoryAnd > 0)
                        {
                            dependencyList.Add(new Dependency(node, virtualNode, (DependencyType.GetMandatory() | DependencyType.GetOr())));
                        }
                        else
                        {
                            dependencyList.Add(new Dependency(node, virtualNode, DependencyType.GetOr()));
                        }
                        dpList.Where(dp => dp.GetDependencyType() == DependencyType.GetAnd() || dp.GetDependencyType() == (DependencyType.GetMandatory() | DependencyType.GetAnd()))
                        .ToList().ForEach(dp => dp.SetParentNode(virtualNode));
                    }
                }
            });
            return(virtualNodeMap);
        }
        public void HandleChild(string parentText, string childText, string firstKeywordsGroup, int lineNumber)
        {
            /*
             * the reason for using '*' at the last group of pattern within comparison is that
             * the last group contains No, Da, De, Ha, Url, Id.
             * In order to track more than one character within the square bracket of last group '*'(Matches 0 or more occurrences of the preceding expression) needs to be used.
             *
             */
            int dependencyType = 0;

            // is 'ITEM' child line
            if (Regex.Match(childText, "(ITEM)(.*)").Success)
            {
                if (!Regex.Match(parentText, "(.*)(AS LIST)").Success)
                {
                    HandleWarning(childText);
                    return;
                }

                // is an indented item child

                childText = childText.Remove(childText.IndexOf("ITEM", StringComparison.CurrentCulture), "ITEM".Length).Trim();

                MetaType?metaType = null;
                if (Regex.Match(parentText, "^(INPUT)(.*)").Success)
                {
                    metaType = MetaType.INPUT;
                }
                else if (Regex.Match(parentText, "^(FIXED)(.*)").Success)
                {
                    metaType = MetaType.FIXED;
                }
                HandleListItem(parentText, childText, metaType);
            }
            else  // is 'A-statement', 'A IS B', 'A <= B', or 'A IS CALC (B * C)' child line
            {
                if (Regex.Match(firstKeywordsGroup, "^(AND\\s?)(.*)").Success)
                {
                    dependencyType = HandleNotKnownManOptPos(firstKeywordsGroup, DependencyType.GetAnd()); // 8-AND | 1-KNOWN? 2-NOT? 64-MANDATORY? 32-OPTIONALLY? 16-POSSIBLY?
                }
                else if (Regex.Match(firstKeywordsGroup, "^(OR\\s?)(.*)").Success)
                {
                    dependencyType = HandleNotKnownManOptPos(firstKeywordsGroup, DependencyType.GetOr()); // 4-OR | 1-KNOWN? 2-NOT? 64-MANDATORY? 32-OPTIONALLY? 16-POSSIBLY?
                }
                else if (Regex.Match(firstKeywordsGroup, "^(WANTS)").Success)
                {
                    dependencyType = DependencyType.GetOr(); // 4-OR
                }
                else if (Regex.Match(firstKeywordsGroup, "^(NEEDS)").Success)
                {
                    dependencyType = DependencyType.GetMandatory() | DependencyType.GetAnd();  //  8-AND | 64-MANDATORY
                }


                /*
                 * the keyword of 'AND' or 'OR' should be removed individually.
                 * it should NOT be removed by using firstToken string in Tokens.tokensList.get(0)
                 * because firstToken string may have something else.
                 * (e.g. string: 'AND NOT ALL Males' name should sound Male', then Token string will be 'UMLM', and 'U' contains 'AND NOT ALL'.
                 * so if we used 'firstToken string' to remove 'AND' in this case as 'string.replace(firstTokenString)'
                 * then it will remove 'AND NOT ALL' even we only need to remove 'AND'
                 *
                 */


                Node data = null;
                nodeSet.GetNodeMap().TryGetValue(childText, out data);
                Tokens tokens = Tokenizer.GetTokens(childText);

                if (data == null)
                {
                    Regex[]       matchPatterns = { VALUE_MATCHER, COMPARISON_MATCHER, ITERATE_MATCHER, EXPRESSION_CONCLUSION_MATCHER, WARNING_MATCHER };
                    Node          tempNode;
                    List <string> possibleChildNodeKeyList;

                    for (int i = 0; i < matchPatterns.Length; i++)
                    {
                        Regex regex = matchPatterns[i];
                        Match match = regex.Match(tokens.tokensString);

                        if (match.Success)
                        {
                            switch (i)
                            {
                            case 4:      // warningMatcher case
                                HandleWarning(childText);
                                break;

                            case 0:      // valueConclusionMatcher case
                                data = new ValueConclusionLine(childText, tokens);

                                tempNode = data;
                                possibleChildNodeKeyList = nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "^(" + tempNode.GetVariableName() + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success).ToList();

                                if (possibleChildNodeKeyList.Count != 0)
                                {
                                    possibleChildNodeKeyList.ForEach(item => {
                                        this.dependencyList.Add(new Dependency(tempNode, nodeSet.GetNodeMap()[item], DependencyType.GetOr()));     //Dependency Type :OR
                                    });
                                }

                                if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING"))
                                {
                                    HandleWarning(parentText);
                                }
                                break;

                            case 1:      // comparisonMatcher case
                                data = new ComparisonLine(childText, tokens);

                                FactValueType rhsType   = ((ComparisonLine)data).GetRHS().GetFactValueType();
                                string        rhsString = FactValue.GetValueInString(((ComparisonLine)data).GetRHS().GetFactValueType(), ((ComparisonLine)data).GetRHS());
                                string        lhsString = ((ComparisonLine)data).GetLHS();
                                tempNode = data;
                                possibleChildNodeKeyList = rhsType.Equals(FactValueType.STRING) ?
                                                           nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "^(" + lhsString + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success || Regex.Match(key, "^(" + rhsString + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success).ToList()
                                                                :
                                                           nodeSet.GetNodeMap().Keys.Where(key => Regex.Match(key, "^(" + lhsString + ")(\\s+(IS(?!(\\s+IN\\s+LIST))).*)*$").Success).ToList();

                                if (possibleChildNodeKeyList.Count != 0)
                                {
                                    possibleChildNodeKeyList.ForEach(item => {
                                        this.dependencyList.Add(new Dependency(tempNode, nodeSet.GetNodeMap()[item], DependencyType.GetOr()));     //Dependency Type :OR
                                    });
                                }

                                if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING"))
                                {
                                    HandleWarning(parentText);
                                }
                                break;

                            case 2:      // iteratenMatcher case
                                data = new IterateLine(childText, tokens);
                                if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING"))
                                {
                                    HandleWarning(parentText);
                                }
                                break;

                            case 3: //exprConclusionMatcher case
                                data = new ExprConclusionLine(childText, tokens);

                                /*
                                 * In this case, there is no mechanism to find possible parent nodes.
                                 * I have brought 'local variable' concept for this case due to it may massed up with structuring node dependency tree with topological sort
                                 * If ExprConclusion node is used as a child, then it means that this node is a local node which has to be strictly bound to its parent node only.
                                 */

                                if (FactValue.GetValueInString(data.GetFactValue().GetFactValueType(), data.GetFactValue()).Equals("WARNING"))
                                {
                                    HandleWarning(parentText);
                                }
                                break;
                            }
                            data.SetNodeLine(lineNumber);
                            this.nodeSet.GetNodeMap().Add(data.GetNodeName(), data);
                            this.nodeSet.GetNodeIdMap().Add(data.GetNodeId(), data.GetNodeName());
                            break;
                        }
                    }
                }

                this.dependencyList.Add(new Dependency(this.nodeSet.GetNode(parentText), data, dependencyType));
            }
        }
Exemple #3
0
        /*
         * The idea of this method is to visit a rule that could get a result of parent rule of the rule as quick as it can be
         * for instance, if a 'OR' child rule is 'TRUE' then the parent rule is 'TRUE',
         * and if a 'AND' child rule is 'FALSE' then the parent rule is 'FALSE'.
         * AS result, visit more likely true 'OR' rule or more likely false 'AND' rule to determine a parent rule as fast as we can
         */
        public static List <Node> Visit(Node node, List <Node> sortedList, Dictionary <string, Record> recordMapOfNodes, Dictionary <string, Node> nodeMap, Dictionary <int?, string> nodeIdMap, List <Node> visitedNodeList, int[,] dependencyMatrix)
        {
            if (node != null)
            {
                sortedList.Add(node);
                int        nodeId                 = node.GetNodeId();
                int        orDependencyType       = DependencyType.GetOr();
                int        andDependencyType      = DependencyType.GetAnd();
                List <int> dependencyMatrixAsList = new List <int>();
                Enumerable.Range(0, dependencyMatrix.GetLength(1)).ToList().ForEach((index) => dependencyMatrixAsList.Add(dependencyMatrix[nodeId, index]));
                List <int> orOutDependency = (System.Collections.Generic.List <int>)Enumerable.Range(0, dependencyMatrixAsList.Count)
                                             .Where(index => (dependencyMatrixAsList[index] & orDependencyType) == orDependencyType);

                List <int> andOutDependency = (System.Collections.Generic.List <int>)Enumerable.Range(0, dependencyMatrixAsList.Count)
                                              .Where(index => (dependencyMatrixAsList[index] & andDependencyType) == andDependencyType);


                if (orOutDependency.Count != 0 || andOutDependency.Count != 0)
                {
                    List <Node> childRuleList = new List <Node>();
                    Enumerable.Range(0, dependencyMatrixAsList.Count).ToList()
                    .Where(childIndex => dependencyMatrixAsList[childIndex] != 0)
                    .ToList()
                    .ForEach(item => childRuleList.Add(nodeMap[nodeIdMap[item]]));


                    if (orOutDependency.Count != 0 && andOutDependency.Count == 0)
                    {
                        while (childRuleList.Count != 0)
                        {
                            /*
                             * the reason for selecting an option having more number of 'yes' is as follows
                             * if it is 'OR' rule and it is 'TRUE' then it is the shortest path, and ignore other 'OR' rules
                             * Therefore, looking for more likely 'TRUE' rule would be the shortest one rather than
                             * looking for more likely 'FALSE' rule in terms of processing time
                             */
                            Node theMostPositive = FindTheMostPositive(childRuleList, recordMapOfNodes, dependencyMatrixAsList);
                            //                              Node theMostPositive = findTheMostPositive(childRuleList, recordMapOfNodes);
                            if (!visitedNodeList.Contains(theMostPositive))
                            {
                                visitedNodeList.Add(theMostPositive);
                                sortedList = Visit(theMostPositive, sortedList, recordMapOfNodes, nodeMap, nodeIdMap, visitedNodeList, dependencyMatrix);
                            }
                        }
                    }
                    else
                    {
                        if (orOutDependency.Count == 0 && andOutDependency.Count != 0)
                        {
                            /*
                             * the reason for selecting an option having more number of 'yes' is as follows
                             * if it is 'AND' rule and it is 'FALSE' then it is the shortest path, and ignore other 'AND' rules
                             * Therefore, looking for more likely 'FALSE' rule would be the shortest one rather than
                             * looking for more likely 'TRUE' rule in terms of processing time
                             */
                            while (childRuleList.Count != 0)
                            {
                                Node theMostNegative = FindTheMostNegative(childRuleList, recordMapOfNodes, dependencyMatrixAsList);
                                //                                  Node theMostNegative = findTheMostNegative(childRuleList, recordMapOfNodes);
                                if (!visitedNodeList.Contains(theMostNegative))
                                {
                                    visitedNodeList.Add(theMostNegative);
                                    sortedList = Visit(theMostNegative, sortedList, recordMapOfNodes, nodeMap, nodeIdMap, visitedNodeList, dependencyMatrix);
                                }
                            }
                        }
                    }
                }
            }


            return(sortedList);
        }