/* This file is part of the wvWare 2 project
   SPDX-FileCopyrightText: 2002-2003 Werner Trobin <trobin@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02111-1307, USA.
*/

#ifndef HANDLERS_H
#define HANDLERS_H

#include <vector>

#include "functordata.h"
#include "global.h"
#include "sharedptr.h"
#include "word97_generated.h"
#include "wv2_export.h"

namespace wvWare
{

class Parser9x;
struct UChar;
class UString;
template<class ParserT, typename Data>
class Functor;
typedef Functor<Parser9x, HeaderData> HeaderFunctor;
typedef Functor<Parser9x, AnnotationData> AnnotationFunctor;
typedef Functor<Parser9x, TableRowData> TableRowFunctor;
typedef Functor<Parser9x, FootnoteData> FootnoteFunctor;
typedef Functor<Parser9x, PictureData> PictureFunctor;

/**
 * This class allows to replace the character values of some
 * characters in a Word document, like non-breaking hyphens,...
 * during the processing. As we have to look at every single
 * character anyway, we can as well do single-character replacement
 * in case it's necessary. That way you don't have to scan all the
 * text again in the consumer filter.
 *
 * We use U8 instead of U16 as all interesting Word characters are
 * within 7bit ASCII range, the names of the methods should be
 * descriptive enough.
 */
class WV2_EXPORT InlineReplacementHandler
{
public:
    virtual ~InlineReplacementHandler();

    virtual U8 tab();
    virtual U8 hardLineBreak();
    virtual U8 columnBreak();
    virtual U8 nonBreakingHyphen();
    virtual U8 nonRequiredHyphen();
    virtual U8 nonBreakingSpace();
};

/**
 * The SubDocumentHandler is more or less a state-callback class. It informs
 * the consumer filter about changes of subdocuments like body, header,
 * footnote,...
 * This class is needed as we reuse one @ref TextHandler object for all the
 * text we find, no matter whether it's inside the main body or within a textbox.
 */
class WV2_EXPORT SubDocumentHandler
{
public:
    virtual ~SubDocumentHandler();

    /**
     * Set the progress of WordDocument Stream processing.  All other
     * streams (Table, Data) are referred from this one.
     */
    virtual void setProgress(const int percent);

    /**
     * This method is called as soon as you call @ref Parser::parse. It indicates
     * the start of the body text (the main document text-flow).
     */
    virtual void bodyStart();
    /**
     * This method is called when all characters of the main body text
     * are processed.
     */
    virtual void bodyEnd();

    /**
     * Every time you invoke a @ref FootnoteFunctor this method will be called.
     * Note that @ref FoonoteFunctor is also emitted when we find endnotes.
     */
    virtual void footnoteStart();
    /**
     * Once the footnote characters are processed this method is called.
     */
    virtual void footnoteEnd();

    /**
     * 2.3.4
     *
     * Comments/Annotations (Microsoft isn't consistent)
     *
     * The comment document contains all of the content in the comments/annotation. It begins at the CP
     * immediately following the Header Document and is FibRgLw97.ccpAtn characters long.
     * The locations of individual comments within the comment document are specified by a PlcfandTxt
     * whose location is specified by the fcPlcfandTxt member of FibRgFcLcb97. The locations of the
     * comment reference characters in the Main Document are specified by a PlcfandRef whose location is
     * specified by the fcPlcfandRef member of FibRgFcLcb97.
     *
     * Let's see whether it makes sense when I continue implementing this...
     */
    /**
     * Every time you invoke a @ref AnnotationFunctor this method will be called.
     */
    virtual void annotationStart();
    /**
     * Once the annotation characters are processed this method is called.
     */
    virtual void annotationEnd();

    /**
     * For every section in a Word document a @ref HeaderFunctor is emitted.
     * Invoking the functor triggers the parsing of all headers inside the
     * section, this method is called to indicate that.
     */
    virtual void headersStart();
    /**
     * This method is called once all headers and footers of the current
     * section are processed.
     */
    virtual void headersEnd();
    /**
     * There are up to 6 headers/footers for every section. This method informs
     * you about the begin of a new header or footer of the given type.
     *
     * The default header/footer is the *Odd one. If you also get any *Even
     * header or footer the document's left and right pages have different
     * headers/footers. In case you get a *First header or footer the first
     * page of this section has a different header or footer.
     *
     * @param type The type of the header or footer. Always emitted in
     *             the order of definition in the enum
     */
    virtual void headerStart(HeaderData::Type type);
    /**
     * The end of the current header or footer.
     */
    virtual void headerEnd();
    /**
     * This method sends a binary mask providing the information of
     * empty/nonempty header and footer stories for each section.  Size of
     * the list equals the number of sections present in the document.
     */
    virtual void headersMask(QList<bool> mask);
};

namespace Word97
{
struct TAP;
}

/**
 * The TableHandler class is the interface for all table related callbacks.
 * It informs about about starts and ends of table cells and rows.
 * Only invoking a table row functor triggers the parsing of the given table
 * row, and results in table(Row|Cell)(Start|End) callbacks.
 *
 * Word doesn't store information about table boundaries internally, but
 * it's quite easy to find out the start/end of a table, as all table
 * row functors are emitted in a row (pun intended). This means that if
 * you get a sequence of table row functors and then suddenly a
 * paragraphStart callback, you know that the table has ended.
 */
class WV2_EXPORT TableHandler
{
public:
    virtual ~TableHandler();

