/* This file is part of the wvWare 2 project
   Copyright (C) 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 LISTS_H
#define LISTS_H

#include <vector>
#include <utility>
#include "global.h"
#include "ustring.h"
#include "sharedptr.h"
#include "wv2_export.h"
#include <QString>

namespace wvWare
{
    class STTBF;
    class OLEStreamReader;
    class StyleSheet;
    class ListLevel;
    class ListData;
    class ListFormatOverride;
    class ListFormatOverrideLVL;
    class ListInfoProvider;
    namespace Word97
    {
        struct FIB;
        struct PAP;
        struct CHP;
    }

    /**
     * Please refer to the documentation of the ListInfo::text method.
     */
    struct ListText
    {
        ListText();
        ~ListText();

        UString text;
        SharedPtr<Word97::CHP> chp;
    };


    /**
     * This class provides an abstraction for the list information in
     * Word6 and Word97 (they are totally different).
     *
     * I'm providing a slim API here and there would be some more information
     * inside the internal structures. Please speak up if you're missing
     * something, don't try to hack around this artificial limitation (Werner)
     */
    class ListInfo
    {
    public:
        enum ListType {BulletType, NumberType, PictureType, DefaultType};

        /**
         * @param current paragraph's PAP
         * @param paragraph mark's CHP
         * @param ListInfoProvider
         */
        ListInfo( Word97::PAP& pap, Word97::CHP& chp, ListInfoProvider& listInfoProvider );

        /**
         * The istd linked to the current list/level, istdNil (4095) if none (LSTF::rgistd)
         */
        U16 linkedIstd() const { return m_linkedIstd; }
        /**
         * Returns whether the list counter should be restarted in new sections. (LSTF::fRestartHdn)
         */
        bool restartingCounter() const { return m_restartingCounter; }

        /**
         * The list starts at this value at the current level (LVLF::iStartAt)
         */
        S32 startAt() const { return m_startAt.first; }
        /**
         * This flag tells you whether some list format override set a new start value.
         * If this method returns true you have to restart the counter (initialized
         * with the startAt value)
         */
        bool startAtOverridden() const { return m_startAt.second; }
        /**
         * Number format code (see ANLD) (LVLF::nfc)
         */
        U8 numberFormat() const { return m_numberFormat; }
        /**
         * Alignment of the list number (LVLF::jc)
         */
        U8 alignment() const { return m_alignment; }
        /**
         * (LVLF::fLegal)
         */
        bool isLegal() const { return m_isLegal; }
        /**
         * (LVLF::fNoRestart)
         */
        bool notRestarted() const { return m_notRestarted; }
        /**
         * (LVLF::fPrev)
         */
        bool prev() const { return m_prev; }
        /**
         * (LVLF::fPrevSpace)
         */
        bool prevSpace() const { return m_prevSpace; }
        /**
         * (LVLF::fWord6)
         */
        bool isWord6() const { return m_isWord6; }

        /**
         * The most important method, returning the text template and
         * the corresponding CHP.
         *
         * The returned string contains place holders for the real
         * list counter text.  The place holders are the values 0...8,
         * representing the corresponding list levels (pap->ilvl).
         * For example: (<0>, <1>,... represent the ASCII values 0,
         * 1,...): "<0>.<1>.<2>)"

         * The <0> should be replaced with the current counter value
         * of level 0, then we should display a '.', <1> should be the
         * counter value of level 1, and so forth.
         *
         * The CHP provides the character formatting properties for
         * the list label.  Information about the alignment and
         * optional spaces/tabs after the counter text is also
         * available here (alignment, followingChar,...)
         */
        const ListText& text() const { return m_text; }

        /**
         * The character following the list number (LVLF::ixchFollow)
         */
        U8 followingChar() const { return m_followingChar; }

        /**
         * In order to help users to detect when a new list starts we also
         * provide access to the (internal) unique ID of a list.
         * @return 0 if it hasn't been initialized.
         */
        S32 lsid() const { return m_lsid; }

        /**
         * The space after the label.
         */
        U16 space() const { return m_space; }

        /**
         * The indent before the label.
         */
        U16 indent() const { return m_indent; }

        /**
         * Debugging...
         */
        void dump() const;

	/**
	 * Set the name of the bullet picture.
	 */
        void setBulletPictureName(const QString& name ) { m_picName = name; };

        /**
         * @return bullet picture name.
         */
        QString bulletPictureName() const { return m_picName; };

        /**
         * @return whether the size of the picture changes automatically to
         * match the size of the text that follows the bullet
         */
        bool isBulletPictureAutoSize() const { return m_picAutoSize; };

	/**
	 * @return list type.
	 */
        ListType type() const { return m_type; };

    private:
        ListInfo& operator=( const ListInfo& rhs );

        U16 m_linkedIstd;
        bool m_restartingCounter;
        std::pair<S32, bool> m_startAt;
        U8 m_numberFormat;
        U8 m_alignment;
        bool m_isLegal;
        bool m_notRestarted;
        bool m_prev;
        bool m_prevSpace;
        bool m_isWord6;
        ListText m_text;
        U8 m_followingChar;
        S32 m_lsid;
        U16 m_space;
        U16 m_indent;
        QString m_picName;
        bool m_picAutoSize;
        ListType m_type;
    };


    /**
     * An internal class managing the list information read from the file.
     * Word versions before 8 don't have any explicit list information in
     * the table stream, it's just a part of the PAP (and it's way less
     * powerful). An object of this class will act as proxy for that
     * information in this case.
     */
    class ListInfoProvider
    {
        friend class ListInfo;
    public:
        /**
         * This constructor assumes that this is a list info provider
         * for a Word 6 document. It will just act as a proxy for the information
         * inside pap.anld. To make that work you have to set the ANLD structure
         * every time the PAP changes, using setWord6StylePAP()
         */
        explicit ListInfoProvider( const StyleSheet* styleSheet );
        /**
         * This constructor reads the structures from the table stream of a
         * Word 97 document.
         */
        ListInfoProvider( OLEStreamReader* tableStream, const Word97::FIB& fib, const StyleSheet* styleSheet );
        ~ListInfoProvider();

        /**
         * Returns true if the passed ilfo is in a valid range.
         */
        bool isValid( S16 ilfo, U8 nLvlAnm ) const;

    private:
        ListInfoProvider( const ListInfoProvider& rhs );
        ListInfoProvider& operator=( const ListInfoProvider& rhs );

        /**
         * @internal
         * This function tries to get the list information (if any) from the
         * given PAP. As the list info handling is completely different in
         * Word6 and in Word97 we have one additional level of indirection here
         * (to keep the user of the library from fighting multiple versions).
         * In case there's no list information for that paragraph it returns
         * false.
         *
         * Take care, these methods modify the passed PAP structure!!
         */
        bool setPAP( Word97::PAP* pap );

        void readListData( OLEStreamReader* tableStream, const U32 endOfLSTF );
        void readListFormatOverride( OLEStreamReader* tableStream );
        void readListNames( OLEStreamReader* tableStream );
        void eatLeading0xff( OLEStreamReader* tableStream );

        void processOverride( ListFormatOverride* lfo );
        void convertCompatANLD();
        ListData* findLST( S32 lsid );

        const ListLevel* formattingListLevel() const;
        std::pair<S32, bool> startAt();
        ListText text(const Word97::CHP& chp) const;

        std::vector<ListData*> m_listData;
        std::vector<ListFormatOverride*> m_listFormatOverride;
        STTBF* m_listNames;

        Word97::PAP* m_pap; // we don't own that one!
        const StyleSheet* const m_styleSheet; // needed to determine the CHP

        ListFormatOverrideLVL* m_currentLfoLVL;
        const ListData* m_currentLst;

        // We have to keep track of the version, as Word radically changed
        // it's way to handle lists from version 7 to 8.
        const WordVersion m_version;
    };

} // namespace wvWare

#endif // LISTS_H
