/* AbiSource
 * 
 * Copyright (C) 2002 Dom Lachowicz <cinamod@hotmail.com>
 * Copyright (C) 2004 Robert Staudinger <robsta@stereolyzer.net>
 * Copyright (C) 2005 Daniel d'Andrada T. de Carvalho
 * <daniel.carvalho@indt.org.br>
 * 
 * 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.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */
 
 
// Class definition include
#include "OO_WriterImpl.h"
 
// Internal includes
#include "OO_Common.h"
#include "OO_StylesWriter.h"
 

// External includes 
#include <gsf/gsf-output-stdio.h>
#include <gsf/gsf-outfile.h>
 
 
 
/**
 * Constructor
 */
OO_WriterImpl::OO_WriterImpl(GsfOutfile* pOutfile,
                             OO_StylesContainer* pStylesContainer)
        : OO_ListenerImpl(),
          m_pStylesContainer(pStylesContainer)
{
    m_pContentStream = gsf_outfile_new_child (pOutfile, "content.xml", FALSE);

    static const char * const preamble [] = {
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
        "<!DOCTYPE office:document-content PUBLIC \"-//OpenOffice.org//DTD OfficeDocument 1.0//EN\" \"office.dtd\">\n",
        "<office:document-content xmlns:office=\"http://openoffice.org/2000/office\" xmlns:style=\"http://openoffice.org/2000/style\" xmlns:text=\"http://openoffice.org/2000/text\" xmlns:table=\"http://openoffice.org/2000/table\" xmlns:draw=\"http://openoffice.org/2000/drawing\" xmlns:fo=\"http://www.w3.org/1999/XSL/Format\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:number=\"http://openoffice.org/2000/datastyle\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:chart=\"http://openoffice.org/2000/chart\" xmlns:dr3d=\"http://openoffice.org/2000/dr3d\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"http://openoffice.org/2000/form\" xmlns:script=\"http://openoffice.org/2000/script\" office:class=\"text\" office:version=\"1.0\">\n",
        "<office:script/>\n"
    };
    
    oo_writeToStream(m_pContentStream, preamble, NrElements(preamble));

    // in my sample files content.xml, styles.xml font-decl sections are the same
    UT_UTF8String fontDecls = "<office:font-decls>\n";
    OO_StylesWriter::addFontDecls(fontDecls, *m_pStylesContainer);
    fontDecls += "</office:font-decls>\n";
    oo_writeUTF8String(m_pContentStream, fontDecls);

    oo_writeUTF8String(m_pContentStream, "<office:automatic-styles>\n");

    int *styleNum = NULL;
    UT_String styleString;

    // span styles
    UT_GenericVector<int*> *tempStylesValuesList = m_pStylesContainer->enumerateSpanStyles();
    UT_GenericVector<const UT_String*> *tempStylesKeysList = m_pStylesContainer->getSpanStylesKeys();

    for (UT_uint32 i=0; i<tempStylesValuesList->size(); i++) {
        styleNum = tempStylesValuesList->getNthItem(i);
        const UT_String *styleProps = tempStylesKeysList->getNthItem(i);
        styleString = UT_String_sprintf("<style:style style:name=\"S%i\" style:family=\"%s\"><style:properties %s/></style:style>\n", *styleNum, "text", styleProps->c_str());
        _writeString(m_pContentStream, styleString);
        UT_DEBUGMSG(("%s", styleString.c_str()));
        UT_DEBUGMSG(("\"%s\"\n", styleProps->c_str()));
    }
    DELETEP(tempStylesKeysList);
    DELETEP(tempStylesValuesList);

    // block styles
    UT_GenericVector<const UT_String*> *tempBlockStylesKeysList = m_pStylesContainer->getBlockStylesKeys();

    for (UT_uint32 i=0; i < tempBlockStylesKeysList->size(); i++) {
        const UT_String* key = tempBlockStylesKeysList->getNthItem(i);
        const UT_String* val = m_pStylesContainer->pickBlockAtts(key);
        styleString = UT_String_sprintf("<style:style style:name=\"P%i\" %s style:family=\"paragraph\">", i, val->c_str());
        styleString += UT_String_sprintf("<style:properties %s/>", key->c_str());
        styleString += UT_String_sprintf("</style:style>");
        _writeString(m_pContentStream, styleString);
    }
    DELETEP(tempBlockStylesKeysList);

    //m_acc.writeStylePreamble(m_contentStream);

    static const char * const midsection [] = {
        "</office:automatic-styles>\n",
        "<office:body>\n",
        "<text:sequence-decls>\n",
        "<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Illustration\"/>\n",
        "<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Table\"/>\n",
        "<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Text\"/>\n",
        "<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Drawing\"/>\n",
        "</text:sequence-decls>\n"
    };

    oo_writeToStream(m_pContentStream, midsection, NrElements(midsection));
}


