/***************************************************************************
                          xmlcode.cpp  -  description
                             -------------------
    begin                : Do 20.01.2005
    copyright            : (C) 2005 by Andre Simon
    email                : andre.simon1@gmx.de
 ***************************************************************************/


/*
This file is part of Highlight.

Highlight 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 3 of the License, or
(at your option) any later version.

Highlight is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Highlight.  If not, see <http://www.gnu.org/licenses/>.
*/


#include <string>
#include <sstream>

#include "version.h"
#include "xmlgenerator.h"

using namespace std;
namespace highlight
{

	XmlGenerator::XmlGenerator()
			: CodeGenerator ( XML )
	{
		spacer = " ";
		newLineTag = "<br />\n";
	}

	XmlGenerator::~XmlGenerator() {}

	string XmlGenerator::getHeader()
	{
		ostringstream header;
		header << "<?xml version=\"1.0\"";
		if ( encodingDefined() )
		{
			header << " encoding=\"" << encoding << "\"";
		}
		header << "?>\n<document>";
		header << "\n<title>" << docTitle << "</title>";
		header << getStyleDefinition();
		return header.str();
	}

	void XmlGenerator::printBody()
	{
		*out << "<source>\n";
		processRootState();
		*out << "</source>\n";
	}


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

	void XmlGenerator::initOutputTags(){
		openTags.push_back ( getOpenTag ( STY_NAME_STD ) );
		openTags.push_back ( getOpenTag ( STY_NAME_STR ) );
		openTags.push_back ( getOpenTag ( STY_NAME_NUM ) );
		openTags.push_back ( getOpenTag ( STY_NAME_SLC ) );
		openTags.push_back ( getOpenTag ( STY_NAME_COM ) );
		openTags.push_back ( getOpenTag ( STY_NAME_ESC ) );
		openTags.push_back ( getOpenTag ( STY_NAME_DIR ) );
		openTags.push_back ( getOpenTag ( STY_NAME_DST ) );
		openTags.push_back ( getOpenTag ( STY_NAME_LIN ) );
		openTags.push_back ( getOpenTag ( STY_NAME_SYM ) );

		closeTags.push_back ( getCloseTag ( STY_NAME_STD ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_STR ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_NUM ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_SLC ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_COM ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_ESC ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_DIR ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_DST ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_LIN ) );
		closeTags.push_back ( getCloseTag ( STY_NAME_SYM ) );
	}

	string XmlGenerator::getStyleDefinition()
	{
		if ( styleDefinitionCache.empty() )
		{
			ostringstream os;
			os << "\n<style>\n"
			<< "\t<bgcolor value=\""
			<< ( docStyle.getBgColour().getRed ( XML ) )
			<< ( docStyle.getBgColour().getGreen ( XML ) )
			<< ( docStyle.getBgColour().getBlue ( XML ) )
			<< "\" />\n";
			os << "\t<font size=\"" << getBaseFontSize();
			os << "\" family=\"" << getBaseFont() << "\" />\n";
			os << getAttributes ( STY_NAME_STD, docStyle.getDefaultStyle() )
			<< getAttributes ( STY_NAME_NUM, docStyle.getNumberStyle() )
			<< getAttributes ( STY_NAME_ESC, docStyle.getEscapeCharStyle() )
			<< getAttributes ( STY_NAME_STR, docStyle.getStringStyle() )
			<< getAttributes ( STY_NAME_DST, docStyle.getDirectiveStringStyle() )
			<< getAttributes ( STY_NAME_SLC, docStyle.getSingleLineCommentStyle() )
			<< getAttributes ( STY_NAME_COM, docStyle.getCommentStyle() )
			<< getAttributes ( STY_NAME_DIR, docStyle.getDirectiveStyle() )
			<< getAttributes ( STY_NAME_SYM, docStyle.getSymbolStyle() )
			<< getAttributes ( STY_NAME_LIN, docStyle.getLineStyle() );

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


	string XmlGenerator::getAttributes ( const string & elemName,
	                                     const ElementStyle & elem )
	{
		ostringstream s;
		s  << "\t<class name=\""
		<< elemName
		<<"\" color=\""
		<< ( elem.getColour().getRed ( XML ) )
		<< ( elem.getColour().getGreen ( XML ) )
		<< ( elem.getColour().getBlue ( XML ) )
		<< "\" bold=\""
		<< ( elem.isBold() ? "true" :"false" )
		<< "\" italic=\""
		<< ( elem.isItalic() ? "true" :"false" )
		<< "\" underline=\""
		<< ( elem.isUnderline() ? "true" :"false" )
		<< "\" />\n" ;
		return  s.str();
	}

	string  XmlGenerator::getOpenTag ( const string& styleName )
	{
		return "<"+styleName+">";
	}

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

	string XmlGenerator::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 XmlGenerator::getKeywordOpenTag ( unsigned int styleID )
	{
		return getOpenTag ( langInfo.getKeywordClasses() [styleID] );
	}

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

}