/* -*- Mode: C++ -*-
   KDChart - a multi-platform charting engine
   */

/****************************************************************************
 ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB.  All rights reserved.
 **
 ** This file is part of the KDChart library.
 **
 ** This file may be distributed and/or modified under the terms of the
 ** GNU General Public License version 2 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.
 **
 ** Licensees holding valid commercial KDChart licenses may use this file in
 ** accordance with the KDChart Commercial License Agreement provided with
 ** the Software.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** See http://www.klaralvdalens-datakonsult.se/?page=products for
 **   information about KDChart Commercial License Agreements.
 **
 ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
 ** licensing are not clear to you.
 **
 **********************************************************************/
#include <tqpainter.h>
#include <tqregion.h>
#include <tqpalette.h>
#include <tqpoint.h>
#include <tqsimplerichtext.h>
#include <tqpaintdevicemetrics.h>

#include <KDChartCustomBox.h>
#include <KDXMLTools.h>
#include <KDFrame.h>



KDChartCustomBox::~KDChartCustomBox()
{
    // Intentionally left blank for now.
}


void KDChartCustomBox::deepCopy( const KDChartCustomBox* source )
{
    if( !source || this == source )
        return;
    _rotation              = source->_rotation;
    _content.deepCopy( &source->_content);
    _fontSize              = source->_fontSize;
    _fontScaleGlobal       = source->_fontScaleGlobal;
    _deltaX                = source->_deltaX;
    _deltaY                = source->_deltaY;
    _width                 = source->_width;
    _height                = source->_height;
    _color                 = source->_color;
    _paper                 = source->_paper;
    _anchorArea            = source->_anchorArea;
    _anchorPos             = source->_anchorPos;
    _anchorAlign           = source->_anchorAlign;
    _dataRow               = source->_dataRow;
    _dataCol               = source->_dataCol;
    _data3rd               = source->_data3rd;
    _deltaAlign            = source->_deltaAlign;
    _deltaScaleGlobal      = source->_deltaScaleGlobal;
    _anchorBeingCalculated = source->_anchorBeingCalculated;
    _parentAxisArea        = source->_parentAxisArea;
}

const KDChartCustomBox* KDChartCustomBox::clone() const
{
    KDChartCustomBox* newBox = new KDChartCustomBox();
    newBox->deepCopy( this );
    return newBox;
}


float KDChartCustomBox::trueFontSize( double areaWidthP1000,
                                      double areaHeightP1000,
                                      int rectHeight ) const
{
    float size;
    if( 0 > _fontSize ) {
      if( _fontScaleGlobal ) {

        size = _fontSize * TQMIN(areaWidthP1000, areaHeightP1000) * -1.0;//(areaWidthP1000 + areaHeightP1000) / -2.0;

      }  else {

            // calculate the exact size:
	float targetLineSpacing = (_fontSize * rectHeight)/ -1000;
            size = targetLineSpacing;
            // step #1  -  try to make the right font size:
            TQFont font( content().font() );
            font.setPointSizeFloat( size );
            TQFontMetrics fm( font );
	    //tqDebug(TQString("\nsize                   : ")+TQString::number(size));
	    //tqDebug(TQString("(float)rectHeight      : ")+TQString::number((float)rectHeight));
	    //tqDebug(TQString("(float)fm.lineSpacing(): ")+TQString::number((float)fm.lineSpacing()));
            size *= targetLineSpacing / fm.lineSpacing();
	    //tqDebug(TQString("size                   : ")+TQString::number(size));
            // step #2  -  make sure the font size is not too big:
            font.setPointSizeFloat( size );
            TQFontMetrics fm2( font );
            size *= targetLineSpacing / fm2.lineSpacing();
	    //tqDebug(TQString("(float)rectHeight      : ")+TQString::number((float)rectHeight));
	    //tqDebug(TQString("(float)fm.lineSpacing(): ")+TQString::number((float)fm.lineSpacing()));
	    //tqDebug(TQString("size                   : ")+TQString::number(size));
        }
    }
    else {
//tqDebug(TQString("\n_fontsize: ")+TQString::number(_fontSize));
        if( _fontSize )
            size = _fontSize;
        else{
            size = content().font().pointSize();
            if( -1 == size )
                size = content().font().pixelSize();
            if( -1 == size )
                size = 10;
        }
    }
    return size;
}