    /**
     * Indicates the start of a table row with the passed properties.
     */
    virtual void tableRowStart(SharedPtr<const Word97::TAP> tap);
    /**
     * Indicates the end of a table row.
     */
    virtual void tableRowEnd();
    /**
     * This method is invoked every time we start processing a new cell.
     */
    virtual void tableCellStart();
    /**
     * This method is invoked every time we reach a cell end.
     */
    virtual void tableCellEnd();
};

/**
 * The GraphicsHandler class is the interface for MS-ODRAW objects related
 * callbacks.  Office Drawing Binary File Format structures are parsed by
 * msoscheme.
 */
class WV2_EXPORT GraphicsHandler
{
public:
    virtual ~GraphicsHandler();

    /**
     * This method gets called when a floating object is found.
     * @param globalCP (character position)
     */
    virtual void handleFloatingObject(unsigned int globalCP);

    /**
     * This method gets called when an inline object is found.  @param data
     * the picture properties and offset into data stream.
     */
    virtual QString handleInlineObject(const PictureData &data, const bool isBulletPicture = false);
};

class ParagraphProperties;
struct FLD;
namespace Word97
{
struct CHP;
struct SEP;
}

/**
 * The TextHandler class is the main worker in this filter. It tells you
 * about sections, paragraphs, and characters inside the document. If
 * you want to have a fast filter, try to make those methods fast, they
 * will get called very often.
 */
class WV2_EXPORT TextHandler
{
public:
    virtual ~TextHandler();

    //////////////////////////////////////////////////////////////////////
    // Section related callbacks...
    /**
     * Denotes the start of a section.
     * The section properties are passed in the @p sep argument.
     */
    virtual void sectionStart(SharedPtr<const Word97::SEP> sep);
    virtual void sectionEnd();
    /**
     * A page break within a section.
     */
    virtual void pageBreak();
    /**
     * Emitted when we found headers or footers. The default implementation
     * simply invokes the functor. This function is called right after the
     * start of a new section.
     */
    virtual void headersFound(const HeaderFunctor &parseHeaders);

    //////////////////////////////////////////////////////////////////////
    // Paragraph related callbacks...
    /**
     * Denotes the start of a paragraph.
     * @param paragraph properties of the paragraph.
     * @param character properties of the paragraph provided for empty
     * paragraphs to set correct font-size, line-height, etc.
     */
    virtual void paragraphStart(SharedPtr<const ParagraphProperties> paragraphProperties, SharedPtr<const Word97::CHP> characterProperties);
    virtual void paragraphEnd();

    /**
     * runOfText is the main worker in this API. It provides a chunk of text with
     * the properties passed. A run of text inside a Word document may encompass
     * an entire document, but in our implementation we chop those runs of text into
     * smaller pieces.
     * A run of text will never cross paragraph boundaries, even if the paragraph
     * properties of the two or more containing paragraphs are the same. It would
     * probably be slightly faster to do that, but IMHO it's just not worth the
     * pain this would cause.
     * @param text The text of this run, UString holds it as UCS-2 host order string.
     * @param chp The character properties attached to this run of text
     */
    virtual void runOfText(const UString &text, SharedPtr<const Word97::CHP> chp);

    //////////////////////////////////////////////////////////////////////
    // Special characters...
    /**
     * The enum only contains characters which are "easy" to handle (as they don't
     * need any further information). All the other fSpec characters are/will be
     * handled via functors. The values match the ones found in the specification.
     *
     * The current list is just a first draft, I have no idea how many of them will
     * be moved out because they're more complex as expected.
     */
    enum SpecialCharacter {
        CurrentPageNumber = 0,
        LineNumber = 6,
        AbbreviatedDate = 10,
        TimeHMS = 11,
        CurrentSectionNumber = 12,
        AbbreviatedDayOfWeek = 14,
        DayOfWeek = 15,
        DayShort = 16,
        HourCurrentTime = 22,
        HourCurrentTimeTwoDigits = 23,
        MinuteCurrentTime = 24,
        MinuteCurrentTimeTwoDigits = 25,
        SecondsCurrentTime = 26,
        AMPMCurrentTime = 27,
        CurrentTimeHMSOld = 28,
        DateM = 29,
        DateShort = 30,
        MonthShort = 33,
        YearLong = 34,
        YearShort = 35,
        AbbreviatedMonth = 36,
        MonthLong = 37,
        CurrentTimeHMS = 38,
        DateLong = 39,
        Symbol = 40
    };

