private void GoalPathNodesI(ArrayList goalpath, DBNode node, Stack path)
        {
            if (node == null)
            {
                return;
            }

            if (module.IsGoal(node.State) && goalpath.Contains(node) == false)
            {
                /*
                 * Console.WriteLine ("goals:");
                 * foreach (IDBSpaceState state in goals)
                 *      Console.WriteLine ("    {0}", state);
                 *
                 * Console.WriteLine ("    add: {0}", node.State);
                 */
                goalpath.Add(node);

                foreach (DBNode pNode in path)
                {
                    if (goalpath.Contains(pNode) == false)
                    {
                        goalpath.Add(pNode);
                    }
                }
            }

            foreach (DBNode child in node.Children)
            {
                path.Push(node);
                GoalPathNodesI(goalpath, child, path);
                path.Pop();
            }
        }
        // TODO
        private void AddCombinationStage(DBNode node, Stack path)
        {
            //Console.WriteLine ("AddCombinationStage");
            if (node == null || node.Level > level)
            {
                return;
            }

            if (node.Type == DBNode.NodeType.Dependency &&
                node.Level == level &&
                node.IsGoal == false)
            {
                /*for (int l = 0 ; l < node.Level ; ++l)
                 *      Console.Write ("    ");
                 * Console.WriteLine ("({0}) down", node.DebugNN);*/
                module.DoExpirationCheck();
                FindAllCombinationNodes(node, path, root, new Stack());
            }

            path.Push(node);
            foreach (DBNode child in node.Children)
            {
                AddCombinationStage(child, path);
            }

            path.Pop();
        }
        private void DumpTree(DBNode node)
        {
            if (node == null)
            {
                return;
            }

            if (node.dumped)
            {
                return;
            }
            node.dumped = true;

            for (int n = 0; n < node.Level; ++n)
            {
                Console.Write("    ");
            }

            Console.WriteLine(node);

            foreach (DBNode child in node.Children)
            {
                DumpTree(child);
            }
        }
        // TODO:
        // if tracing back this nodes anypath to the root node, will we cross
        // 'node' ?
        public bool BacktraceLeadsOverNode(DBNode node)
        {
            // TODO: this is inefficient, as we check almost the whole graph
            // By reversing it (and storing backpointers in each node, we
            // could make this faster).
            if (this == node)
            {
                return(true);
            }

            if (node.Level >= Level)
            {
                return(false);
            }

            foreach (DBNode child in node.Children)
            {
                if (BacktraceLeadsOverNode(child))
                {
                    return(true);
                }
            }

            return(false);
        }
        public void AddCombinationNode(DBNode node, DBNode newNode)
        {
            TreeSizeIncreased = true;
            nodeCount        += 1;

            // Graph bookkeeping
            node.Children.Add(newNode);
        }
        private int DEBUGParentNN(DBNode node, DBNode search)
        {
            if (node.Children.IndexOf(search) >= 0)
            {
                return(node.DebugNN);
            }

            foreach (DBNode child in node.Children)
            {
                int cnn = DEBUGParentNN(child, search);
                if (cnn != -1)
                {
                    return(cnn);
                }
            }

            return(-1);
        }
        private bool HaveCommonCombinedChild(DBNode node1, DBNode node2)
        {
            foreach (DBNode child1 in node1.Children)
            {
                if (node2.CombinedChildren.IndexOf(child1) >= 0)
                {
                    return(true);
                }
            }

            foreach (DBNode child2 in node2.Children)
            {
                if (node1.CombinedChildren.IndexOf(child2) >= 0)
                {
                    return(true);
                }
            }

            return(false);
        }
        private void AddDependentChildren(DBNode node, int subLevel)
        {
            // Console.WriteLine ("    AddDependentChildren");
            // TODO
            IDBOperator[] opers = module.LegalOperators(node);
            if (opers == null)
            {
                return;
            }
            //Console.WriteLine ("      opers.Count = {0}", opers.Length);

            foreach (IDBOperator op in opers)
            {
                if (module.Applicable(op, node))
                {
                    DBNode newChild = LinkNewChildToGraph(node, op);
                    newChild.subLevel = subLevel;

                    if (newChild.IsGoal == false)
                    {
                        if (breadthFirst)
                        {
                            dependencyNodeQueue.Enqueue
                                (new DepQElem(newChild, subLevel + 1));
                        }
                        else
                        {
                            AddDependentChildren(newChild, subLevel + 1);
                        }
                    }
                    else if (module.OneGoalStopsSearch ||
                             (module.GoalCountThresh != 0 &&
                              goalCount >= module.GoalCountThresh))
                    {
                        throw (new GoalCountExceededException());
                    }
                }
            }
        }
        private void AddDependencyStage(DBNode node)
        {
            //Console.WriteLine ("AddDependencyStage");
            if (node == null)
            {
                return;
            }

            if (level == (node.Level + 1) &&
                (node.Type == DBNode.NodeType.Root ||
                 node.Type == DBNode.NodeType.Combination))
            {
                // Do not expand goal nodes any further or nodes that have
                // already been expanded.
                if (node.IsGoal == false && node.DependencyExpanded == false)
                {
                    if (breadthFirst)
                    {
                        dependencyNodeQueue.Enqueue(new DepQElem(node, 0));

                        node.DependencyExpanded = true;
                    }
                    else
                    {
                        AddDependentChildren(node, 0);
                    }
                }

                // FIXME: check if this is ok, seems to be and makes sense
                return;
            }

            foreach (DBNode child in node.Children)
            {
                AddDependencyStage(child);
            }
        }
        // Returns new child
        private DBNode LinkNewChildToGraph(DBNode node, IDBOperator op)
        {
            IDBSpaceState newState = op.Apply(module, node.State);

            newState.UpdateIsGoal(module);

            DBNode newNode = new DBNode(DBNode.NodeType.Dependency,
                                        newState, level);

            if (newNode.IsGoal)
            {
                goalCount += 1;
            }

            TreeSizeIncreased = true;
            nodeCount        += 1;

            // Graph bookkeeping
            node.Children.Add(newNode);

            module.RegisterNewNode(newNode, root);

            return(newNode);
        }
        private void GoalStatesI(ArrayList goals, DBNode node)
        {
            if (node == null)
            {
                return;
            }

            if (module.IsGoal(node.State) && goals.Contains(node.State) == false)
            {
                /*
                 * Console.WriteLine ("goals:");
                 * foreach (IDBSpaceState state in goals)
                 *      Console.WriteLine ("    {0}", state);
                 *
                 * Console.WriteLine ("    add: {0}", node.State);
                 */
                goals.Add(node.State);
            }

            foreach (DBNode child in node.Children)
            {
                GoalStatesI(goals, child);
            }
        }
        // partnerPath: path up to and excluding partner
        // nodePath: path up to and excluding node
        private void FindAllCombinationNodes(DBNode partner, Stack partnerPath,
                                             DBNode node, Stack nodePath)
        {
            //Console.WriteLine ("FindAllCombinationNodes");
            if (node == null || node == partner)
            {
                return;
            }

            if (node.IsGoal)
            {
                return;
            }

            if (node.Type == DBNode.NodeType.Root ||
                module.NotInConflict(partner, node))
            {
                // HaveCommonChild checks if we already combined in the
                // reverse direction, but we also need to check whether their
                // path's are independant.  That is, whether tracing node's
                // path back to root we will cross over partner.  Also whether
                // tracing partner's path back will lead us over node.
                if (node.Type == DBNode.NodeType.Dependency &&
                    HaveCommonCombinedChild(partner, node) == false)
                {
                    IDBSpaceState combination =
                        module.CombineIfResultIsNewOperators(partner, partnerPath,
                                                             node, nodePath);

                    if (combination != null)
                    {
                        DBNode combNode = new DBNode(DBNode.NodeType.Combination,
                                                     combination, level);
                        combNode.IsGoal = module.IsGoal(combination);
                        if (combNode.IsGoal)
                        {
                            goalCount += 1;
                        }

                        AddCombinationNode(partner, combNode);

                        // Also make the new node a child ("combined child") of
                        // node.  We do not add it it to the Children array
                        // for two reasons:
                        //   1. We want a strict tree structure in memory, no
                        //      DAG
                        //   2. The only point where this DAG-like
                        //      relationship is used is in this method, when
                        //      its checked we did not already combine them.
                        node.CombinedChildren.Add(combNode);

                        // Notify the implementation of a new node.
                        module.RegisterNewNode(combNode, root);

                        if (combNode.IsGoal)
                        {
                            if (module.OneGoalStopsSearch ||
                                (module.GoalCountThresh != 0 &&
                                 goalCount >= module.GoalCountThresh))
                            {
                                throw (new GoalCountExceededException());
                            }
                        }
                    }
                }

                nodePath.Push(node);
                foreach (DBNode child in node.Children)
                {
                    FindAllCombinationNodes(partner, partnerPath, child, nodePath);
                }

                nodePath.Pop();
            }
        }
 internal DepQElem(DBNode node, int subLevel)
 {
     this.node     = node;
     this.subLevel = subLevel;
 }
        public void Search(IDBSpaceState rootState)
        {
            rootState.UpdateIsGoal(module);
            root = new DBNode(DBNode.NodeType.Root, rootState, 0);
            if (root.IsGoal)
            {
                goalCount += 1;
            }

            module.RegisterNewNode(root, root);

            level = 1;

            TreeSizeIncreased = true;
            try {
                while (TreeSizeIncreased)
                {
                    //Console.WriteLine ("level {0}", level);

                    TreeSizeIncreased = false;

                    if (breadthFirst)
                    {
                        dependencyNodeQueue.Clear();
                    }
                    AddDependencyStage(root);

                    if (breadthFirst)
                    {
                        SolveDependencyStage();
                    }
                    //DumpTree (root);

                    /*Console.WriteLine ("level {0} dependency finished: {1} nodes, {2} goals",
                     *      level, nodeCount, goalCount);*/

                    if (TreeSizeIncreased == false)
                    {
                        break;
                    }
                    if (module.GoalCountThresh != 0 && goalCount >= module.GoalCountThresh)
                    {
                        break;
                    }

                    /*
                     * Console.WriteLine ("COMB TEST");
                     * module.CombinationStage (level, root, this);
                     *
                     * if (module.GoalCountThresh != 0 && goalCount >= module.GoalCountThresh)
                     *      break;
                     */

                    AddCombinationStage(root, new Stack());

                    /*Console.WriteLine ("level {0} combination finished: {1} nodes, {2} goals",
                     *      level, nodeCount, goalCount);*/
                    if (TreeSizeIncreased == false)
                    {
                        break;
                    }
                    if (module.GoalCountThresh != 0 && goalCount >= module.GoalCountThresh)
                    {
                        break;
                    }
                    //DumpTree (root);

                    level += 1;
                }
            } catch (GoalCountExceededException) {
                /*
                 * Console.WriteLine ("GOAL count limit of {0} exceeded.",
                 *      module.GoalCountThresh);*/
            }
        }
        private void DumpDOT(TextWriter dotFile, DBNode node,
                             ArrayList nodesFilter)
        {
            if (node == null)
            {
                return;
            }

            if (nodesFilter != null && nodesFilter.Contains(node) == false)
            {
                return;
            }

            if (node.dumped)
            {
                return;
            }
            node.dumped = true;

            for (int n = 0; n < node.Level; ++n)
            {
                dotFile.Write("    ");
            }

            // Order nodes on level
            string rankLevel;

            if (node.Level == 0)
            {
                rankLevel = "root";
            }
            else if (node.Type == DBNode.NodeType.Dependency)
            {
                rankLevel = String.Format("dep{0}", node.Level);
            }
            else if (node.Type == DBNode.NodeType.Combination)
            {
                rankLevel = String.Format("comb{0}", node.Level);
            }
            else
            {
                rankLevel = "invalid";
            }
            if (node.subLevel == 0)
            {
                dotFile.WriteLine("{{ rank=same; {0};", rankLevel);
            }

            dotFile.WriteLine("{0} [shape=box label = <{1}>];",
                              node.DebugNN, node.State.DescShort);
            if (node.subLevel == 0)
            {
                dotFile.WriteLine("}");
            }
            foreach (DBNode child in node.Children)
            {
                if (nodesFilter != null && nodesFilter.Contains(child) == false)
                {
                    continue;
                }

                for (int n = 0; n < node.Level; ++n)
                {
                    dotFile.Write("    ");
                }

                dotFile.WriteLine("{0} -> {1};", node.DebugNN, child.DebugNN);
            }

            // Also combined children
            if (node.CombinedChildren != null)
            {
                foreach (DBNode child in node.CombinedChildren)
                {
                    if (nodesFilter != null && nodesFilter.Contains(child) == false)
                    {
                        continue;
                    }
                    for (int n = 0; n < node.Level; ++n)
                    {
                        dotFile.Write("    ");
                    }

                    dotFile.WriteLine("{0} -> {1} [color=\"#b0b0b0\"] ;", node.DebugNN, child.DebugNN);
                }
            }

            foreach (DBNode child in node.Children)
            {
                DumpDOT(dotFile, child, nodesFilter);
            }
        }