/* This file is part of the KDE project
   Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
	              Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   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 02110-1301, USA.
*/

#ifndef KFORMULADOCUMENT_H
#define KFORMULADOCUMENT_H

#include <tqdom.h>
#include <tqobject.h>
#include <tqptrlist.h>
#include <tqstring.h>
#include <tqstringlist.h>

#include <tdeaction.h>
#include <kcommand.h>
#include <tdeconfig.h>
#include <KoCommandHistory.h>
//#include "KoCommandHistory.h"
#include "kformuladefs.h"

KFORMULA_NAMESPACE_BEGIN

class Container;
class ContextStyle;
class SymbolAction;
class SymbolTable;
class DocumentWrapper;
class ElementCreationStrategy;


/**
 * small utility class representing a sortable (by x,y position) list
 * of formulas you can use sort() and inSort(item)
 **/
class FormulaList: public TQPtrList<Container>
{
protected:
    virtual int compareItems( TQPtrCollection::Item a, TQPtrCollection::Item b );
};


/**
 * A document that can contain a lot of formulas (container).
 *
 * The relationship between the document and its formulas is an
 * open one. The document sure owns the formulas and when it
 * vanishes the formulas will be destroyed, too. But the user
 * will most often work with those formulas directly and not
 * bother to ask the document. It's legal to directly create
 * or destroy a Container object.
 */
class KOFORMULA_EXPORT Document : public TQObject {
    Q_OBJECT
  

    friend class DocumentWrapper;
    friend class Container;

public:

    /**
     * Creates a formula document.
     */
    Document( TQObject *parent=0, const char *name=0,
              const TQStringList &args=TQStringList() );
    ~Document();

    /**
     * Factory method.
     */
    virtual Container* createFormula( int pos=-1, bool registerMe=true );

    /**
     * Registers a new formula to be part of this document. Each formula
     * must be part of exactly one document.
     */
    virtual void registerFormula( Container*, int pos=-1 );

    /**
     * Removes a formula from this document. The formula will stay
     * alive and might be registered again.
     */
    virtual void unregisterFormula( Container* );

    /**
     * Triggers the evaluation of the whole document. This obviously
     * required evaluation support.
     */
    virtual void evaluateFormulas() {}
    virtual void enableEvaluation( bool ) {}

    /**
     * Load a kformula DomDocument with all its formulas.
     * This must only be called on a virgin document.
     */
    bool loadXML( const TQDomDocument& doc );

    /**
     * Load a OASIS content.xml DomDocument
     * @since 1.4
     */
    bool loadOasis( const TQDomDocument& doc );
    
    /**
     * Load the document settings.
     */
    bool loadDocumentPart( TQDomElement node );

    /**
     * Save the document with all its formulae.
     */
    TQDomDocument saveXML();

    /**
     * Save the document settings.
     */
    TQDomElement saveDocumentPart( TQDomDocument& doc );


    /**
     * @returns the documents context style.
     */
    ContextStyle& getContextStyle( bool edit=false );

    /**
     * Change the zoom factor to @p z (e.g. 150 for 150%)
     * and/or change the resolution, given in DPI.
     * Uses the KoTextZoomHandler.
     */
    void setZoomAndResolution( int zoom, int dpiX, int dpiY );

    void newZoomAndResolution( bool updateViews, bool forPrint );

    /**
     * Sets the zoom by hand. This is to be used in <code>paintContent</code>.
     */
    void setZoomAndResolution( int zoom, double zoomX, double zoomY,
                               bool updateViews=false, bool forPrint=false );

    double getXResolution() const;
    double getYResolution() const;

    /**
     * Sets a new formula.
     */
    void activate(Container* formula);

    /**
     * Enables our action according to enabled.
     */
    void setEnabled( bool enabled );

    /**
     * @returns our undo stack so the formulas can use it.
     */
    KoCommandHistory* getHistory() const;

    /**
     * @returns the documents symbol table
     */
    const SymbolTable& getSymbolTable() const;

    /**
     * Gets called when the configuration changed.
     * (Maybe we can find a better solution.)
     */
    void updateConfig();

    /**
     * Return a kformula DomDocument.
     */
    static TQDomDocument createDomDocument();

    /**
     * Create a MathML Dom Document, deprecates KFO Dom Document for internal layout
     * TODO: Shouldn't this go to KoDocument ?
     */
    TQDomDocument createMathMLDomDocument();

    /**
     * Set formula creation strategy: old KFormula or MathML/ODF.
     * This tells which tags are valid during formula constructions
     *
     * @param strategy -- "Ordinary" for old Kformula, "Oasis" for MathML/ODF
     */
    void setCreationStrategy( TQString strategy );

public:

    /**
     * @returns an iterator for the collection of formulas.
     */
    TQPtrListIterator<Container> formulas();

    SymbolType leftBracketChar();
    SymbolType rightBracketChar();

    DocumentWrapper* wrapper() { return m_wrapper; }

protected:

