/* 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 SEQUENCEELEMENT_H
#define SEQUENCEELEMENT_H

#include <tqptrlist.h>
#include <tqstring.h>

#include "basicelement.h"

class TQKeyEvent;

KFORMULA_NAMESPACE_BEGIN

class SymbolTable;
class ElementCreationStrategy;

/**
 * The element that contains a number of children.
 * The children are aligned in one line.
 */
class SequenceElement : public BasicElement {
    SequenceElement& operator=( const SequenceElement& ) { return *this; }
public:

    SequenceElement(BasicElement* parent = 0);
    ~SequenceElement();

    SequenceElement( const SequenceElement& );

    virtual SequenceElement* clone() {
        return new SequenceElement( *this );
    }

    virtual bool accept( ElementVisitor* visitor );

    /**
     * @returns whether its prohibited to change the sequence with this cursor.
     */
    virtual bool readOnly( const FormulaCursor* ) const;

    /**
     * @returns true if the sequence contains only text.
     */
    virtual bool isTextOnly() const { return textSequence; }

    /**
     * Sets the cursor and returns the element the point is in.
     * The handled flag shows whether the cursor has been set.
     * This is needed because only the innermost matching element
     * is allowed to set the cursor.
     */
    virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
                                   const LuPixelPoint& point,
                                   const LuPixelPoint& parentOrigin );

    // drawing
    //
    // Drawing depends on a context which knows the required properties like
    // fonts, spaces and such.
    // It is essential to calculate elements size with the same context
    // before you draw.

    /**
     * Tells the sequence to have a smaller size than its parant.
     */
    void setSizeReduction(const ContextStyle& context);

    /**
     * @returns true if there is no visible element in the sequence.
     * Please note that there might be phantom elements.
     */
    bool isEmpty();

    /**
     * Calculates our width and height and
     * our children's parentPosition.
     */
    virtual void calcSizes( const ContextStyle& cstyle,
						    ContextStyle::TextStyle tstyle,
						    ContextStyle::IndexStyle istyle,
							StyleAttributes& style );

    /**
     * Draws the whole element including its children.
     * The `parentOrigin' is the point this element's parent starts.
     * We can use our parentPosition to get our own origin then.
     */
    virtual void draw( TQPainter& painter, const LuPixelRect& r,
                       const ContextStyle& context,
                       ContextStyle::TextStyle tstyle,
                       ContextStyle::IndexStyle istyle,
					   StyleAttributes& style,
                       const LuPixelPoint& parentOrigin );

    /**
     * Dispatch this FontCommand to all our TextElement children.
     */
    virtual void dispatchFontCommand( FontCommand* cmd );

    virtual void drawEmptyRect( TQPainter& painter, const ContextStyle& context,
								double factor, const LuPixelPoint& upperLeft );

    virtual void calcCursorSize( const ContextStyle& context,
                                 FormulaCursor* cursor, bool smallCursor );

    /**
     * If the cursor is inside a sequence it needs to be drawn.
     */
    virtual void drawCursor( TQPainter& painter, const ContextStyle& context,
							 StyleAttributes& style, FormulaCursor* cursor,
							 bool smallCursor, bool activeCursor );

    // navigation
    //
    // The elements are responsible to handle cursor movement themselves.
    // To do this they need to know the direction the cursor moves and
    // the element it comes from.
    //
    // The cursor might be in normal or in selection mode.

    /**
     * Enters this element while moving to the left starting inside
     * the element `from'. Searches for a cursor position inside
     * this element or to the left of it.
     */
    virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);

    /**
     * Enters this element while moving to the right starting inside
     * the element `from'. Searches for a cursor position inside
     * this element or to the right of it.
     */
    virtual void moveRight(FormulaCursor* cursor, BasicElement* from);

    /**
     * Moves to the beginning of this word or if we are there already
     * to the beginning of the previous.
     */
    virtual void moveWordLeft(FormulaCursor* cursor);

    /**
     * Moves to the end of this word or if we are there already
     * to the end of the next.
     */
    virtual void moveWordRight(FormulaCursor* cursor);

    /**
     * Enters this element while moving up starting inside
     * the element `from'. Searches for a cursor position inside
     * this element or above it.
     */
    virtual void moveUp(FormulaCursor* cursor, BasicElement* from);

    /**
     * Enters this element while moving down starting inside
     * the element `from'. Searches for a cursor position inside
     * this element or below it.
     */
    virtual void moveDown(FormulaCursor* cursor, BasicElement* from);

    /**
     * Moves the cursor to the first position in this sequence.
     * (That is before the first child.)
     */
    virtual void moveHome(FormulaCursor* cursor);

    /**
     * Moves the cursor to the last position in this sequence.
     * (That is behind the last child.)
     */
    virtual void moveEnd(FormulaCursor* cursor);

    /**
     * Sets the cursor inside this element to its start position.
     * For most elements that is the main child.
     */
    virtual void goInside(FormulaCursor* cursor);

    /**
     * Sets the cursor inside this element to its last position.
     * For most elements that is the main child.
     */
    virtual void goInsideLast(FormulaCursor* cursor);


    // children

    /**
     * Inserts all new children at the cursor position. Places the
     * cursor according to the direction. The inserted elements will
     * be selected.
     *
     * The list will be emptied but stays the property of the caller.
     */
    virtual void insert(FormulaCursor*, TQPtrList<BasicElement>&, Direction);

    /**
     * Removes all selected children and returns them. Places the
     * cursor to where the children have been.
     */
    virtual void remove(FormulaCursor*, TQPtrList<BasicElement>&, Direction);

    /**
     * Moves the cursor to a normal place where new elements
     * might be inserted.
     */
    virtual void normalize(FormulaCursor*, Direction);

    /**
     * Returns the child at the cursor.
     * Does not care about the selection.
     */
    virtual BasicElement* getChild(FormulaCursor*, Direction = beforeCursor);

    /**
     * Sets the cursor to select the child. The mark is placed before,
     * the position behind it.
     */
    virtual void selectChild(FormulaCursor* cursor, BasicElement* child);

    /**
     * Moves the cursor away from the given child. The cursor is
     * guaranteed to be inside this element.
     */
    virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child);

    /**
     * @returns the number of children we have.
     */
    uint countChildren() const { return children.count(); }

    /**
     * @returns whether the child has the given number.
     */
    bool isChildNumber( uint pos, BasicElement* child )
        { return children.at( pos ) == child; }

    /**
     * Selects all children. The cursor is put behind, the mark before them.
     */
    void selectAllChildren(FormulaCursor* cursor);

    bool onlyTextSelected( FormulaCursor* cursor );


    /**
     * This is called by the container to get a command depending on
     * the current cursor position (this is how the element gets chosen)
     * and the request.
     *
     * @returns the command that performs the requested action with
     * the containers active cursor.
     */
    virtual KCommand* buildCommand( Container*, Request* );


    /**
     * Parses the input. It's the container which does create
     * new elements because it owns the undo stack. But only the
     * sequence knows what chars are allowed.
     */
    virtual KCommand* input( Container* container, TQChar ch );
    virtual KCommand* input( Container* container, TQKeyEvent* event );

    /**
     * Parses the sequence and generates a new syntax tree.
     * Has to be called after each modification.
     */
    virtual void parse();

    /**
     * Stores the given childrens dom in the element.
     */
    void getChildrenDom( TQDomDocument& doc, TQDomElement elem, uint from, uint to);

    /**
     * Stores the given childrens MathML dom in the element.
     */
    void getChildrenMathMLDom( TQDomDocument& doc, TQDomNode& elem, uint from, uint to );

    /**
     * Builds elements from the given node and its siblings and
     * puts them into the list.
     * Returns false if an error occures.
     */
    bool buildChildrenFromDom(TQPtrList<BasicElement>& list, TQDomNode n);

    /**
     * @returns the latex representation of the element and
     * of the element's children
     */
    virtual TQString toLatex();

    virtual TQString formulaString();

    /**
     * @returns the child at position i.
     */
    BasicElement* getChild(uint i) { return children.at(i); }
    const BasicElement* getChild(uint i) const;

    int childPos( BasicElement* child ) { return children.find( child ); }
    int childPos( const BasicElement* child ) const;

    class ChildIterator {
    public:
        ChildIterator( SequenceElement* sequence, int pos=0 )
            : m_sequence( sequence ), m_pos( pos ) {}

        typedef BasicElement value_type;
        typedef BasicElement* pointer;
        typedef BasicElement& reference;

        // we simply expect the compared iterators to belong
        // to the same sequence.
        bool operator== ( const ChildIterator& it ) const
            { return /*m_sequence==it.m_sequence &&*/ m_pos==it.m_pos; }
        bool operator!= ( const ChildIterator& it ) const
            { return /*m_sequence!=it.m_sequence ||*/ m_pos!=it.m_pos; }

        const BasicElement& operator* () const
            { return *m_sequence->getChild( m_pos ); }
        BasicElement& operator* ()
            { return *m_sequence->getChild( m_pos ); }

        BasicElement* operator->() const
            { return m_sequence->getChild( m_pos ); }

        ChildIterator& operator++ ()
            { ++m_pos; return *this; }
        ChildIterator operator++ ( int )
            { ChildIterator it( *this ); ++m_pos; return it; }
        ChildIterator& operator-- ()
            { --m_pos; return *this; }
        ChildIterator operator-- ( int )
            { ChildIterator it( *this ); --m_pos; return it; }
        ChildIterator& operator+= ( int j )
            { m_pos+=j; return *this; }
        ChildIterator & operator-= ( int j )
            { m_pos-=j; return *this; }

    private:
        SequenceElement* m_sequence;
        int m_pos;
    };

    typedef ChildIterator iterator;

    iterator begin() { return ChildIterator( this, 0 ); }
    iterator end() { return ChildIterator( this, countChildren() ); }

    static void setCreationStrategy( ElementCreationStrategy* strategy );

	virtual void setStyle(StyleElement *style);
	virtual int buildChildrenFromMathMLDom(TQPtrList<BasicElement>& list, TQDomNode n);
	virtual int readContentFromMathMLDom(TQDomNode& node);
	int buildMathMLChild( TQDomNode node );

