/***************************************************************************
                          xmlcode.cpp  -  description
                             -------------------
    begin                : Mo 23.06.2008
    copyright            : (C) 2008 by Andre Simon
    email                : andre.simon1@gmx.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <string>
#include <sstream>

#include "version.h"
#include "svggenerator.h"

using namespace std;
namespace highlight {

SVGGenerator::SVGGenerator()
: CodeGenerator(SVG)
{
    styleTagOpen.push_back("");
    styleTagOpen.push_back(getOpenTag("str"));
    styleTagOpen.push_back(getOpenTag("num"));
    styleTagOpen.push_back(getOpenTag("slc"));
    styleTagOpen.push_back(getOpenTag("com"));
    styleTagOpen.push_back(getOpenTag("esc"));
    styleTagOpen.push_back(getOpenTag("dir"));
    styleTagOpen.push_back(getOpenTag("dstr"));
    styleTagOpen.push_back(getOpenTag("line"));
    styleTagOpen.push_back(getOpenTag("sym"));

    styleTagClose.push_back("");
    styleTagClose.push_back(getCloseTag("str"));
    styleTagClose.push_back(getCloseTag("num"));
    styleTagClose.push_back(getCloseTag("slc"));
    styleTagClose.push_back(getCloseTag("com"));
    styleTagClose.push_back(getCloseTag("esc"));
    styleTagClose.push_back(getCloseTag("dir"));
    styleTagClose.push_back(getCloseTag("dstr"));
    styleTagClose.push_back(getCloseTag("line"));
    styleTagClose.push_back(getCloseTag("sym"));

    spacer = " ";
    newLineTag = "\n";
    styleCommentOpen="/*";
    styleCommentClose="*/";
}

SVGGenerator::~SVGGenerator() {}

string SVGGenerator::getStyleDefinition()
{
    if (styleDefinitionCache.empty()) {
        ostringstream os;
        if (includeStyleDef) {
          os << "<style type=\"text/css\">\n"
             << "<![CDATA[\n";
        }
        os << "rect { fill:#"
           << (docStyle.getBgColour().getRed(XML))
           << (docStyle.getBgColour().getGreen(XML))
           << (docStyle.getBgColour().getBlue(XML))
           << "; } \n";
        os << "g { font-size: " << getBaseFontSize();
        os << "; font-family: \"" << getBaseFont() << "\"; }\n";
        os << getAttributes("text", docStyle.getDefaultStyle())
           << getAttributes("tspan.num", docStyle.getNumberStyle())
           << getAttributes("tspan.esc", docStyle.getEscapeCharStyle())
           << getAttributes("tspan.str", docStyle.getStringStyle())
           << getAttributes("tspan.dstr", docStyle.getDirectiveStringStyle())
           << getAttributes("tspan.slc", docStyle.getSingleLineCommentStyle())
           << getAttributes("tspan.com", docStyle.getCommentStyle())
           << getAttributes("tspan.dir", docStyle.getDirectiveStyle())
           << getAttributes("tspan.sym", docStyle.getSymbolStyle())
           << getAttributes("tspan.line", docStyle.getLineStyle());

        KeywordStyles styles = docStyle.getKeywordStyles();
        for (KSIterator it=styles.begin(); it!=styles.end(); it++){
            os << getAttributes("tspan."+it->first, it->second);
        }
        if (includeStyleDef) {
          os << "]]>\n"
             << "</style>";
        }
        styleDefinitionCache=os.str();
    }
    return styleDefinitionCache;
}


string SVGGenerator::getAttributes(const string & elemName,
                                           const ElementStyle & elem)
{
  ostringstream s;
  if (!elemName.empty()) {
     s << /*cssClassName<<"."<<*/ elemName<<" { ";
  }
  s << "fill:#"
    << (elem.getColour().getRed(HTML))
    << (elem.getColour().getGreen(HTML))
    << (elem.getColour().getBlue(HTML))
    << ( elem.isBold() ?     "; font-weight:bold" :"" )
    << ( elem.isItalic() ?   "; font-style:italic" :"" )
    << ( elem.isUnderline()? "; text-decoration:underline" :"" );
  if (!elemName.empty()) {
     s << "; }\n" ;
  }
  return s.str();
}

string  SVGGenerator::getOpenTag(const string& styleName ){
    return "<tspan class=\""+styleName+"\">";
}

string  SVGGenerator::getCloseTag(const string& styleName ){
    return "</tspan>";
}

string SVGGenerator::getHeader()
{
    ostringstream header;
    header << "<?xml version=\"1.0\"";
    if (encodingDefined()) {
        header << " encoding=\"" << encoding << "\"";
    }
    header << "?>\n";
    if (!includeStyleDef) {
	header  << "<?xml-stylesheet type=\"text/css\" href=\""
		<< getStyleOutputPath()
		<< "\"?>\n";
    }
    header << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.2//EN\" "
           << "\"http://www.w3.org/Graphics/SVG/1.2/DTD/svg12.dtd\">\n";
    header << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.2\" "
           << "baseProfile=\"full\" xml:space=\"preserve\"";
    if (width.size()) header << " width=\""<<width<<"\"";
    if (height.size()) header << " height=\""<<height<<"\"";
   //viewBox=\"0 0 800 600\"
    header << ">\n<desc>" << docTitle << "</desc>\n";
    if (includeStyleDef) {
      header << "<defs>\n";
      header << getStyleDefinition();
      header << "\n</defs>\n";
    }
    return header.str();
}

void SVGGenerator::printBody()
{
  *out << "<g>\n<rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\"/>"; // rect: background color
  int fontSize=0;
  StringTools::str2num<int>(fontSize, getBaseFontSize(), std::dec);
  *out << "\n<text x=\"10\" y=\""<<fontSize*2<<"\">";
  processRootState();
  *out << "</text>\n</g>\n";
}


string SVGGenerator::getFooter()
{
  ostringstream os;
  os <<"</svg>\n";
  os<< "<!-- SVG generated by Highlight "
     << HIGHLIGHT_VERSION
     << ", "
     << HIGHLIGHT_URL
     <<" -->\n";
  return os.str();
}

string SVGGenerator::maskCharacter(unsigned  char c)
{
  switch (c)
    {
      case '<' :
      return "&lt;";
      break;
    case '>' :
      return "&gt;";
      break;
    case '&' :
      return "&amp;";
      break;
    case '\"' :
      return "&quot;";
      break;
    default:
      return string( 1, c );
    }
}

string SVGGenerator::getMatchingOpenTag(unsigned int styleID){
    return getOpenTag(langInfo.getKeywordClasses()[styleID]);
}

string SVGGenerator::getMatchingCloseTag(unsigned int styleID){
    return getCloseTag(langInfo.getKeywordClasses()[styleID]);
}

string SVGGenerator::getNewLine(){

  if (lineNumber>1) {
     ostringstream os;
     int fontSize=0;
     StringTools::str2num<int>(fontSize, getBaseFontSize(), std::dec);
     os<< "</text>\n<text x=\"10\" y=\""<<(lineNumber*fontSize*2)<<"\">";
     return os.str();
  } else {
     return "";
  }
}

void SVGGenerator::setSVGSize( const string& w, const string& h){
   width=w;
   height=h;
}

}
