void _buildTree(string[] keywords)
        {
            //build keyword tree and transition function
            _root = new InnerNode(null, ' ');
            var keywordCount = keywords.Length;

            for (int i = 0; i < keywordCount; ++i)
            {
                var p = keywords[i];

                // add pattern to tree
                InnerNode nd = _root;
                foreach (var c in p)
                {
                    InnerNode ndNew = null;
                    foreach (InnerNode trans in nd._transitionsArr)
                    {
                        if (trans._char == c)
                        {
                            ndNew = trans; break;
                        }
                    }

                    if (ndNew == null)
                    {
                        ndNew = new InnerNode(nd, c);
                        nd.AddTransition(ndNew);
                    }
                    nd = ndNew;
                }
                nd.AddResult(p, i);
            }

            // Find failure functions
            var nodes = new List <InnerNode>();

            // level 1 nodes - fail to root node
            foreach (InnerNode nd in _root._transitionsArr)
            {
                nd._failure = _root;
                foreach (InnerNode trans in nd._transitionsArr)
                {
                    nodes.Add(trans);
                }
            }
            // other nodes - using BFS
            while (nodes.Count != 0)
            {
                var newNodes = new List <InnerNode>();
                foreach (InnerNode nd in nodes)
                {
                    InnerNode r = nd._parent._failure;
                    char      c = nd._char;

                    while (r != null && !r.ContainsTransition(c))
                    {
                        r = r._failure;
                    }
                    if (r == null)
                    {
                        nd._failure = _root;
                    }
                    else
                    {
                        nd._failure = r.GetTransition(c);
                        foreach (var result in nd._failure._results)
                        {
                            nd.AddResult(result.Key, result.Value);
                        }
                    }

                    // add child nodes to BFS list
                    foreach (InnerNode child in nd._transitionsArr)
                    {
                        newNodes.Add(child);
                    }
                }
                nodes = newNodes;
            }
            _root._failure = _root;
        }