package info.bliki.wiki.tags;

import info.bliki.htmlcleaner.TagNode;
import info.bliki.htmlcleaner.Utils;
import info.bliki.wiki.filter.ITextConverter;
import info.bliki.wiki.model.IWikiModel;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class HTMLTag extends TagNode {
  public final static boolean NEW_LINES = true;

  // compile the regex, for better performance
  protected final static Pattern XML_QNAME = Pattern
    .compile("^[_A-Za-z][\\w\\.\\-]*(:[_A-Za-z][\\w\\.\\-]*)?$");

  public static void appendEscapedAttributes(Appendable buf,
      Map<String, String> tagAtttributes) throws IOException {
    if (tagAtttributes != null) {
      for (Map.Entry<String, String> currEntry : tagAtttributes.entrySet()) {
        String attName = currEntry.getKey();
        if (attName.length() >= 1 && Character.isLetter(attName.charAt(0))) {
          // skip any invalid element names
          // these usually come from bad markup input
          // http://www.w3.org/TR/REC-xml-names/#NT-PrefixedName
          if (!XML_QNAME.matcher(attName).matches()) {
            continue;
          }
          String attValue = currEntry.getValue();
          buf.append(" ");
          buf.append(attName);
          buf.append("=\"");
          Utils.escapeXmlToBuffer(attValue, buf, false, false, false);
          buf.append("\"");
        }
      }
    }
  }

  public static void appendUnescapedAttributes(Appendable buf,
      Map<String, String> tagAtttributes) throws IOException {
    if (tagAtttributes != null) {
      for (Map.Entry<String, String> currEntry : tagAtttributes.entrySet()) {
        String attName = currEntry.getKey();
        if (attName.length() >= 1 && Character.isLetter(attName.charAt(0))) {
          String attValue = currEntry.getValue();

          buf.append(" " + attName + "=\"" + attValue + "\"");
        }
      }
    }
  }

  public HTMLTag(String name) {
    super(name);
  }

  public void appendAttributes(Appendable buf,
      Map<String, String> tagAtttributes) throws IOException {
    appendEscapedAttributes(buf, tagAtttributes);
  }

  public void renderHTML(ITextConverter converter, Appendable buf,
      IWikiModel model) throws IOException {
    boolean newLines = false;
    TagNode node = this;
    String name = node.getName();
    List<Object> children = node.getChildren();
    if (children.size() == 0) {
      // don't render empty tags (see Issue98)
      if (!name.equals("a") && !name.equals("br")) {
        // because of section tags allow <a href=\"#Section..." />
        return;
      }
    }

    if (NEW_LINES) {
      if (name.equals("div")
        || name.equals("p")
        || name.equals("li")
        || name.equals("td")) {
        buf.append('\n');
      } else if (name.equals("table")
        || name.equals("ul")
        || name.equals("ol")
        || name.equals("th")
        || name.equals("tr")
        || name.equals("pre")) {
        buf.append('\n');
        newLines = true;
      }
    }
    buf.append('<');
    buf.append(name);

    Map<String, String> tagAtttributes = node.getAttributes();

    appendAttributes(buf, tagAtttributes);

    if (children.size() == 0) {
      buf.append(" />");
    } else {
      buf.append('>');
      if (newLines) {
        buf.append('\n');
      }
      converter.nodesToText(children, buf, model);
      if (newLines) {
        buf.append('\n');
      }
      buf.append("</");
      buf.append(node.getName());
      buf.append('>');
    }
  }

  public void renderHTMLWithoutTag(ITextConverter converter, Appendable buf,
      IWikiModel model) throws IOException {
    TagNode node = this;
    List<Object> children = node.getChildren();
    if (children.size() != 0) {
      converter.nodesToText(children, buf, model);
    }
  }

  /**
   * Set if the text is rendered as a template. This method is a placeholder, it
   * can be overridden in subclasses.
   * 
   * @param isTemplate
   *          <code>true</code>, if the text is rendered as a template. See
   *          {@link info.bliki.wiki.filter.WikipediaParser#isTemplate()}
   */
  public void setTemplate(boolean isTemplate) {
    // empty function
  }
}