int KDChartCustomBox::trueFontLineSpacing( double areaWidthP1000,
                                           double areaHeightP1000,
                                           int rectHeight ) const
{
    TQFont font( content().font() );
    font.setPointSizeFloat( trueFontSize( areaWidthP1000,areaHeightP1000, rectHeight ) );
    TQFontMetrics fm( font );
    return fm.lineSpacing();
}


void KDChartCustomBox::getTrueShift( double areaWidthP1000,
                                     double areaHeightP1000,
                                     int rectHeight,
                                     int& dX,
                                     int& dY ) const
{
    int x, y;
    if( _deltaScaleGlobal ){
        x = (0 > _deltaX) ? static_cast < int > ( -areaWidthP1000  * _deltaX ) : _deltaX;
        y = (0 > _deltaY) ? static_cast < int > ( -areaHeightP1000 * _deltaY ) : _deltaY;
    }else{
        int fontHeight = trueFontLineSpacing( areaWidthP1000, areaHeightP1000, rectHeight );
        //tqDebug("\nfontHeight %i",fontHeight);
        x = (0 > _deltaX) ? static_cast < int > ( fontHeight * _deltaX / -100.0 ) : _deltaX;
        y = (0 > _deltaY) ? static_cast < int > ( fontHeight * _deltaY / -100.0 ) : _deltaY;
        //tqDebug("y %i",y);
    }
    uint deltaAlign = (KDCHART_AlignAuto == _deltaAlign) ? _anchorAlign : _deltaAlign;
    if (      TQt::AlignLeft  == (TQt::AlignLeft  & deltaAlign) )
        dX = x;
    else if ( TQt::AlignRight == (TQt::AlignRight & deltaAlign) )
        dX = -x;
    else
        dX = 0; //  <--  so the _deltaX value becomes ineffective!

    if (      TQt::AlignTop    == (TQt::AlignTop    & deltaAlign) )
        dY = y;
    else if ( TQt::AlignBottom == (TQt::AlignBottom & deltaAlign) )
        dY = -y;
    else
        dY = 0; //  <--  so the _deltaY value becomes ineffective!
}

TQRect KDChartCustomBox::trueRect( TQPainter * /*painter*/, TQPoint /*anchor*/, double /*areaWidthP1000*/, double /*areaHeightP1000*/ ) const
{
    //temporary allow KDC_Presentation to compile
  tqDebug( "Sorry, not implemented yet: KDChartCustomBox::trueRect()" );
  return TQRect( 1, 1, 2, 2 );
}

//static TQPainter* pppainter=0;
//static int pdWidth =1280;
//static int pdHeight =1024;

TQRect KDChartCustomBox::trueRect( TQPoint anchor, double areaWidthP1000, double areaHeightP1000 ) const
{
   int w = (0 > _width ) ? static_cast < int > ( -areaWidthP1000  * _width  ) : _width;
   int h = (0 > _height) ? static_cast < int > ( -areaHeightP1000 * _height ) : _height;

   //tqDebug("w: %i    h: %i", w,h );

    if( _fontScaleGlobal && 0 == w && 0 == h ){
      //Now calculate the size of the box based upon the content!
        TQFont font( content().font() );
        if ( _fontSize ) {
            font.setPointSizeFloat(
                (0 > _fontSize)
            ? (_fontSize * TQMIN(areaWidthP1000, areaHeightP1000) * -1.0)//(areaWidthP1000 + areaHeightP1000) / -2.0
            : _fontSize );
	    //tqDebug("\n_fontSize * TQMIN(areaWidthP1000, areaHeightP1000)    %i * TQMIN(%f, %f) text: %s", _fontSize , areaWidthP1000, areaHeightP1000, content().text().latin1());
        }
        TQString txt(     content().text() );
        TQString txtTest( txt.stripWhiteSpace().lower() );
        if( !txtTest.startsWith("<qt>" ) )
            txt.prepend(        "<qt>" );
        if( !txtTest.endsWith(  "</qt>") )
            txt.append(         "</qt>");

        //tqDebug("\nw: %i    h: %i", w,h );
        TQSimpleRichText tmpContent( txt, font );
//        tmpContent.setWidth(pdWidth);
//        tmpContent.setHeight(pdHeight);
//        tmpContent.adjustSize();
//        if( pppainter ){
//            tmpContent.setWidth(pppainter, 2000);
//            tmpContent.adjustSize();
//        }
        w = tmpContent.widthUsed();
        h = tmpContent.height();
	//tqDebug("pdWidth: %i               w: %i  h %i",pdWidth,w,h);
        //tqDebug("w: %i    h: %i", w,h );
    }

    //tqDebug("\nw: %i    h: %i", w,h );
    int x,y;
    if (      TQt::AlignLeft  == (TQt::AlignLeft  & _anchorAlign) )
        x = 0;
    else if ( TQt::AlignRight == (TQt::AlignRight & _anchorAlign) )
        x = - w + 1;
    else
        x = - w / 2;

    if (      TQt::AlignTop    == (TQt::AlignTop    & _anchorAlign) )
        y = 0;
    else if ( TQt::AlignBottom == (TQt::AlignBottom & _anchorAlign) )
        y = - h + 1;
    else
        y = - h / 2;
    int dX,dY;
    getTrueShift( areaWidthP1000, areaHeightP1000, h,
                  dX, dY );
    //tqDebug("trueRect:  x %i  y %i    w %i  h %i text: %s", anchor.x()+x+dX, anchor.y()+y+dY, w,h, content().text().latin1());

    return TQRect( anchor.x()+x+dX, anchor.y()+y+dY, w, h );
}