    /**
     * @returns the internal position of this formula or -1 if it
     * doesn't belong to us.
     */
    int formulaPos( Container* formula );

    /**
     * @returns the formula at position pos.
     */
    Container* formulaAt( uint pos );

    /**
     * @returns the number of formulas in this document.
     */
    int formulaCount();

    /**
     * Sorts the list of formulas according to their screen positions.
     */
    void sortFormulaList();

private:

    /**
     * Return the formula with the given number or create a new one
     * if there is no such formula.
     */
    Container* newFormula( uint number );

    /**
     * @returns whether we have a formula that can get requests.
     */
    bool hasFormula();

    /**
     * recalc all formulae.
     */
    void recalc();

    void introduceWrapper( DocumentWrapper* wrapper, bool init );

    /**
     * The Wrapper we belong to.
     */
    DocumentWrapper* m_wrapper;

    /**
     * The active formula.
     */
    Container* m_formula;

    /**
     * The documents context style. This is the place where all
     * the user configurable informations are stored.
     */
    ContextStyle* m_contextStyle;

    /**
     * All formulae that belong to this document.
     */
    FormulaList formulae;

	/**
	 * Creation strategy to use in this document.
	 */
	ElementCreationStrategy* creationStrategy;
};



/**
 * A Wrapper that constracts the actions and must be given a real
 * document to work with.
 */
class KOFORMULA_EXPORT DocumentWrapper : public TQObject {
    Q_OBJECT
  

public:

    DocumentWrapper( TDEConfig* config,
                     TDEActionCollection* collection,
                     KoCommandHistory* history = 0 );
    ~DocumentWrapper();

    TDEConfig* config() { return m_config; }
    KoCommandHistory* history() { return m_history; }

    /**
     * @return the document we are using.
     */
    Document* document() const { return m_document; }

    /**
     * Enables our action according to enabled.
     */
    void setEnabled( bool enabled );

    /**
     * Inserts the document we are wrapping. This must be called once
     * before the wrapper can be used.
     */
    void document( Document* document, bool init = true );

    TDEAction* getAddNegThinSpaceAction()  { return m_addNegThinSpaceAction; }
    TDEAction* getAddThinSpaceAction()     { return m_addThinSpaceAction; }
    TDEAction* getAddMediumSpaceAction()   { return m_addMediumSpaceAction; }
    TDEAction* getAddThickSpaceAction()    { return m_addThickSpaceAction; }
    TDEAction* getAddQuadSpaceAction()     { return m_addQuadSpaceAction; }
    TDEAction* getAddBracketAction()       { return m_addBracketAction; }
    TDEAction* getAddSBracketAction()      { return m_addSBracketAction;}
    TDEAction* getAddCBracketAction()      { return m_addCBracketAction;}
    TDEAction* getAddAbsAction()           { return m_addAbsAction;}
    TDEAction* getAddFractionAction()      { return m_addFractionAction; }
    TDEAction* getAddRootAction()          { return m_addRootAction; }
    TDEAction* getAddSumAction()           { return m_addSumAction; }
    TDEAction* getAddProductAction()       { return m_addProductAction; }
    TDEAction* getAddIntegralAction()      { return m_addIntegralAction; }
    TDEAction* getAddMatrixAction()        { return m_addMatrixAction; }
    TDEAction* getAddOneByTwoMatrixAction(){ return m_addOneByTwoMatrixAction; }
    TDEAction* getAddUpperLeftAction()     { return m_addUpperLeftAction; }
    TDEAction* getAddLowerLeftAction()     { return m_addLowerLeftAction; }
    TDEAction* getAddUpperRightAction()    { return m_addUpperRightAction; }
    TDEAction* getAddLowerRightAction()    { return m_addLowerRightAction; }
    TDEAction* getAddGenericUpperAction()  { return m_addGenericUpperAction; }
    TDEAction* getAddGenericLowerAction()  { return m_addGenericLowerAction; }
    TDEAction* getAddOverlineAction()      { return m_addOverlineAction; }
    TDEAction* getAddUnderlineAction()     { return m_addUnderlineAction; }
    TDEAction* getAddMultilineAction()     { return m_addMultilineAction; }
    TDEAction* getRemoveEnclosingAction()  { return m_removeEnclosingAction; }
    TDEAction* getMakeGreekAction()        { return m_makeGreekAction; }
    TDEAction* getInsertSymbolAction()     { return m_insertSymbolAction; }

    TDEAction* getAppendColumnAction()     { return m_appendColumnAction; }
    TDEAction* getInsertColumnAction()     { return m_insertColumnAction; }
    TDEAction* getRemoveColumnAction()     { return m_removeColumnAction; }
    TDEAction* getAppendRowAction()        { return m_appendRowAction; }
    TDEAction* getInsertRowAction()        { return m_insertRowAction; }
    TDEAction* getRemoveRowAction()        { return m_removeRowAction; }