    /**
     * Very special characters (bad, bad name) are the ones which need additional
     * information from the file (i.e. the plain "put the current date there" isn't sufficient).
     */
    enum VerySpecialCharacter {
        Picture = 1,
        FootnoteAuto = 2,
        AnnotationRef = 5,
        DrawnObject = 8,
        FieldBegin = 19,
        FieldSeparator = 20,
        FieldEnd = 21,
        FieldEscapeChar = 92
    };

    /**
     * special characters that were defined in parser9x.h  (fSpec = 1) but that weren't used.
     */
    enum UnusedSpecialCharacter {
        FootnoteSeparator = 3,
        FootnodeContinuation = 4,
        HandAnnotationPic = 7,
        AbbrevDate = 10,
        MergeHelper = 41
    };

    /**
     * This method passes the simple cases of special characters we find. More complex ones
     * will get their own callback.
     */
    virtual void specialCharacter(SpecialCharacter character, SharedPtr<const Word97::CHP> chp);

    /**
     * The parser found a footnote. The passed functor will trigger the parsing of this
     * footnote/endnote, the default implementation just emits the passed character
     * (unless it's an auto-numbered footnote, we won't emit ASCII 2 by default) with
     * runOfText (that it doesn't get lost if someone doesn't override this method) and
     * invokes the functor.
     */
    virtual void footnoteFound(FootnoteData data,
                               UString characters,
                               SharedPtr<const Word97::SEP> sep,
                               SharedPtr<const Word97::CHP> chp,
                               const FootnoteFunctor &parseFootnote);

    /**
     * The parser found an annotation. The passed functor will trigger the parsing of this
     * annotation, the default implementation just emits the passed character with
     * runOfText (that it doesn't get lost if someone doesn't override this method) and
     * invokes the functor.
     */
    virtual void annotationFound(UString characters, SharedPtr<const Word97::CHP> chp, const AnnotationFunctor &parseAnnotation);

    /**
     * This callback will get triggered when parsing a auto-numbered footnote.
     * The passed CHP is the character formatting information provided for the
     * "number"
     */
    virtual void footnoteAutoNumber(SharedPtr<const Word97::CHP> chp);

    /**
     * This callback indicates the start of a field. Fields consist of two parts, separated
     * by a field separator.
     * @param fld Describes the type of the field for live fields. May be 0!
     * @param chp The character properties of the field start (ASCII 19)
     */
    virtual void fieldStart(const FLD *fld, SharedPtr<const Word97::CHP> chp);
    /**
     * This callback separates the two parts of a field. The first part contains control
     * codes and keywords, the second part is the field result.
     * @param fld Describes the type of the field for live fields. May be 0!
     * @param chp The character properties of the field separator (ASCII 20)
     */
    virtual void fieldSeparator(const FLD *fld, SharedPtr<const Word97::CHP> chp);
    /**
     * The end of the field result is indicated by this callback, fields may be nested up
     * to 20 levels, so take care :-)
     * @param fld Describes the type of the field for live fields. May be 0!
     * @param chp The character properties of the field end (ASCII 21)
     */
    virtual void fieldEnd(const FLD *fld, SharedPtr<const Word97::CHP> chp);

    /**
     * This method is called every time an inline or floating MS-ODRAW
     * object is found.  If the @param data is ZERO, then it's a floating
     * object.  Else it's an inline object.
     *
     * @param globalCP the CP to which the floating object is anchored
     * @param data the inline object data as defined by functordata
     */
    virtual void msodrawObjectFound(const unsigned int globalCP, const PictureData *data);

    /**
     * Denotes the start of a bookmark.
     */
    virtual void bookmarkStart(const BookmarkData &data);
    virtual void bookmarkEnd(const BookmarkData &data);

    // NOTE: those two belong into the TableHandler !!!!!

    /**
     * This method is called every time we find a table row. The default
     * implementation invokes the functor, which triggers the parsing
     * process for the given table row.
     * @param tap the table row properties. Those are the same as the
     * ones you'll get when invoking the functor, but by having them here,
     * you can do some preprocessing on the whole table first.
     */
    virtual void tableRowFound(const TableRowFunctor &tableRow, SharedPtr<const Word97::TAP> tap);

    /**
     * This method is called every time we find a table end. No default
     * implementation at the moment!
     */
    virtual void tableEndFound();
};

} // namespace wvWare

#endif // HANDLERS_H
