// ---------------------------------------------------------------------
    //
    // Private Methods
    //
    // ---------------------------------------------------------------------

    #region Private Methods
    /// <summary>
    /// Processes a root level element of XAML (normally it's FlowDocument element).
    /// </summary>
    /// <param name="xamlReader">
    /// XmlTextReader for a source xaml.
    /// </param>
    /// <param name="htmlWriter">
    /// XmlTextWriter producing resulting html
    /// </param>
    private static bool WriteFlowDocument(XmlTextReader xamlReader, ISgmlWriter htmlWriter)
    {
      if (!ReadNextToken(xamlReader))
      {
        // Xaml content is empty - nothing to convert
        return false;
      }

      if (xamlReader.NodeType != XmlNodeType.Element || xamlReader.Name != "FlowDocument")
      {
        // Root FlowDocument elemet is missing
        return false;
      }

      // Create a buffer StringBuilder for collecting css properties for inline STYLE attributes
      // on every element level (it will be re-initialized on every level).
      StringBuilder inlineStyle = new StringBuilder();

      //htmlWriter.WriteStartElement("HTML");
      //htmlWriter.WriteStartElement("BODY");

      WriteFormattingProperties(xamlReader, htmlWriter, inlineStyle);

      WriteElementContent(xamlReader, htmlWriter, inlineStyle);

      //htmlWriter.WriteEndElement();
      //htmlWriter.WriteEndElement();

      return true;
    }
    /// <summary>
    /// Converts a xaml element into an appropriate html element.
    /// </summary>
    /// <param name="xamlReader">
    /// On entry this XmlTextReader must be on Element start tag;
    /// on exit - on EndElement tag.
    /// </param>
    /// <param name="htmlWriter">
    /// May be null, in which case we are skipping xaml content
    /// without producing any html output
    /// </param>
    /// <param name="inlineStyle">
    /// StringBuilder used for collecting css properties for inline STYLE attributes on every level.
    /// </param>
    private static void WriteElement(XmlTextReader xamlReader, ISgmlWriter htmlWriter, StringBuilder inlineStyle)
    {
      Debug.Assert(xamlReader.NodeType == XmlNodeType.Element);

      if (htmlWriter == null)
      {
        // Skipping mode; recurse into the xaml element without any output
        WriteElementContent(xamlReader, /*htmlWriter:*/null, null);
      }
      else
      {
        string htmlElementName = null;

        switch (xamlReader.Name)
        {
          case "Run":
          case "Span":
            htmlElementName = "SPAN";
            break;
          case "InlineUIContainer":
            htmlElementName = "SPAN";
            break;
          case "Bold":
            htmlElementName = "B";
            break;
          case "Italic":
            htmlElementName = "I";
            break;
          case "Paragraph":
            htmlElementName = "P";
            break;
          case "BlockUIContainer":
            htmlElementName = "DIV";
            break;
          case "Section":
            htmlElementName = "DIV";
            break;
          case "Table":
            htmlElementName = "TABLE";
            break;
          case "TableColumn":
            htmlElementName = "COL";
            break;
          case "TableRowGroup":
            htmlElementName = "TBODY";
            break;
          case "TableRow":
            htmlElementName = "TR";
            break;
          case "TableCell":
            htmlElementName = "TD";
            break;
          case "List":
            string marker = xamlReader.GetAttribute("MarkerStyle");
            if (marker == null || marker == "None" || marker == "Disc" || marker == "Circle" || marker == "Square" || marker == "Box")
            {
              htmlElementName = "UL";
            }
            else
            {
              htmlElementName = "OL";
            }
            break;
          case "ListItem":
            htmlElementName = "LI";
            break;
          default:
            htmlElementName = null; // Ignore the element
            break;
        }

        if (htmlWriter != null && htmlElementName != null)
        {
          htmlWriter.Element(htmlElementName);

          WriteFormattingProperties(xamlReader, htmlWriter, inlineStyle);

          WriteElementContent(xamlReader, htmlWriter, inlineStyle);

          htmlWriter.ElementEnd();
        }
        else
        {
          // Skip this unrecognized xaml element
          WriteElementContent(xamlReader, /*htmlWriter:*/null, null);
        }
      }
    }
    /// <summary>
    /// Reads attributes of the current xaml element and converts
    /// them into appropriate html attributes or css styles.
    /// </summary>
    /// <param name="xamlReader">
    /// XmlTextReader which is expected to be at XmlNodeType.Element
    /// (opening element tag) position.
    /// The reader will remain at the same level after function complete.
    /// </param>
    /// <param name="htmlWriter">
    /// XmlTextWriter for output html, which is expected to be in
    /// after WriteStartElement state.
    /// </param>
    /// <param name="inlineStyle">
    /// String builder for collecting css properties for inline STYLE attribute.
    /// </param>
    private static void WriteFormattingProperties(XmlTextReader xamlReader, ISgmlWriter htmlWriter, StringBuilder inlineStyle)
    {
      Debug.Assert(xamlReader.NodeType == XmlNodeType.Element);

      // Clear string builder for the inline style
      inlineStyle.Remove(0, inlineStyle.Length);

      if (!xamlReader.HasAttributes)
      {
        return;
      }

      bool borderSet = false;

      while (xamlReader.MoveToNextAttribute())
      {
        string css = null;

        switch (xamlReader.Name)
        {
          // Character fomatting properties
          // ------------------------------
          case "Background":
            css = "background-color:" + ParseXamlColor(xamlReader.Value) + ";";
            break;
          case "FontFamily":
            css = "font-family:" + xamlReader.Value + ";";
            break;
          case "FontStyle":
            css = "font-style:" + xamlReader.Value.ToLower() + ";";
            break;
          case "FontWeight":
            css = "font-weight:" + xamlReader.Value.ToLower() + ";";
            break;
          case "FontStretch":
            break;
          case "FontSize":
            css = "font-size:" + xamlReader.Value + ";";
            break;
          case "Foreground":
            css = "color:" + ParseXamlColor(xamlReader.Value) + ";";
            break;
          case "TextDecorations":
            css = "text-decoration:underline;";
            break;
          case "TextEffects":
            break;
          case "Emphasis":
            break;
          case "StandardLigatures":
            break;
          case "Variants":
            break;
          case "Capitals":
            break;
          case "Fraction":
            break;

          // Paragraph formatting properties
          // -------------------------------
          case "Padding":
            css = "padding:" + ParseXamlThickness(xamlReader.Value) + ";";
            break;
          case "Margin":
            css = "margin:" + ParseXamlThickness(xamlReader.Value) + ";";
            break;
          case "BorderThickness":
            css = "border-width:" + ParseXamlThickness(xamlReader.Value) + ";";
            borderSet = true;
            break;
          case "BorderBrush":
            css = "border-color:" + ParseXamlColor(xamlReader.Value) + ";";
            borderSet = true;
            break;
          case "LineHeight":
            break;
          case "TextIndent":
            css = "text-indent:" + xamlReader.Value + ";";
            break;
          case "TextAlignment":
            css = "text-align:" + xamlReader.Value + ";";
            break;
          case "IsKeptTogether":
            break;
          case "IsKeptWithNext":
            break;
          case "ColumnBreakBefore":
            break;
          case "PageBreakBefore":
            break;
          case "FlowDirection":
            break;

          // Table attributes
          // ----------------
          case "Width":
            css = "width:" + xamlReader.Value + ";";
            break;
          case "ColumnSpan":
            htmlWriter.Attribute("COLSPAN", xamlReader.Value);
            break;
          case "RowSpan":
            htmlWriter.Attribute("ROWSPAN", xamlReader.Value);
            break;
        }

        if (css != null)
        {
          inlineStyle.Append(css);
        }
      }

      if (borderSet)
      {
        inlineStyle.Append("border-style:solid;mso-element:para-border-div;");
      }

      // Return the xamlReader back to element level
      xamlReader.MoveToElement();
      Debug.Assert(xamlReader.NodeType == XmlNodeType.Element);
    }
    /// <summary>
    /// Reads a content of current xaml element, converts it
    /// </summary>
    /// <param name="xamlReader">
    /// XmlTextReader which is expected to be at XmlNodeType.Element
    /// (opening element tag) position.
    /// </param>
    /// <param name="htmlWriter">
    /// May be null, in which case we are skipping the xaml element;
    /// witout producing any output to html.
    /// </param>
    /// <param name="inlineStyle">
    /// StringBuilder used for collecting css properties for inline STYLE attribute.
    /// </param>
    private static void WriteElementContent(XmlTextReader xamlReader, ISgmlWriter htmlWriter, StringBuilder inlineStyle)
    {
      Debug.Assert(xamlReader.NodeType == XmlNodeType.Element);

      bool elementContentStarted = false;

      if (xamlReader.IsEmptyElement)
      {
        if (htmlWriter != null && !elementContentStarted && inlineStyle.Length > 0)
        {
          // Output STYLE attribute and clear inlineStyle buffer.
          htmlWriter.Attribute("STYLE", inlineStyle.ToString());
          inlineStyle.Remove(0, inlineStyle.Length);
        }
        elementContentStarted = true;
      }
      else
      {
        while (ReadNextToken(xamlReader) && xamlReader.NodeType != XmlNodeType.EndElement)
        {
          switch (xamlReader.NodeType)
          {
            case XmlNodeType.Element:
              if (xamlReader.Name.Contains("."))
              {
                AddComplexProperty(xamlReader, inlineStyle);
              }
              else
              {
                if (htmlWriter != null && !elementContentStarted && inlineStyle.Length > 0)
                {
                  // Output STYLE attribute and clear inlineStyle buffer.
                  htmlWriter.Attribute("STYLE", inlineStyle.ToString());
                  inlineStyle.Remove(0, inlineStyle.Length);
                }
                elementContentStarted = true;
                WriteElement(xamlReader, htmlWriter, inlineStyle);
              }
              Debug.Assert(xamlReader.NodeType == XmlNodeType.EndElement || xamlReader.NodeType == XmlNodeType.Element && xamlReader.IsEmptyElement);
              break;
            case XmlNodeType.Comment:
              if (htmlWriter != null)
              {
                if (!elementContentStarted && inlineStyle.Length > 0)
                {
                  htmlWriter.Attribute("STYLE", inlineStyle.ToString());
                }
                htmlWriter.Comment(xamlReader.Value);
              }
              elementContentStarted = true;
              break;
            case XmlNodeType.CDATA:
            case XmlNodeType.Text:
            case XmlNodeType.SignificantWhitespace:
              if (htmlWriter != null)
              {
                if (!elementContentStarted && inlineStyle.Length > 0)
                {
                  htmlWriter.Attribute("STYLE", inlineStyle.ToString());
                }
                htmlWriter.Value(xamlReader.Value);
              }
              elementContentStarted = true;
              break;
          }
        }

        Debug.Assert(xamlReader.NodeType == XmlNodeType.EndElement);
      }
    }
 public HtmlWriterWrapper(ISgmlWriter writer)
 {
   _writer = writer;
 }