int KDChartCustomBox::trueRectAlignX(const TQRect& rect) const
{
    int ret = rect.center().x();
    if (      TQt::AlignLeft  == (TQt::AlignLeft  & _anchorAlign) )
        ret -= rect.width();
    else if ( TQt::AlignRight == (TQt::AlignRight & _anchorAlign) )
        ret += rect.width();
    return ret;
}
int KDChartCustomBox::trueRectAlignY(const TQRect& rect) const
{
    int ret = rect.center().y();
    if (      TQt::AlignTop    == (TQt::AlignTop    & _anchorAlign) )
        ret -= rect.height();
    else if ( TQt::AlignBottom == (TQt::AlignBottom & _anchorAlign) )
        ret += rect.height();
    return ret;
}

void KDChartCustomBox::paint( TQPainter* painter,
                              TQPoint anchor,
                              double areaWidthP1000,
                              double areaHeightP1000,
                              const KDFrame* frame,
                              const TQRect&   frameRect,
                              const TQColor * color,
                              const TQBrush * paper ) const
{
    painter->save();
    int rotDX = 0;
    int rotDY = 0;
/*
//pppainter=painter;
const TQPaintDeviceMetrics metrics(painter->device());
pdWidth = metrics.width();
const int aWidthP1000  = metrics.width() /1000;
const int aHeightP1000 = metrics.height()/1000;
//pdHeight = metrics.height();
*/

    TQRect myRect( trueRect( anchor, areaWidthP1000, areaHeightP1000 ) );


    /*
TQPaintDeviceMetrics metrics(painter->device());
int pdWidth = metrics.width();
int dpiY = metrics.logicalDpiY();
int dpiX = metrics.logicalDpiX();
tqDebug("dpiY: %i    dpiX: %i",dpiY,dpiX);
tqDebug("pdWidth: %i    box myRect w: %i  h %i",pdWidth,myRect.width(),myRect.height());
    */
//myRect.setSize(myRect.size()*6);


    TQRect myFrameRect( frameRect );
    if ( myRect.isValid() ) {
//tqDebug("box myRect center:  x %i  y %i",myRect.center().x(),myRect.center().y());
        if( _rotation ){
            getTrueShift( areaWidthP1000, areaHeightP1000, myRect.height(),
                          rotDX, rotDY );
            myRect.moveBy( -rotDX, -rotDY );
            if( frame )
                myFrameRect.moveBy( -rotDX, -rotDY );
//tqDebug("\nrotDelta:  x %i  y %i",rotDX,rotDY);
//tqDebug("\nbox myRect center:  x %i  y %i",myRect.center().x(),myRect.center().y());
            myRect.moveCenter( TQPoint( anchor.x() - trueRectAlignX(myRect),
                                       anchor.y() - trueRectAlignY(myRect) ) );
            if( frame )
                myFrameRect.moveCenter( TQPoint( anchor.x() - trueRectAlignX(myFrameRect),
                                                anchor.y() - trueRectAlignY(myFrameRect) ) );
//tqDebug("box myRect center:  x %i  y %i",myRect.center().x(),myRect.center().y());
            painter->translate( anchor.x(), anchor.y() );
            painter->rotate( _rotation );
            painter->translate( rotDX, rotDY );
        }
        if( frame )
            frame->paint( painter, KDFrame::PaintAll, myFrameRect );
        if ( _fontSize ) {
	  TQFont font( content().font() );

          float trueSize = trueFontSize(areaWidthP1000,areaHeightP1000, myRect.height() );
          font.setPointSizeFloat( trueSize );
          //adjust the area height related to the font size
          myRect.setHeight( (int)(trueSize )+ (int)(trueSize*0.5));
	  const KDChartTextPiece tmpTextPiece( painter, content().text(), font );

	  tmpTextPiece.draw( painter, myRect.x(), myRect.y(), myRect,
			     color ? *color :  _color,
			     paper ?  paper : &_paper );
        }else{

	  content().draw( painter, myRect.x(), myRect.y(), myRect,
			  color ? *color :  _color,
			  paper ?  paper : &_paper );
        }
    }
    painter->restore();
}


