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

#include <iostream>
#include <tqpainter.h>

#include <kdebug.h>

#include "contextstyle.h"
#include "formulacursor.h"
#include "formulaelement.h"
#include "kformulacontainer.h"
#include "kformuladocument.h"

KFORMULA_NAMESPACE_BEGIN

FormulaElement::FormulaElement(FormulaDocument* container)
    : document( container ), baseSize( 20 ), ownBaseSize( false )
{
}


void FormulaElement::setBaseSize( int size )
{
    if ( size > 0 ) {
        baseSize = size;
        ownBaseSize = true;
    }
    else {
        ownBaseSize = false;
    }
    document->baseSizeChanged( size, ownBaseSize );
}


/**
 * Returns the element the point is in.
 */
BasicElement* FormulaElement::goToPos( FormulaCursor* cursor, const LuPixelPoint& point )
{
    bool handled = false;
    BasicElement* element = inherited::goToPos(cursor, handled, point, LuPixelPoint());
    if (element == 0) {
        //if ((point.x() > getWidth()) || (point.y() > getHeight())) {
            cursor->setTo(this, countChildren());
            //}
            return this;
    }
    return element;
}

void FormulaElement::elementRemoval(BasicElement* child)
{
    document->elementRemoval(child);
}

void FormulaElement::changed()
{
    document->changed();
}

void FormulaElement::cursorHasMoved( FormulaCursor* cursor )
{
    document->cursorHasMoved( cursor );
}

void FormulaElement::moveOutLeft( FormulaCursor* cursor )
{
    document->moveOutLeft( cursor );
}

void FormulaElement::moveOutRight( FormulaCursor* cursor )
{
    document->moveOutRight( cursor );
}

void FormulaElement::moveOutBelow( FormulaCursor* cursor )
{
    document->moveOutBelow( cursor );
}

void FormulaElement::moveOutAbove( FormulaCursor* cursor )
{
    document->moveOutAbove( cursor );
}

void FormulaElement::tell( const TQString& msg )
{
    document->tell( msg );
}

void FormulaElement::removeFormula( FormulaCursor* cursor )
{
    document->removeFormula( cursor );
}

void FormulaElement::insertFormula( FormulaCursor* cursor )
{
    document->insertFormula( cursor );
}

void FormulaElement::calcSizes( const ContextStyle& context,
                                ContextStyle::TextStyle tstyle,
                                ContextStyle::IndexStyle istyle,
                                StyleAttributes& style )
{
    inherited::calcSizes( context, tstyle, istyle, style );
}


void FormulaElement::draw( TQPainter& painter, const LuPixelRect& r,
                           const ContextStyle& context,
                           ContextStyle::TextStyle tstyle,
                           ContextStyle::IndexStyle istyle,
                           StyleAttributes& style,
                           const LuPixelPoint& parentOrigin )
{
    inherited::draw( painter, r, context, tstyle, istyle, style, parentOrigin );
}


/**
 * Calculates the formulas sizes and positions.
 */
void FormulaElement::calcSizes( ContextStyle& context )
{
    //kdDebug( DEBUGID ) << "FormulaElement::calcSizes" << endl;
    if ( ownBaseSize ) {
        context.setSizeFactor( static_cast<double>( getBaseSize() )/context.baseSize() );
    }
    else {
        context.setSizeFactor( 1 );
    }
    StyleAttributes style;
    calcSizes( context, context.getBaseTextStyle(), ContextStyle::normal, style );
}

/**
 * Draws the whole thing.
 */
void FormulaElement::draw( TQPainter& painter, const LuPixelRect& r,
                           ContextStyle& context )
{
    //kdDebug( DEBUGID ) << "FormulaElement::draw" << endl;
    if ( ownBaseSize ) {
        context.setSizeFactor( static_cast<double>( getBaseSize() )/context.baseSize() );
    }
    else {
        context.setSizeFactor( 1 );
    }
    StyleAttributes style;
    draw( painter, r, context, context.getBaseTextStyle(),
          ContextStyle::normal, style, LuPixelPoint() );
}

KCommand* FormulaElement::buildCommand( Container* container, Request* request )
{
    switch ( *request ) {
    case req_compactExpression:
        return 0;
    default:
        break;
    }
    return inherited::buildCommand( container, request );
}

