private IEnumerable <CreoleRichTextElementNodeData> _GetRootNodesFrom(TokenRange <CreoleTokenCode> tokens, IEnumerable <CreoleRichTextElementData> elementsData)
        {
            var rootNodes           = new List <CreoleRichTextElementNodeData>();
            var visitedElementTypes = new List <CreoleRichTextElementType>(10);

            foreach (var elementData in elementsData)
            {
                var node = new CreoleRichTextElementNodeData(elementData);

                IList <CreoleRichTextElementNodeData> siblingNodes = rootNodes;
                while (siblingNodes.Count > 0 && _Contains(siblingNodes[siblingNodes.Count - 1], node))
                {
                    var parentNode = siblingNodes[siblingNodes.Count - 1];
                    siblingNodes = parentNode.ChildNodes;
                    visitedElementTypes.Add(parentNode.ElementType);
                }

                if (node.ElementType == CreoleRichTextElementType.Hyperlink)
                {
                    var contentRange = tokens.SubRange(node.ContentStartIndex, (node.ContentEndIndex - node.ContentStartIndex));
                    foreach (var hyperlinkContentElementNodeData in _GetHyperlinkContentElementNodesData(contentRange, visitedElementTypes))
                    {
                        node.ChildNodes.Add(_AddIndexOffset(node.ContentStartIndex, hyperlinkContentElementNodeData));
                    }
                }

                siblingNodes.Add(node);
                visitedElementTypes.Clear();
            }

            return(rootNodes);
        }
        private string _GetContentFrom(TokenRange <CreoleTokenCode> tokens, CreoleRichTextElementNodeData richTextElementData)
        {
            var contentStartIndex = richTextElementData.ContentStartIndex;
            var contentEndIdnex   = richTextElementData.ContentEndIndex;
            var contentRange      = tokens.SubRange(contentStartIndex, (contentEndIdnex - contentStartIndex));

            return(TokenRangeHelper.GetPlainText(contentRange));
        }
        private string _GetUrlFrom(TokenRange <CreoleTokenCode> tokens, CreoleRichTextElementNodeData richTextElementData)
        {
            var urlStartIndex = richTextElementData.UrlStartIndex;
            var urlEndIdnex   = richTextElementData.UrlEndIndex;
            var urlRange      = tokens.SubRange(urlStartIndex, (urlEndIdnex - urlStartIndex));

            return(TokenRangeHelper.GetPlainText(urlRange));
        }
 private CreoleRichTextElementNodeData _AddIndexOffset(int offset, CreoleRichTextElementNodeData nodeData)
 => new CreoleRichTextElementNodeData(
     new CreoleRichTextElementData(
         elementType: nodeData.ElementType,
         startIndex: (offset + nodeData.StartIndex),
         endIndex: (offset + nodeData.EndIndex),
         urlStartIndex: (offset + nodeData.UrlStartIndex),
         urlEndIndex: (offset + nodeData.UrlEndIndex),
         contentStartIndex: (offset + nodeData.ContentStartIndex),
         contentEndIndex: (offset + nodeData.ContentEndIndex)
         ),
     nodeData.ChildNodes
     );
 private static bool _Contains(CreoleRichTextElementNodeData parent, CreoleRichTextElementNodeData child)
 => (parent.ContentStartIndex <= child.StartIndex && child.EndIndex <= parent.ContentEndIndex);
        private Element _GetCreoleElementFrom(TokenRange <CreoleTokenCode> tokens, CreoleRichTextElementNodeData nodeData)
        {
            Element result = null;

            switch (nodeData.ElementType)
            {
            case CreoleRichTextElementType.Code:
                result = new CodeElement(
                    _GetContentFrom(tokens, nodeData)
                    );
                break;

            case CreoleRichTextElementType.Hyperlink:
                result = new HyperlinkElement(
                    _GetUrlFrom(tokens, nodeData),
                    _GetCreoleElements(tokens, nodeData.ContentStartIndex, nodeData.ContentEndIndex, nodeData.ChildNodes)
                    );
                break;

            case CreoleRichTextElementType.Image:
                if (nodeData.UrlEndIndex < nodeData.ContentStartIndex)
                {
                    result = new ImageElement(
                        _GetUrlFrom(tokens, nodeData),
                        _GetContentFrom(tokens, nodeData)
                        );
                }
                else
                {
                    result = new ImageElement(
                        _GetUrlFrom(tokens, nodeData)
                        );
                }
                break;

            case CreoleRichTextElementType.Plugin:
                result = new PluginElement(
                    _GetContentFrom(tokens, nodeData)
                    );
                break;

            case CreoleRichTextElementType.LineBreak:
                result = _creoleLineBreakElement;
                break;

            case CreoleRichTextElementType.InlineHyperlink:
                var url = _GetUrlFrom(tokens, nodeData);
                result = new HyperlinkElement(url, new[] { new TextElement(url) });
                break;

            case CreoleRichTextElementType.EscapedInlineHyperlink:
                result = new TextElement(
                    _GetUrlFrom(tokens, nodeData)
                    );
                break;

            case CreoleRichTextElementType.Emphasis:
                result = new EmphasisElement(
                    _GetCreoleElements(tokens, nodeData.ContentStartIndex, nodeData.ContentEndIndex, nodeData.ChildNodes)
                    );
                break;

            case CreoleRichTextElementType.Strong:
                result = new StrongElement(
                    _GetCreoleElements(tokens, nodeData.ContentStartIndex, nodeData.ContentEndIndex, nodeData.ChildNodes)
                    );
                break;
            }

            return(result);
        }