protected:

    //Save/load support

    /**
     * Returns the tag name of this element type.
     */
    virtual TQString getTagName() const { return "SEQUENCE"; }

    /**
     * Appends our attributes to the dom element.
     */
    virtual void writeDom(TQDomElement element);

    virtual TQString getElementName() const { return "mrow"; }
    virtual void writeMathMLContent( TQDomDocument& doc, 
                                     TQDomElement& element,
                                     bool oasisFormat ) const;
    /**
     * Reads our attributes from the element.
     * Returns false if it failed.
     */
    virtual bool readAttributesFromDom(TQDomElement element);

    /**
     * Reads our content from the node. Sets the node to the next node
     * that needs to be read.
     * Returns false if it failed.
     */
    virtual bool readContentFromDom(TQDomNode& node);

    /**
     * Sets the childrens' positions after their size has been
     * calculated.
     *
     * @see #calcSizes
     */
    virtual void setChildrenPositions();

    /**
     * Creates a new element with the given type.
     *
     * @param type the desired type of the element
     */
    virtual BasicElement* createElement(TQString type, const TQDomElement &element);

    /**
     * @returns the position where the child starts.
     *
     * @param context the context the child is in
     * @param child the child's number
     */
    luPixel getChildPosition( const ContextStyle& context, uint child );

    /**
     * @returns whether the child is the first element of its token.
     */
    virtual bool isFirstOfToken( BasicElement* child );

    /**
     * Insert a new child in the sequence
     * 
     * @returns true if succesful, i.e. if index is in range, otherwise returns
     * false. The valid range is 0 to count(). The child is appended if index == count().
     *
     * @param index position in the sequence to insert the child
     * @param child the child to insert in the sequence
     */
    bool insert( uint index, BasicElement *child );

    static ElementCreationStrategy* getCreationStrategy() { return creationStrategy; }

    /**
     * Space around sequence
     */
    virtual luPt getSpaceBefore( const ContextStyle&, ContextStyle::TextStyle, double ) { return 0; }
    virtual luPt getSpaceAfter( const ContextStyle&, ContextStyle::TextStyle, double ) { return 0; }

    static ElementCreationStrategy* creationStrategy;
    
