/* 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_Listener.h"

// Internal includes
#include "OO_StylesWriter.h"

// Abiword includes
#include <px_ChangeRecord.h>
#include <px_CR_Span.h>
#include <px_CR_Strux.h>




OO_Listener::OO_Listener (PD_Document* pDocument,
                          IE_Exp_OpenDocument* pie,
                          OO_ListenerImpl* pListenerImpl)
    : PL_Listener (),
      m_pDocument(pDocument),
      m_pie(pie),
      m_pListenerImpl(pListenerImpl),
      m_bInBlock(false),
      m_bInSpan(false)
{
}


bool OO_Listener::populate(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr)
{
    switch (pcr->getType()) {
        case PX_ChangeRecord::PXT_InsertSpan:
        {
            const PX_ChangeRecord_Span* pcrs =
                static_cast<const PX_ChangeRecord_Span *>(pcr);
                
            PT_BufIndex bi = pcrs->getBufIndex();
            PT_AttrPropIndex api = pcr->getIndexAP();
            if (api) {
                _openSpan(api);
            }
            m_pListenerImpl->insertText(m_pDocument->getPointer(bi), pcrs->getLength());
            if (api) {
                _closeSpan();
            }
            return true;
        }
        default:
            break;
    }
    return true;
}


bool OO_Listener::populateStrux(PL_StruxDocHandle sdh,
const PX_ChangeRecord * pcr,
PL_StruxFmtHandle * psfh)
{
    const PX_ChangeRecord_Strux * pcrx = static_cast<const PX_ChangeRecord_Strux *> (pcr);
    *psfh = 0;                                    // we don't need it.

    switch (pcrx->getStruxType()) {
        case PTX_Block:
        {
            _closeSpan ();
            _openBlock(pcr->getIndexAP());
        }
    }

    return true;
}


bool OO_Listener::change(PL_StruxFmtHandle sfh,
const PX_ChangeRecord * pcr)
{
    UT_ASSERT_NOT_REACHED();
    return true;
}


bool OO_Listener::insertStrux(PL_StruxFmtHandle sfh,
const PX_ChangeRecord * pcr,
PL_StruxDocHandle sdh,
PL_ListenerId lid,
void (* pfnBindHandles)(PL_StruxDocHandle sdhNew,
PL_ListenerId lid,
PL_StruxFmtHandle sfhNew))
{
    UT_ASSERT_NOT_REACHED();
    return true;
}


bool OO_Listener::signal(UT_uint32 iSignal)
{
    UT_ASSERT_NOT_REACHED();
    return true;
}


void OO_Listener::endDocument()
{
    _closeBlock();
}


void OO_Listener::_openBlock (PT_AttrPropIndex api)
{
    if (m_bInBlock)
        _closeBlock();

    const PP_AttrProp * pAP = NULL;
    bool bHaveProp = m_pDocument->getAttrProp(api, &pAP);
    bool bIsHeading = false;
    UT_String styleAtts, propAtts, font;

    if (bHaveProp && pAP) {
        UT_UTF8String sa, pa, f;
        OO_StylesWriter::map(pAP, sa, pa, f);

        const XML_Char * szStyle = NULL;
        pAP->getAttribute("style", szStyle);

        if (szStyle && pa.size()) {
            // custom properties, prepare to derive style
            sa += UT_UTF8String_sprintf("style:parent-style-name=\"%s\" ", szStyle);
        }
        else if (szStyle)
            sa += UT_UTF8String_sprintf("text:style-name=\"%s\" ", szStyle);

        // FIXME: hacky, but in sxw there is a distinction between heading- and text paragraphs
        // we should probably also care about text:level here
        if (szStyle && strstr(szStyle, "Heading"))
            bIsHeading = true;

        styleAtts += sa.utf8_str();
        propAtts += pa.utf8_str();
        font += f.utf8_str();
    }

    m_pListenerImpl->openBlock(styleAtts, propAtts, font, bIsHeading);
    m_bInBlock = true;
}


void OO_Listener::_closeBlock ()
{
    if (!m_bInBlock)
        return;

    m_pListenerImpl->closeBlock();
    m_bInBlock = false;
}


void OO_Listener::_openSpan(PT_AttrPropIndex api)
{
    if (!m_bInBlock) {
        return;
    }
    const PP_AttrProp * pAP = NULL;
    bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);

    UT_String propAtts, font;

    if (bHaveProp && pAP) {
        UT_UTF8String sa, pa, f;
        OO_StylesWriter::map(pAP, sa, pa, f);

        if (sa.size())
            UT_DEBUGMSG(("OO_Listener::_openSpan(): style atts in span"));

        propAtts += pa.utf8_str();
        font += f.utf8_str();
    }

    m_pListenerImpl->openSpan(propAtts, font);
    m_bInSpan = true;
}


void OO_Listener::_closeSpan()
{
    if (m_bInSpan)
        m_pListenerImpl->closeSpan();
    m_bInSpan = false;
}
