/* AbiSource
 * 
 * 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.
 */

#ifndef _OD_STREAMLISTENER_H_
#define _OD_STREAMLISTENER_H_

// Internal includes
#include "OD_ListenerStateAction.h"
#include "OD_ElementStack.h"
#include "OD_XMLRecorder.h"

// External includes
#include <gsf/gsf.h>

// AbiWord includes
#include <ut_types.h>
#include <ut_xml.h>
#include <ut_vector.h>

// Internal classes
class OD_Office_Styles;
class OD_Postpone_ListenerState;
class OD_Abi_Data;

// AbiWord classes
class PD_Document;

/**
 * This class parses the OpenDocument XML.
 * 
 * Its behaviour is distributed among several OD_*_ListenerState classes.
 * So, the code used for its functions depends on its current state.
 *
 * It follows the State design pattern.
 */
class OD_StreamListener : public virtual UT_XML::Listener {

public:

    OD_StreamListener(PD_Document* pAbiDocument, GsfInfile* pGsfInfile,
                      OD_Office_Styles* pStyles, OD_Abi_Data& rAbiData,
                      OD_ElementStack* pElementStack = NULL);
    
    virtual ~OD_StreamListener();
    
    void startElement (const XML_Char* pName, const XML_Char** ppAtts) {
        _startElement(pName, ppAtts, false);
    }
                       
    void endElement (const XML_Char* pName) {
        _endElement(pName, false);
    }

    void charData (const XML_Char* pBuffer, int length);

    UT_Error setState(const char* pStateName);
    void setState(OD_ListenerState* pState, bool deleteWhenPop);

private:

    void _startElement (const XML_Char* pName, const XML_Char** ppAtts,
                       bool doingRecursion);
                       
    void _endElement (const XML_Char* pName, bool doingRecursion);

    void _handleStateAction();
    void _clear();
    OD_ListenerState* _createState(const char* pStateName);
    void _resumeParsing(OD_Postpone_ListenerState* pPostponeState);
    void _playRecordedElement();

    PD_Document* m_pAbiDocument;
    GsfInfile* m_pGsfInfile;
    OD_Office_Styles* m_pStyles;
    OD_Abi_Data& m_rAbiData;

    // A place holder used by the states to signal state changes, etc.
    OD_ListenerStateAction m_stateAction;

    OD_ElementStack* m_pElementStack;
    
    bool m_recordingElement;
    UT_UTF8String m_recordedElementName;
    OD_XMLRecorder m_xmlRecorder;
    UT_uint32 m_recordedElemenStackSize;
    
    class StackCell {
    public:
        StackCell() {m_pState=NULL; m_deleteWhenPop=false;}
        StackCell(OD_ListenerState* pState, bool deleteWhenPop) {
            m_deleteWhenPop = deleteWhenPop;
            m_pState = pState;
        }
        // Work around the "return 0" issue of the UT_GenericVector::getNhItem()
        StackCell(UT_uint32 i) {m_pState=NULL; m_deleteWhenPop=false;}
        
        StackCell& operator=(const StackCell& sc) {
            this->m_deleteWhenPop = sc.m_deleteWhenPop;
            this->m_pState = sc.m_pState;
            
            return *this;
        }
        
        bool m_deleteWhenPop;
        OD_ListenerState* m_pState;
    };
    
    OD_ListenerState* m_pCurrentState;
    bool m_deleteCurrentWhenPop;
    
    UT_GenericVector <OD_StreamListener::StackCell> m_stateStack;
    UT_GenericVector <OD_Postpone_ListenerState*> m_postponedParsing;
};

#endif //_OD_STREAMLISTENER_H_