/**
 * Destructor
 */
OO_WriterImpl::~OO_WriterImpl()
{
    static const char * const postamble [] = {
        "</office:body>\n",
        "</office:document-content>\n"
    };
    oo_writeToStream(m_pContentStream, postamble, NrElements(postamble));

    oo_gsf_output_close(m_pContentStream);
}


/**
 * 
 */
void OO_WriterImpl::insertText(const UT_UCSChar * data, UT_uint32 length)
{
    _outputCharData(m_pContentStream, data, length);
}



/**
 * 
 */
void OO_WriterImpl::openBlock(UT_String & styleAtts, UT_String & styleProps, UT_String & font, bool bIsHeading)
{
    UT_UTF8String tag, props;

    if (styleAtts.size() && styleProps.size()) {
        // derive automatic style
        props = UT_UTF8String_sprintf("text:style-name=\"P%i\" ",
                    m_pStylesContainer->getBlockStyleNum(styleAtts, styleProps));
    } else {
        props = styleAtts.c_str();
    }

    if (bIsHeading) {
        tag = "<text:h " + props + ">";
        m_blockEnd = "</text:h>\n";
    } else {
        tag = "<text:p " + props + ">";
        m_blockEnd = "</text:p>\n";
    }

    oo_writeUTF8String(m_pContentStream, tag);
}


/**
 * 
 */
void OO_WriterImpl::closeBlock()
{
    oo_writeUTF8String (m_pContentStream, m_blockEnd);
    m_blockEnd.clear();
}



/**
 * 
 */
void OO_WriterImpl::openSpan(UT_String & props, UT_String & font)
{
    UT_UTF8String spanString = UT_UTF8String_sprintf("<text:span text:style-name=\"S%i\">",
        m_pStylesContainer->getSpanStyleNum(props));

    oo_writeUTF8String(m_pContentStream, spanString);
}



/**
 * 
 */
void OO_WriterImpl::closeSpan()
{
    UT_UTF8String closeSpan = "</text:span>";
    oo_writeUTF8String(m_pContentStream, closeSpan);
}
 
 
 
/**
 * 
 */
void OO_WriterImpl::_writeString (GsfOutput * output, const UT_String & str)
{
   oo_gsf_output_write (output, str.length(), reinterpret_cast<const guint8*>(str.c_str()));
}




/**
 * 
 */
void OO_WriterImpl::_outputCharData (GsfOutput * output,
                                     const UT_UCSChar * data,
                                     UT_uint32 length)
{
    UT_UTF8String sBuf;
    const UT_UCSChar * pData;

    UT_ASSERT(sizeof(UT_Byte) == sizeof(char));

    for (pData=data; (pData<data+length); /**/) {
        switch (*pData) {
            case '<':
                sBuf += "&lt;";
                pData++;
                break;

            case '>':
                sBuf += "&gt;";
                pData++;
                break;

            case '&':
                sBuf += "&amp;";
                pData++;
                break;

            case UCS_LF:                          //line breaks
                sBuf += "<text:line-break/>";
                pData++;
                break;

            case UCS_TAB:
                sBuf += "\t";
                pData++;
                break;

            default:
                if (*pData < 0x20)                // Silently eat these characters.
                    pData++;
                else {
                    sBuf.appendUCS4 (pData, 1);
                    pData++;
                }
        }
    }
    oo_writeUTF8String (output, sBuf);
}
