// Map each token to its corresponding node.
        public static void MapNodes(BTLGUILine line, CodeMap codemap)
        {
            line.btnodes.Clear();
            for (int t = 0; t < line.tokens.Count; ++t)
            {
                line.btnodes.Add(null);
            }

            for (int t = 0; t < line.tokens.Count; ++t)
            {
                var token = line.tokens[t];

                if (token.type == BTLTokenizer.TokenType.Comment)
                {
                    continue;
                }

                for (int n = 0; n < codemap.nodes.Length; ++n)
                {
                    var node    = codemap.nodes[n];
                    var nodeLoc = codemap.substringLocations[n];

                    if (
                        nodeLoc.start <= token.substring_start &&
                        (token.substring_start + token.substring_length) <= (nodeLoc.start + nodeLoc.length)
                        )
                    {
                        line.btnodes[t] = node;
                        break;
                    }
                }
            }
        }
        public static void MapNodes(BTLGUILine[] lines, CodeMap codemap)
        {
            var stack = new Stack <BTLGUILine>();

            for (int i = lines.Length - 1; i >= 0; i--)
            {
                stack.Push(lines[i]);
            }

            while (stack.Count > 0)
            {
                var line = stack.Pop();
                MapNodes(line, codemap);
                for (int i = line.children.Count - 1; i >= 0; i--)
                {
                    stack.Push(line.children[i]);
                }
            }
        }
        public static SourceDisplay[] MapGUILines(BTSource[] btlSources, BTProgram program, PandaScriptException[] pandaExceptions)
        {
            if (btlSources == null || program == null)
            {
                return(null);
            }

            var sourceDisplays = new SourceDisplay[btlSources.Length];

            for (int i = 0; i < btlSources.Length; i++)
            {
                if (btlSources[i] == null)
                {
                    continue;
                }

                SourceDisplay sourceDisplay = null;
                var           tokens        = BTLAssetManager.GetBTLTokens(btlSources, btlSources[i]);
                sourceDisplay = BTLGUILine.Analyse(tokens, i);

                sourceDisplays[i] = sourceDisplay;

                CodeMap codemap = null;
                if (program.codemaps != null && i < program.codemaps.Length)
                {
                    codemap = program.codemaps[i];
                }

                if (codemap != null)
                {
                    BTLGUILine.MapNodes(sourceDisplay.lines, codemap);

                    var lines = sourceDisplay.flattenLines;
                    foreach (var line in lines)
                    {
                        foreach (var n in line.btnodes)
                        {
                            var task = n as BTTask;
                            if (task != null && task.boundState != BoundState.Bound)
                            {
                                line.hasErrors = true;
                            }
                        }
                    }
                }

                if (sourceDisplay != null)
                {
                    var lines = sourceDisplay.flattenLines;
                    foreach (var line in lines)
                    {
                        foreach (var pandaException in pandaExceptions)
                        {
                            if (pandaException != null)
                            {
                                if (pandaException.filePath == btlSources[i].url && line.lineNumber == pandaException.lineNumber)
                                {
                                    line.hasErrors = true;
                                }
                            }
                        }
                    }
                }
            }

            return(sourceDisplays);
        }
        static BTTree[] Build(BTLParser.Node[] trees, out CodeMap codemap, bool createCodeMap)
        {
            var           codeMapDict = new Dictionary <BTNode, SubstringLocation>();
            List <BTTree> roots       = new List <BTTree>();

            BTTree root = null;
            // Get all nodes
            var parseNodes = BTLParser.GetNodes(trees);

            var nodeID = new Dictionary <BTLParser.Node, int>();

            for (int i = 0; i < parseNodes.Length; ++i)
            {
                nodeID[parseNodes[i]] = i;
            }


            // create nodes
            var nodes = new BTNode[parseNodes.Length];

            foreach (var n in parseNodes)
            {
                int id = nodeID[n];

                switch (n.token.type)
                {
                case TokenType.Tree:
                    var newRoot = new BTTree();

                    if (n.parameters.Count > 0)
                    {
                        newRoot.name = n.parsedParameters[0] as string;
                    }

                    nodes[id] = newRoot;
                    root      = newRoot;
                    roots.Add(root);

                    break;

                case TokenType.TreeProxy:
                    var rootProxy = new BTTreeProxy();

                    if (n.parameters.Count > 0)
                    {
                        rootProxy.name = n.parsedParameters[0] as string;
                    }

                    nodes[id] = rootProxy;

                    break;


                case TokenType.Value:
                case TokenType.Word:

                    var task = new BTTask();
                    task.taskName = n.token.content.Trim();

                    nodes[id] = task;

                    break;

                case TokenType.Mute:
                    nodes[id] = new BTMute();
                    break;

                case TokenType.Not:
                    nodes[id] = new BTNot();
                    break;

                case TokenType.Repeat:
                    nodes[id] = new BTRepeat();
                    break;

                case TokenType.Fallback:        nodes[id] = new BTFallback(); break;

                case TokenType.Sequence:        nodes[id] = new BTSequence(); break;

                case TokenType.Parallel:        nodes[id] = new BTParallel(); break;

                case TokenType.While:   nodes[id] = new BTWhile(); break;

                case TokenType.Race: nodes[id] = new BTRace(); break;

                case TokenType.Random: nodes[id] = new BTRandom(); break;
                }



                if (nodes[id] != null)
                {
                    nodes[id].i_parameters = n.parsedParameters;
                }

                if (nodes[id] != null)
                {
                    var loc = new SubstringLocation();
                    loc.line   = n.token.line;
                    loc.start  = n.token.substring_start;
                    loc.length = n.token.substring_length;

                    if (n.parameters.Count > 0)
                    {
                        loc.length = n.parseLength;
                    }

                    codeMapDict[nodes[id]] = loc;
                }
            }


            // parenting
            foreach (var n in parseNodes)
            {
                int pid    = nodeID[n];
                var parent = nodes[pid];
                if (parent != null)
                {
                    foreach (var c in n.children)
                    {
                        int cid   = nodeID[c];
                        var child = nodes[cid];
                        if (child != null)
                        {
                            parent.AddChild(child);
                        }
                    }
                }
            }

            if (roots.Count > 0)
            {
                root = roots[0];
            }

            if (createCodeMap)
            {
                codemap = new CodeMap(codeMapDict);
            }
            else
            {
                codemap = null;
            }


            return(roots.ToArray());
        }