private void AddProfile(ISyntaxTreeNodeCollection nodes, BlockCollection blocks, Paragraph currentParagraph, Span currentSpan)
        {
            foreach (var node in nodes)
            {
                var tagNode = node as TagNode;
                if (tagNode != null)
                {
                    var parameter = tagNode.AttributeValues.Values.FirstOrDefault();
                    switch (tagNode.Tag.Name)
                    {
                    case "left":
                    case "center":
                    case "right":
                    case "justify":
                        var aligned = new Section {
                            TextAlignment = tagNode.Tag.Name.ToEnum <TextAlignment>()
                        };
                        blocks.Add(aligned);
                        AddProfile(tagNode.SubNodes, aligned.Blocks, null, null);
                        currentParagraph = null;
                        continue;

                    case "collapse":
                        var document = new FlowDocument {
                            FontFamily = Document.FontFamily, FontSize = Document.FontSize, Foreground = Document.Foreground
                        };
                        var viewer = new FlowDocumentScrollViewer {
                            Document = document, VerticalScrollBarVisibility = ScrollBarVisibility.Disabled
                        };
                        viewer.PreviewMouseWheel += (sender, args) => {
                            args.Handled = true;
                            DocumentViewer.RaiseEvent(new MouseWheelEventArgs(args.MouseDevice, args.Timestamp, args.Delta)
                            {
                                RoutedEvent = MouseWheelEvent, Source = sender
                            });
                        };
                        blocks.Add(new BlockUIContainer(new Expander {
                            Content = viewer, Header = parameter
                        }));
                        AddProfile(node.SubNodes, document.Blocks, null, null);
                        currentParagraph = null;
                        continue;

                    case "indent":
                        var indented = new Section {
                            Margin = new Thickness(10, 0, 0, 0)
                        };
                        blocks.Add(indented);
                        AddProfile(tagNode.SubNodes, indented.Blocks, null, null);
                        currentParagraph = null;
                        continue;

                    case "hr":
                        blocks.Add(new BlockUIContainer(new Separator()));
                        currentParagraph = null;
                        continue;

                    case "heading":
                        blocks.Add(new Paragraph {
                            FontSize = 18, FontWeight = FontWeights.Bold, Inlines = { BBCode.ToInlines(node.SubNodes) }
                        });
                        currentParagraph = null;
                        continue;

                    case "img":
                        var image = new BitmapImage(new Uri(Profile.InlineImages[int.Parse(parameter)].Url));
                        blocks.Add(new BlockUIContainer(new Image {
                            Source = image, Stretch = Stretch.None
                        }));
                        currentParagraph = null;
                        continue;
                    }
                }
                if (currentParagraph == null)
                {
                    currentParagraph = new Paragraph();
                    currentSpan      = new Span();
                    blocks.Add(currentParagraph);
                    currentParagraph.Inlines.Add(currentSpan);
                }
                if (tagNode != null)
                {
                    var inline = BBCode.ToInline(tagNode);
                    currentSpan.Inlines.Add(inline);
                    var span = inline as Span;
                    if (span != null)
                    {
                        AddProfile(tagNode.SubNodes, blocks, currentParagraph, span);
                    }
                }
                else
                {
                    currentSpan.Inlines.Add(new Run(node.ToText()));
                }
            }
        }
        private void AddTag(string tag, string attribute = null)
        {
            if (IsSimple)
            {
                TextBox.SelectedText = (string.IsNullOrEmpty(attribute) ? $"[{tag}]" : $"[{tag}={attribute}]") + $"{TextBox.SelectedText}[/{tag}]";
            }
            else
            {
                var  selection = RichTextBox.Selection;
                bool isNormal;
                switch (tag)
                {
                case "b":
                    isNormal = selection.GetPropertyValue(TextElement.FontWeightProperty) as FontWeight? == FontWeights.Normal;
                    selection.ApplyPropertyValue(TextElement.FontWeightProperty, isNormal ? FontWeights.Bold : FontWeights.Normal);
                    break;

                case "i":
                    isNormal = selection.GetPropertyValue(TextElement.FontStyleProperty) as FontStyle? == FontStyles.Normal;
                    selection.ApplyPropertyValue(TextElement.FontStyleProperty, isNormal ? FontStyles.Italic : FontStyles.Normal);
                    break;

                case "u":
                    ToggleTextDecoration(TextDecorationLocation.Underline);
                    break;

                case "s":
                    ToggleTextDecoration(TextDecorationLocation.Strikethrough);
                    break;

                case "big":
                    isNormal = selection.GetPropertyValue(TextElement.FontSizeProperty) as double? == theme.FontSize;
                    selection.ApplyPropertyValue(TextElement.FontSizeProperty, isNormal ? theme.FontSizeBig : theme.FontSize);
                    break;

                case "small":
                    isNormal = selection.GetPropertyValue(TextElement.FontSizeProperty) as double? == theme.FontSize;
                    selection.ApplyPropertyValue(TextElement.FontSizeProperty, isNormal ? theme.FontSizeSmall : theme.FontSize);
                    break;

                case "sup":
                    isNormal = selection.GetPropertyValue(Inline.BaselineAlignmentProperty) as BaselineAlignment? == BaselineAlignment.Baseline;
                    selection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, isNormal ? BaselineAlignment.TextTop : BaselineAlignment.Baseline);
                    selection.ApplyPropertyValue(TextElement.FontSizeProperty, isNormal ? theme.FontSizeSmall : theme.FontSize);
                    break;

                case "sub":
                    isNormal = selection.GetPropertyValue(Inline.BaselineAlignmentProperty) as BaselineAlignment? == BaselineAlignment.Baseline;
                    selection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, isNormal ? BaselineAlignment.Subscript : BaselineAlignment.Baseline);
                    selection.ApplyPropertyValue(TextElement.FontSizeProperty, isNormal ? theme.FontSizeSmall : theme.FontSize);
                    break;

                case "url":
                    GetSelectedParagraph().Inlines.Add(new Hyperlink(selection.Start, selection.End)
                    {
                        NavigateUri = new Uri(attribute), IsEnabled = true
                    });
                    break;

                case "user":
                case "icon":
                case "eicon":
                    var content = selection.Text.Trim();
                    var inline  = BBCode.ToInline(new TagNode(new BBTag(tag), new TextNode(content).SingletonEnumerable()));
                    inline.Tag = $"[{tag}]{content}[/{tag}]";
                    ReplaceSelection(inline);
                    break;
                }
            }
        }