void KDChartCustomBox::createCustomBoxNode( TQDomDocument& document,
        TQDomNode& parent,
        const TQString& elementName,
        const KDChartCustomBox* custombox )
{
    TQDomElement customBoxElement = document.createElement( elementName );
    parent.appendChild( customBoxElement );
    KDXML::createIntNode( document, customBoxElement, "Rotation", custombox->_rotation );
    KDXML::createStringNode( document, customBoxElement, "ContentText",
            custombox->_content.text() );
    KDXML::createFontNode( document, customBoxElement, "ContentFont",
            custombox->_content.font() );
    KDXML::createIntNode( document, customBoxElement, "FontSize", custombox->_fontSize );
    KDXML::createBoolNode( document, customBoxElement, "FontScaleGlobal",
            custombox->_fontScaleGlobal );
    KDXML::createIntNode( document, customBoxElement, "DeltaX", custombox->_deltaX );
    KDXML::createIntNode( document, customBoxElement, "DeltaY", custombox->_deltaY );
    KDXML::createIntNode( document, customBoxElement, "Width", custombox->_width );
    KDXML::createIntNode( document, customBoxElement, "Height", custombox->_height );
    KDXML::createColorNode( document, customBoxElement, "Color", custombox->_color );
    KDXML::createBrushNode( document, customBoxElement, "Paper", custombox->_paper );
    KDXML::createIntNode( document, customBoxElement, "AnchorArea",
            custombox->_anchorArea );
    KDXML::createStringNode( document, customBoxElement, "AnchorPos",
            KDChartEnums::positionFlagToString( custombox->_anchorPos ) );
    KDXML::createIntNode( document, customBoxElement, "AnchorAlign",
            custombox->_anchorAlign );
    KDXML::createIntNode( document, customBoxElement, "DataRow",
            custombox->_dataRow );
    KDXML::createIntNode( document, customBoxElement, "DataCol",
            custombox->_dataCol );
    KDXML::createIntNode( document, customBoxElement, "Data3rd",
            custombox->_data3rd );
    KDXML::createIntNode( document, customBoxElement, "DeltaAlign",
            custombox->_deltaAlign );
    KDXML::createBoolNode( document, customBoxElement, "DeltaScaleGlobal",
            custombox->_deltaScaleGlobal );
    KDXML::createIntNode( document,  customBoxElement,  "ParentAxisArea",
                          custombox->_parentAxisArea );
}