private:

    /**
     * Removes the children at pos and appends it to the list.
     */
    void removeChild(TQPtrList<BasicElement>& removedChildren, int pos);


    /**
     * Our children. Be sure to notify the rootElement before
     * you remove any.
     */
    TQPtrList<BasicElement> children;

    /**
     * the syntax tree of the sequence
     */
    ElementType* parseTree;

    /**
     * true if the sequence contains only text
     */
    bool textSequence;

    bool singlePipe; //The key '|' produces one '|' not '| |', '||' produces '| |'

	StyleElement *style;
};


/**
 * The sequence thats a name. Actually the purpose
 * is to be able to insert any element by keyboard.
 */
class NameSequence : public SequenceElement {
    typedef SequenceElement inherited;
public:

    NameSequence( BasicElement* parent = 0 );

    virtual NameSequence* clone() {
        return new NameSequence( *this );
    }

    virtual bool accept( ElementVisitor* visitor );

    /**
     * @returns true if the sequence contains only text.
     */
    //virtual bool isTextOnly() const { return true; }

    /**
     * @returns the character that represents this element. Used for
     * parsing a sequence.
     * This is guaranteed to be TQChar::null for all non-text elements.
     */
    virtual TQChar getCharacter() const { return '\\'; }

    /**
     * @returns the type of this element. Used for
     * parsing a sequence.
     */
    virtual TokenType getTokenType() const { return NAME; }