    void enableMatrixActions(bool);
    TDESelectAction* getLeftBracketAction()  { return m_leftBracket; }
    TDESelectAction* getRightBracketAction() { return m_rightBracket; }
    SymbolAction* getSymbolNamesAction()  { return m_symbolNamesAction; }
    TDEToggleAction* getSyntaxHighlightingAction()
        { return m_syntaxHighlightingAction; }
    TDEToggleAction* getFormatBoldAction()   { return m_formatBoldAction; }
    TDEToggleAction* getFormatItalicAction() { return m_formatItalicAction; }

    TDESelectAction* getFontFamilyAction() { return m_fontFamily; }
    TDESelectAction* getTokenElementAction() { return m_tokenElement; }

    SymbolType leftBracketChar() const  { return m_leftBracketChar; }
    SymbolType rightBracketChar() const { return m_rightBracketChar; }

    void updateConfig();

    KoCommandHistory* getHistory() const { return m_history; }

    void undo();
    void redo();

public slots:

    void paste();
    void copy();
    void cut();

    void addNegThinSpace();
    void addThinSpace();
    void addMediumSpace();
    void addThickSpace();
    void addQuadSpace();
    void addDefaultBracket();
    void addBracket( SymbolType left, SymbolType right );
    void addParenthesis();
    void addSquareBracket();
    void addCurlyBracket();
    void addLineBracket();
    void addFraction();
    void addRoot();
    void addIntegral();
    void addProduct();
    void addSum();
    void addMatrix( uint rows=0, uint columns=0 );
    void addOneByTwoMatrix();
    void addNameSequence();
    void addLowerLeftIndex();
    void addUpperLeftIndex();
    void addLowerRightIndex();
    void addUpperRightIndex();
    void addGenericLowerIndex();
    void addGenericUpperIndex();
    void addOverline();
    void addUnderline();
    void addMultiline();
    void removeEnclosing();
    void makeGreek();
    void insertSymbol();
    void insertSymbol( TQString name );

    void appendColumn();
    void insertColumn();
    void removeColumn();
    void appendRow();
    void insertRow();
    void removeRow();

    void toggleSyntaxHighlighting();
    void textBold();
    void textItalic();
    void delimiterLeft();
    void delimiterRight();
    void symbolNames();

    void fontFamily();
    void tokenElement();

private:

    void createActions( TDEActionCollection* collection );
    void initSymbolNamesAction();
    void setCommandStack( KoCommandHistory* history );

    bool hasFormula() { return m_document->hasFormula(); }
    Container* formula() { return m_document->m_formula; }

    Document* m_document;

    TDEAction* m_addNegThinSpaceAction;
    TDEAction* m_addThinSpaceAction;
    TDEAction* m_addMediumSpaceAction;
    TDEAction* m_addThickSpaceAction;
    TDEAction* m_addQuadSpaceAction;
    TDEAction* m_addBracketAction;
    TDEAction* m_addSBracketAction;
    TDEAction* m_addCBracketAction;
    TDEAction* m_addAbsAction;
    TDEAction* m_addFractionAction;
    TDEAction* m_addRootAction;
    TDEAction* m_addSumAction;
    TDEAction* m_addProductAction;
    TDEAction* m_addIntegralAction;
    TDEAction* m_addMatrixAction;
    TDEAction* m_addOneByTwoMatrixAction;
    TDEAction* m_addUpperLeftAction;
    TDEAction* m_addLowerLeftAction;
    TDEAction* m_addUpperRightAction;
    TDEAction* m_addLowerRightAction;
    TDEAction* m_addGenericUpperAction;
    TDEAction* m_addGenericLowerAction;
    TDEAction* m_addOverlineAction;
    TDEAction* m_addUnderlineAction;
    TDEAction* m_addMultilineAction;
    TDEAction* m_removeEnclosingAction;
    TDEAction* m_makeGreekAction;
    TDEAction* m_insertSymbolAction;

    TDEAction* m_appendColumnAction;
    TDEAction* m_insertColumnAction;
    TDEAction* m_removeColumnAction;
    TDEAction* m_appendRowAction;
    TDEAction* m_insertRowAction;
    TDEAction* m_removeRowAction;

    TDEToggleAction* m_syntaxHighlightingAction;
    TDEToggleAction* m_formatBoldAction;
    TDEToggleAction* m_formatItalicAction;

    TDESelectAction* m_leftBracket;
    TDESelectAction* m_rightBracket;
    SymbolAction* m_symbolNamesAction;

    TDESelectAction* m_fontFamily;
    TDESelectAction* m_tokenElement;

    SymbolType m_leftBracketChar;
    SymbolType m_rightBracketChar;
    TQString m_selectedName;

    TDEConfig* m_config;
    KoCommandHistory* m_history;

    /**
     * Tells whether we are responsible to remove our history.
     */
    bool m_ownHistory;

    bool m_hasActions;
};


KFORMULA_NAMESPACE_END

#endif // KFORMULADOCUMENT_H