bool KDChartCustomBox::readCustomBoxNode( const TQDomElement& element,
        KDChartCustomBox& custombox )
{
    bool ok = true;
    TQString tempContentText;
    TQFont tempContentFont;
    int tempRotation = 0; // must be initialized: new parameter, not present in old versions of KDChart
    int tempDeltaAlign = KDCHART_AlignAuto; // must be initialized too: new parameter
    bool tempDeltaScaleGlobal = true;   // must be initialized too: new parameter
    int tempFontSize, tempDeltaX, tempDeltaY,
    tempWidth, tempHeight, tempAnchorArea, tempParentAxisArea,  tempAnchorAlign,
    tempDataRow, tempDataCol, tempData3rd;
    bool tempFontScaleGlobal;
    TQColor tempColor;
    TQBrush tempPaper;
    KDChartEnums::PositionFlag tempAnchorPos = KDChartEnums::PosTopLeft;
    TQDomNode node = element.firstChild();
    while( !node.isNull() ) {
        TQDomElement element = node.toElement();
        if( !element.isNull() ) { // was really an element
            TQString tagName = element.tagName();
            if( tagName == "Rotation" ) {
                ok = ok & KDXML::readIntNode( element, tempRotation );
            } else if( tagName == "ContentText" ) {
                ok = ok & KDXML::readStringNode( element, tempContentText );
            } else if( tagName == "ContentFont" ) {
                ok = ok & KDXML::readFontNode( element, tempContentFont );
            } else if( tagName == "FontSize" ) {
                ok = ok & KDXML::readIntNode( element, tempFontSize );
            } else if( tagName == "FontScaleGlobal" ) {
                ok = ok & KDXML::readBoolNode( element, tempFontScaleGlobal );
            } else if( tagName == "DeltaX" ) {
                ok = ok & KDXML::readIntNode( element, tempDeltaX );
            } else if( tagName == "DeltaY" ) {
                ok = ok & KDXML::readIntNode( element, tempDeltaY );
            } else if( tagName == "Width" ) {
                ok = ok & KDXML::readIntNode( element, tempWidth );
            } else if( tagName == "Height" ) {
                ok = ok & KDXML::readIntNode( element, tempHeight );
            } else if( tagName == "Color" ) {
                ok = ok & KDXML::readColorNode( element, tempColor );
            } else if( tagName == "Paper" ) {
                ok = ok & KDXML::readBrushNode( element, tempPaper );
            } else if( tagName == "AnchorArea" ) {
                ok = ok & KDXML::readIntNode( element, tempAnchorArea );
            } else if( tagName == "AnchorPos" ) {
                TQString value;
                ok = ok & KDXML::readStringNode( element, value );
                tempAnchorPos = KDChartEnums::stringToPositionFlag( value );
            } else if( tagName == "AnchorAlign" ) {
                ok = ok & KDXML::readIntNode( element, tempAnchorAlign );
            } else if( tagName == "DataRow" ) {
                ok = ok & KDXML::readIntNode( element, tempDataRow );
            } else if( tagName == "DataCol" ) {
                ok = ok & KDXML::readIntNode( element, tempDataCol );
            } else if( tagName == "Data3rd" ) {
                ok = ok & KDXML::readIntNode( element, tempData3rd );
            } else if( tagName == "DeltaAlign" ) {
                ok = ok & KDXML::readIntNode( element, tempDeltaAlign );
            } else if( tagName == "DeltaScaleGlobal" ) {
                ok = ok & KDXML::readBoolNode( element, tempDeltaScaleGlobal );
            } else if ( tagName == "ParentAxisArea" ) {
                 ok = ok & KDXML::readIntNode( element, tempParentAxisArea );
            } else {
                tqDebug( "Unknown tag in custom box" );
            }
        }
        node = node.nextSibling();
    }

    if( ok ) {
        const KDChartTextPiece piece( 0, tempContentText, tempContentFont );
        custombox._content.deepCopy( &piece );
        custombox._rotation = tempRotation;
        custombox._fontSize = tempFontSize;
        custombox._fontScaleGlobal = tempFontScaleGlobal;
        custombox._deltaX = tempDeltaX;
        custombox._deltaY = tempDeltaY;
        custombox._width = tempWidth;
        custombox._height = tempHeight;
        custombox._color = tempColor;
        custombox._paper = tempPaper;
        custombox._anchorArea = tempAnchorArea;
        custombox._anchorPos = tempAnchorPos;
        custombox._anchorAlign = tempAnchorAlign;
        custombox._dataRow = tempDataRow;
        custombox._dataCol = tempDataCol;
        custombox._data3rd = tempData3rd;
        custombox._deltaAlign       = tempDeltaAlign;
        custombox._deltaScaleGlobal = tempDeltaScaleGlobal;
        custombox._parentAxisArea = tempParentAxisArea;
    }

    return ok;
}

#include "KDChartCustomBox.moc"