    /**
     * We are our own main child. This causes interessting effects.
     */
    virtual SequenceElement* getMainChild() { return this; }

    virtual void calcCursorSize( const ContextStyle& context,
                                 FormulaCursor* cursor, bool smallCursor );

    /**
     * If the cursor is inside a sequence it needs to be drawn.
     */
    virtual void drawCursor( TQPainter& painter, const ContextStyle& context,
							 StyleAttributes& style, FormulaCursor* cursor, 
							 bool smallCursor, bool activeCursor );

    /**
     * Moves to the beginning of this word or if we are there already
     * to the beginning of the previous.
     */
    virtual void moveWordLeft(FormulaCursor* cursor);

    /**
     * Moves to the end of this word or if we are there already
     * to the end of the next.
     */
    virtual void moveWordRight(FormulaCursor* cursor);

    /**
     * This is called by the container to get a command depending on
     * the current cursor position (this is how the element gets chosen)
     * and the request.
     *
     * @returns the command that performs the requested action with
     * the containers active cursor.
     */
    virtual KCommand* buildCommand( Container*, Request* );


    /**
     * Parses the input. It's the container which does create
     * new elements because it owns the undo stack. But only the
     * sequence knows what chars are allowed.
     */
    virtual KCommand* input( Container* container, TQChar ch );

    /**
     * Sets a new type. This is done during parsing.
     */
    virtual void setElementType( ElementType* t );

    /**
     * @returns the element this sequence is to be replaced with.
     */
    BasicElement* replaceElement( const SymbolTable& table );

    /**
     * Tests whether the selected elements can be inserted in a
     * name sequence.
     */
    static bool isValidSelection( FormulaCursor* cursor );

protected:

    /**
     * Returns the tag name of this element type.
     */
    virtual TQString getTagName() const { return "NAMESEQUENCE"; }

    virtual TQString getElementName() const { return "mi"; }
    /**
     * Creates a new element with the given type.
     *
     * @param type the desired type of the element
     */
    virtual BasicElement* createElement( TQString type );

    /**
     * Parses the sequence and generates a new syntax tree.
     * Has to be called after each modification.
     */
    //virtual void parse();

    /**
     * @returns whether the child is the first element of its token.
     * This can never happen here. Our children reuse our own
     * element type.
     */
    virtual bool isFirstOfToken( BasicElement* ) { return false; }

private:

    KCommand* compactExpressionCmd( Container* container );

    TQString buildName();
};

KFORMULA_NAMESPACE_END

#endif // SEQUENCEELEMENT_H
