protected virtual NodeStep EvaluateNode(Node node)
        {
            NodeStep step;

            Log.Trace("Entering node {0}", node.GetType().Name);

            try
            {
                step = node.Evaluate();
            }
            catch
            {
                step = new NodeStep(NodeResult.Fail, null);
            }

            if (evaluating)
            {
                Log.Trace("Exiting node {0} with result {1}{2}", node.GetType().Name, step.Result, step.Slot == null ? "" : (" by slot " + step.Slot.Name));
            }

            return(step);
        }
        protected virtual void EvaluateNodes()
        {
            Node[] stepNodes;

            lock (Nodes)
            {
                if (Nodes.Count == 0)
                {
                    return;
                }

                stepNodes = Nodes.ToArray();
                Nodes.Clear();
            }

            Thread[] threads = new Thread[stepNodes.Length];

            for (int i = 0; i < stepNodes.Length; i++)
            {
                Node node = stepNodes[i];

                // Create the thread
                threads[i] = new Thread(() =>
                {
                    NodeStep step = EvaluateNode(node);

                    if (!evaluating)
                    {
                        Return(NodeResult.Stop);
                        return;
                    }

                    switch (step.Result)
                    {
                    case NodeResult.Fail: Return(NodeResult.Fail); return;

                    case NodeResult.Stop: Return(NodeResult.Stop); return;
                    }

                    if (step.Result == NodeResult.Success)
                    {
                        lock (Nodes)
                            foreach (Node slotNode in step.Slot.Nodes)
                            {
                                Nodes.Add(slotNode);
                            }
                    }

                    lock (this.threads)
                    {
                        this.threads.Remove(Thread.CurrentThread);

                        if (this.threads.Count == 0 && Nodes.Count == 0)
                        {
                            Return();
                            return;
                        }
                    }

                    if (evaluating && !evaluated)
                    {
                        EvaluateNodes();
                    }
                });
            }

            if (!evaluating)
            {
                Return(NodeResult.Stop);
                return;
            }

            // Register threads
            lock (this.threads)
                this.threads.AddRange(threads);

            // Start threads
            foreach (Thread thread in threads)
            {
                thread.Start();
            }
        }