const SymbolTable& FormulaElement::getSymbolTable() const
{
    return document->getSymbolTable();
}


TQDomElement FormulaElement::emptyFormulaElement( TQDomDocument& doc )
{
    TQDomElement element = doc.createElement( getTagName() );
    /*
    element.setAttribute( "VERSION", "6" );
    if ( ownBaseSize ) {
        element.setAttribute( "BASESIZE", baseSize );
    }
    */
    return element;
}

KCommand* FormulaElement::input( Container* container, TQKeyEvent* event )
{
    TQChar ch = event->text().at( 0 );
    if ( !ch.isPrint() ) {
        int action = event->key();
        //int state = event->state();
        //MoveFlag flag = movementFlag(state);

	switch ( action ) {
        case TQt::Key_Return:
        case TQt::Key_Enter: {
            FormulaCursor* cursor = container->activeCursor();
            insertFormula( cursor );
            return 0;
        }
        }
    }
    return inherited::input( container, event );
}

/**
 * Appends our attributes to the dom element.
 */
void FormulaElement::writeDom(TQDomElement element)
{
    inherited::writeDom(element);
    element.setAttribute( "VERSION", "6" );
    if ( ownBaseSize ) {
        element.setAttribute( "BASESIZE", baseSize );
    }
}

/**
 * Reads our attributes from the element.
 * Returns false if it failed.
 */
bool FormulaElement::readAttributesFromDom(TQDomElement element)
{
    if (!inherited::readAttributesFromDom(element)) {
        return false;
    }
    int version = -1;
    TQString versionStr = element.attribute( "VERSION" );
    if ( !versionStr.isNull() ) {
        version = versionStr.toInt();
    }
    if ( version > -1 ) {
        // Version 6 added the MultilineElement (TabMarker)
        // Version 5 added under- and overlines
        if ( version < 4 ) {
            convertNames( element );
        }
    }
    TQString baseSizeStr = element.attribute( "BASESIZE" );
    if ( !baseSizeStr.isNull() ) {
        ownBaseSize = true;
        baseSize = baseSizeStr.toInt();
    }
    else {
        ownBaseSize = false;
    }
    return true;
}

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

void FormulaElement::convertNames( TQDomNode node )
{
    if ( node.isElement() && ( node.nodeName().upper() == "TEXT" ) ) {
        TQDomNamedNodeMap attr = node.attributes();
        TQDomAttr ch = attr.namedItem( "CHAR" ).toAttr();
        if ( ch.value() == "\\" ) {
            TQDomNode sequence = node.parentNode();
            TQDomDocument doc = sequence.ownerDocument();
            TQDomElement nameseq = doc.createElement( "NAMESEQUENCE" );
            sequence.replaceChild( nameseq, node );

            bool inName = true;
            while ( inName ) {
                inName = false;
                TQDomNode n = nameseq.nextSibling();
                if ( n.isElement() && ( n.nodeName().upper() == "TEXT" ) ) {
                    attr = n.attributes();
                    ch = attr.namedItem( "CHAR" ).toAttr();
                    if ( ch.value().at( 0 ).isLetter() ) {
                        nameseq.appendChild( sequence.removeChild( n ) );
                        inName = true;
                    }
                }
            }
        }
    }
    if ( node.hasChildNodes() ) {
        TQDomNode n = node.firstChild();
        while ( !n.isNull() ) {
            convertNames( n );
            n = n.nextSibling();
        }
    }
}

TQString FormulaElement::toLatex()
{
    return inherited::toLatex();   //Consider $$ sorround
}

void FormulaElement::writeMathML( TQDomDocument& doc, TQDomNode& parent, bool oasisFormat ) const
{
    TQDomElement de;
    if ( !oasisFormat ) {
        de = doc.createElementNS( "http://www.w3.org/1998/Math/MathML",
                                              "math" );
        parent.appendChild( de );
    }
    else {
        TQDomElement element = doc.createElement( "math:semantics" );
        de = doc.createElement( "math:mrow" );
        parent.appendChild( element );
        element.appendChild( de );
    }
    for ( uint i = 0; i < countChildren(); ++i ) {
        const BasicElement* e = getChild( i );
        e->writeMathML( doc, de, oasisFormat );
    }
}

KFORMULA_NAMESPACE_END