/***************************************************************************
 *   Copyright (C) 2004 by Hans Oischinger                                 *
 *   hans.oischinger@kdemail.net                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.             *
 ***************************************************************************/
#include "vdrawelements.h"

// Core
#include "core/direktorinstance.h"
#include "core/timeserver.h"

// ELements
#include "elements/vectorelement.h"
#include "elements/documentelement.h"
#include "elements/animatedlengthattr.h"
#include "elements/lengthattribute.h"
#include "elements/animatedcolorattr.h"
#include "elements/colorattribute.h"
#include "elements/fillattribute.h"
#include "elements/strokeattribute.h"
#include "elements/vectorpath.h"
#include "elements/groupelement.h"
#include "elements/useelement.h"
#include "elements/matrix.h"
#include "elements/elementselection.h"
#include "elements/elementtreeiterator.h"
#include "elements/animatednumber.h"
#include "elements/number.h"
#include "elements/lineargradient.h"
#include "elements/radialgradient.h"
#include "elements/urireference.h"
#include "elements/stopelement.h"
#include "elements/transformlist.h"
#include "elements/animatedtransformlist.h"
#include "elements/enumeration.h"
#include "elements/animatedenum.h"

// KCanvas
#include <kcanvas/KCanvas.h>
#include <kcanvas/KCanvasPath.h>
#include <kcanvas/KCanvasItem.h>
#include <kcanvas/KCanvasMatrix.h>
#include <kcanvas/KCanvasCreator.h>
#include <kcanvas/KCanvasRegistry.h>
#include <kcanvas/device/KRenderingDevice.h>
#include <kcanvas/device/KRenderingStyle.h>
#include <kcanvas/device/KRenderingPaintServerSolid.h>
#include <kcanvas/device/KRenderingPaintServerGradient.h>
#include <kcanvas/device/KRenderingFillPainter.h>
#include <kcanvas/device/KRenderingStrokePainter.h>

// Visitors
#include "vconsolidatetransform.h"

// Qt
#include <qcolor.h>

// KDE
#include <kdebug.h>


VDrawElements::VDrawElements( KCanvas *canvas, KRenderingDevice *device,
                              bool removeItemsOnly, bool setZindex, Transform* globalTrans )
    : Visitor(),
    m_canvas(canvas),
    m_device(device),
    m_removeItemsOnly(removeItemsOnly),
    m_setZindex(setZindex),
    m_globalTransform(globalTrans),
    m_zindex(0),
    m_normalizePaintServers(false),
    m_referencedContext(0)
{}


VDrawElements::~VDrawElements()
{}


bool VDrawElements::visit( DocumentElement& element )
{
  ++m_zindex;

  if ( element.getState() == Element::deleted )
    return false;

  //   KCanvasItem *canvasItem = element.context();
  //
  //   if ( element.getState() == Element::hidden || element.getState() == Element::hidden_locked )
  //     return false;
  //
  //   // Remove the old canvas if m_removeItemsOnly is set
  //   if ( m_removeItemsOnly || element.getState() == Element::deleted  )
  //   {
  //     m_canvas->removeItem(canvasItem);
  //     canvasItem = 0;
  //     element.setContext(canvasItem);
  //     if (m_removeItemsOnly)
  //       return true;
  //   }
  //
  //   if (!canvasItem)
  //   {
  //     KRenderingStyle *renderStyle = new KRenderingStyle();
  //     KRenderingPaintServer *fillPainter =
  //       m_device->createPaintServer(KCPaintServerType(PS_SOLID));
  //     KRenderingPaintServerSolid *fillPainterSolid = static_cast<KRenderingPaintServerSolid *>(fillPainter);
  //     fillPainterSolid->setColor(QColor("white"));
  //     KRenderingPaintServer *strokePainter = m_device->createPaintServer(KCPaintServerType(PS_SOLID));
  //     KRenderingPaintServerSolid *strokePainterSolid = static_cast<KRenderingPaintServerSolid *>(strokePainter);
  //     strokePainterSolid->setColor(QColor("black"));
  //     renderStyle->fillPainter()->setPaintServer(fillPainter);
  //     renderStyle->strokePainter()->setPaintServer(strokePainter);
  //     renderStyle->strokePainter()->setStrokeWidth(1.0);
  //
  //     // Documents with 0 width and height are invalid
  //     if (element.width().animVal().value()!=0 && element.height().animVal().value()!=0)
  //     {
  //       KCPathDataList itemPathData;
  //       itemPathData = KCanvasCreator::self()->createRectangle( 0, 0,
  //                      element.width().animVal().value(), element.height().animVal().value());
  //       canvasItem = KCanvasCreator::self()->createPathItem(m_canvas, renderStyle, itemPathData);
  //
  //       element.setContext(canvasItem);
  //       m_canvas->insertItem(canvasItem, m_zindex);
  //     }
  //   }
  //   else
  //   {
  //     // NOP?
  //   }
  //
  //   //m_canvas->setRootClippingRect( element.bbox() );
  //
  //   // Update all dirty elements
  //   element.setDirty(false);

  return true;
}

bool VDrawElements::visit( VectorElement& element )
{
  ++m_zindex;
  KCanvasItem *canvasItem = element.context();

  // kdDebug() << "VDrawElements::visit( VectorElement& element ) - " << element.readAbleType() << endl;
  if ( checkHideShow( element, canvasItem ) )
    return true;

  // Remove the old canvas if m_removeItemsOnly is set
  if ( m_removeItemsOnly || element.getState() == Element::deleted )
  {
    if ( canvasItem )
    {
      // kdDebug() << "VDrawElements::visit( VectorElement& element ) - Detaching CanvasItem" << endl;
      // Remove item from the canvas
      m_canvas->removeItem(canvasItem);
    }
    canvasItem = 0;
    element.setContext(0);
    return true;
  }

  // Create or update the CanvasItem
  bool transformChanged = true; // TODO: Always true for now... until i add new dirty flags
  bool styleChanged = element.isContextDirty();
  bool pathChanged = element.isContextDirty();

  KAbstractRenderingStyle *renderStyle = 0;
  KCPathDataList pathData;
  if (!canvasItem)
  {
    transformChanged = true;
    styleChanged = true;
    pathChanged = false;
    renderStyle = new KRenderingStyle();
    pathData = createKCPathDataList( element );
  }
  else
  {
    renderStyle = canvasItem->style();
  }

  // update RenderStyle
  if ( styleChanged )
  {
    updateRenderStyle( renderStyle, element );
  }

  // Create a CanvasItem if not exists
  if (!canvasItem)
  {
    // kdDebug() << "VDrawElements::visit() -   Creating new CanvasItem" << endl;
    canvasItem = KCanvasCreator::self()->createPathItem( m_canvas, renderStyle, pathData );

    if (!canvasItem)
    {
      // kdWarning() << "VDrawElements::visit() -   CanvasItem creation (metaType " << element.vectorPath().shapeMetaType() << ") failed!" << endl;
      return false;
    }

    // Set references to ContainerItem
    GroupElement* parentGroup = 0;
    parentGroup = ::qt_cast<GroupElement*>(element.getParent());
    if (parentGroup && parentGroup->context() )
    {
      parentGroup->context()->appendItem( canvasItem );
      canvasItem->setParent( parentGroup->context() );
    }

    element.setContext(canvasItem);
    m_canvas->insertItem(canvasItem, m_zindex);
  }
  else
  {
    // Invalidate old KCanvasItem
    if ( transformChanged || styleChanged || pathChanged )
    {
      canvasItem->invalidate();
    }

    // update Path
    if ( pathChanged )
    {
      // kdDebug() << "VDrawElements::visit() -   Updating CanvasPath" << endl;
      KCPathDataList newpathData = createKCPathDataList( element );
      canvasItem->changePath(
        KCanvasCreator::self()->createCanvasPathData( m_canvas, newpathData ) );
    }
  }

  // Set the object matrix
  if ( transformChanged )
  {
    //     Matrix *ctm = 0;
    //     Transform* consolidatedTrans = new Transform();
    //     element.transformList().animVal().consolidate( *consolidatedTrans );
    //     ctm = consolidatedTrans->matrix();
    //     /*
    //         Matrix *ctm = 0;
    //         ctm = VConsolidateTransform::calcCTM(element);*/
    //     if (m_globalTransform)
    //       ctm->multiply(m_globalTransform->matrix());
    //     renderStyle->setObjectMatrix(*new KCanvasMatrix(ctm->qmatrix())); // FIXME: Memory leak?
    //     //delete ctm;
    //     delete consolidatedTrans;

    Matrix *ctm = 0;
    ctm = VConsolidateTransform::calcCTM(element);
    if (m_globalTransform)
      ctm->postMultiply(*m_globalTransform->matrix());
    KCanvasMatrix kcCtm(ctm->qmatrix());
    if (renderStyle->objectMatrix() != kcCtm )
      renderStyle->setObjectMatrix(*new KCanvasMatrix(ctm->qmatrix())); // FIXME: Memory leak?
    delete ctm;
  }

  // set ZIndex
  if (m_setZindex)
    m_canvas->insertItem(canvasItem, m_zindex);

  // Invalidate updated/new KCanvasItem
  if ( transformChanged || styleChanged || pathChanged )
  {
    canvasItem->invalidate();
  }

  // Update all dirty elements
  element.setDirty(false);
  return true;
}

bool VDrawElements::visit( GroupElement& element )
{
  ++m_zindex;
  KCanvasContainer *canvasItem = element.context();

  // kdDebug() << "VDrawElements::visit( VectorElement& element ) - " << element.readAbleType() << endl;
  if ( checkHideShow( element, canvasItem ) )
    return true;

  // Remove the old canvas if m_removeItemsOnly is set
  if ( m_removeItemsOnly || element.getState() == Element::deleted )
  {
    if ( canvasItem )
    {
      // kdDebug() << "VDrawElements::visit( VectorElement& element ) - Detaching CanvasItem" << endl;
      m_canvas->removeItem(canvasItem);
    }
    canvasItem = 0;
    element.setContext(0);
    return true;
  }

  // Create or update the CanvasItem
  bool transformChanged = true; // TODO: Always true for now... until i add new dirty flags
  bool styleChanged = element.isContextDirty();

  KAbstractRenderingStyle *renderStyle = 0;
  if (!canvasItem)
  {
    transformChanged = true;
    styleChanged = true;
    renderStyle = new KRenderingStyle();
  }
  else
  {
    renderStyle = canvasItem->style();
  }

  // update RenderStyle
  if ( styleChanged )
  {
    updateRenderStyle( renderStyle, element );
  }

  // Create a CanvasItem if not exists
  if (!canvasItem)
  {
    // kdDebug() << "VDrawElements::visit() - Creating new CanvasItem" << endl;
    canvasItem = KCanvasCreator::self()->createContainer( m_canvas, renderStyle );

    if (!canvasItem)
    {
      kdWarning() << "VDrawElements::visit(GroupElement) - CanvasItem creation failed!" << endl;
      return false;
    }

    element.setContext(canvasItem);
    m_canvas->insertItem(canvasItem, m_zindex);
  }

  // Set the object matrix
  if ( transformChanged )
  {
    Matrix *ctm = 0;
    ctm = VConsolidateTransform::calcCTM(element);
    if (m_globalTransform)
      ctm->multiply(*m_globalTransform->matrix());
    if (renderStyle->objectMatrix() != *new KCanvasMatrix(ctm->qmatrix()) )
      renderStyle->setObjectMatrix(*new KCanvasMatrix(ctm->qmatrix())); // FIXME: Memory leak?
    delete ctm;
  }

  // set ZIndex
  if (m_setZindex)
    m_canvas->insertItem(canvasItem, m_zindex);

  // Invalidate
  if ( transformChanged || styleChanged )
  {
    canvasItem->invalidate();
  }

  // Update all dirty elements
  element.setDirty(false);
  return true;
}

bool VDrawElements::visit( UseElement& element )
{
  // kdDebug() << "VDrawElements::visit( UseElement& ) - drawing refID: " << element.refId() << endl;

  //   m_referencedContext = &element;
  //   ElementTreeIterator itr( &element.refClone() );
  //   for( ; itr.current(); itr.next() )
  //   {
  // //     kdDebug() << "VDrawElements::visit( UseElement& ) - iterating " << itr.current()->className() << endl;
  //     itr.current()->accept( *this );
  //   }
  //
  //   m_referencedContext = 0;
  return true;
}

bool VDrawElements::visit( ElementSelection& element )
{
  if (m_removeItemsOnly || element.getState() == Element::deleted )  // Never remove selection element
    return true;

  if ( checkHideShow( element ) )
    return true;

  bool pathChanged = element.isContextDirty();

  KCanvasItem *canvasItem = element.context(ElementSelection::node_body);
  if (!canvasItem)
  {
    KRenderingStyle *renderStyle = new KRenderingStyle();
    KRenderingPaintServer *strokePainter = m_device->createPaintServer(KCPaintServerType(PS_SOLID));
    KRenderingPaintServerSolid *strokePainterSolid = static_cast<KRenderingPaintServerSolid *>(strokePainter);
    strokePainterSolid->setColor(QColor("blue"));
    renderStyle->strokePainter()->setPaintServer(strokePainter);
    renderStyle->strokePainter()->setStrokeWidth(0.5);

    KCPathDataList itemPathData = KCanvasCreator::self()->createRectangle(
                                    element.bbox().x(), element.bbox().y(),
                                    element.bbox().width(), element.bbox().height());
    canvasItem = KCanvasCreator::self()->createPathItem(m_canvas, renderStyle, itemPathData);

    element.setContext(ElementSelection::node_body, canvasItem);
    m_canvas->insertItem(canvasItem, 500000);
  }
  else
  {
    // update Path
    if ( pathChanged )
    {
      canvasItem->invalidate();
      KCPathDataList newpathData = KCanvasCreator::self()->createRectangle(
                                     element.bbox().x(), element.bbox().y(),
                                     element.bbox().width(), element.bbox().height() );
      canvasItem->changePath(
        KCanvasCreator::self()->createCanvasPathData( m_canvas, newpathData ) );
      canvasItem->invalidate();
    }
  }

  for (unsigned int i = ElementSelection::node_lt; i <= ElementSelection::node_rb; ++i)
    createSelectionHandles( i, element );

  createPathNodeHandles( element );

  // Update all dirty elements
  element.setDirty(false);

  return true;
}

bool VDrawElements::visit( LinearGradient& element )
{
  if ( element.getState() == Element::deleted )
    return false;

  // Create a new Paintserver if none exists
  KRenderingPaintServer *fillPainter = 0;
  if ( !element.context() )
  {
    fillPainter = m_device->createPaintServer(KCPaintServerType(PS_LINEAR_GRADIENT));
    element.setContext( fillPainter );
    m_canvas->registry()->addPaintServerById( element.id(), element.context() );
    element.setDirty();
  }

  // Update paintserver
  if ( element.isContextDirty() )
    updatePaintServer( element );

  return true;
}

bool VDrawElements::visit( RadialGradient& element )
{
  if ( element.getState() == Element::deleted )
    return false;

  // Create a new Paintserver if none exists
  KRenderingPaintServer *fillPainter = 0;
  if ( !element.context() )
  {
    fillPainter = m_device->createPaintServer(KCPaintServerType(PS_RADIAL_GRADIENT));
    element.setContext( fillPainter );
    m_canvas->registry()->addPaintServerById( element.id(), element.context() );
    element.setDirty();
  }

  // Update paintserver
  if ( element.isContextDirty() )
    updatePaintServer( element );

  return true;
}

void VDrawElements::updateRenderStyle( KAbstractRenderingStyle *renderStyle, Stylable& element )
{
  KRenderingPaintServer *fillPainter = 0;
  unsigned int fillType = element.fill().fillType();

  // Handle the different fill Types
  if ( fillType == FillAttribute::FILL_SOLID )
  {
    fillPainter = m_device->createPaintServer(KCPaintServerType(PS_SOLID));
    KRenderingPaintServerSolid *fillPainterSolid = static_cast<KRenderingPaintServerSolid *>(fillPainter);

    fillPainterSolid->setColor( element.fill().color().animVal().qColor() );
    renderStyle->fillPainter()->setOpacity( element.fill().fillOpacity().animVal().value() );
  }
  else if ( fillType == FillAttribute::FILL_NONE )
  {
    // fillPainter = m_device->createPaintServer(KCPaintServerType(PS_SOLID));
    // KRenderingPaintServerSolid *fillPainterSolid = static_cast<KRenderingPaintServerSolid *>(fillPainter);
    // fillPainterSolid->setColor( QColor(qRgba(0, 0, 0, 0)) );
  }
  else if ( fillType == FillAttribute::FILL_REF )
  {
    fillPainter = m_canvas->registry()->getPaintServerById(
                    element.fill().ref().getLocalURI() );
    //     if ( element.fill().ref().getRefElement()->inherits("Gradient") )
    //       fillPainter = createGradient( static_cast<Gradient*>(element.fill().ref().getRefElement()) );
  }



  KRenderingPaintServer *strokePainter = 0;
  unsigned int strokeType = element.stroke().strokeType();

  // Handle the different stroke Types
  if ( strokeType == StrokeAttribute::STROKE_SOLID )
  {
    strokePainter = m_device->createPaintServer(KCPaintServerType(PS_SOLID));
    KRenderingPaintServerSolid *strokePainterSolid = static_cast<KRenderingPaintServerSolid *>(strokePainter);

    strokePainterSolid->setColor( element.stroke().color().animVal().qColor() );
    renderStyle->strokePainter()->setOpacity( element.stroke().strokeOpacity().animVal().value() );
  }
  else if ( strokeType == StrokeAttribute::STROKE_NONE )
  {
    //strokeColor = QColor(qRgba(0, 0, 0, 0));
  }
  else if ( strokeType == StrokeAttribute::STROKE_REF )
  {
    fillPainter = m_canvas->registry()->getPaintServerById(
                    element.stroke().ref().getLocalURI() );
    /*    if ( element.stroke().ref().getRefElement()->inherits("Gradient") )
    strokePainter = createGradient( static_cast<Gradient*>(element.stroke().ref().getRefElement()) );*/
  }

  if (fillPainter)
    renderStyle->fillPainter()->setPaintServer(fillPainter);
  if (strokePainter)
    renderStyle->strokePainter()->setPaintServer(strokePainter);
  renderStyle->strokePainter()->setStrokeWidth( element.stroke().strokeWidth().animVal().value() );
}


void VDrawElements::createSelectionHandles( unsigned int node, ElementSelection& element )
{
  bool pathChanged = element.isContextDirty();
  KCanvasItem *canvasItem = element.context((ElementSelection::HandleNode)node);
  QPoint centerCoord;

  if ( !canvasItem || pathChanged )
  {
    switch(node)
    {
    case ElementSelection::node_lt:
      centerCoord.setX( element.bbox().x() );
      centerCoord.setY( element.bbox().y() );
      break;
    case ElementSelection::node_mt:
      centerCoord.setX( element.bbox().x() + element.bbox().width()/2 );
      centerCoord.setY( element.bbox().y() );
      break;
    case ElementSelection::node_rt:
      centerCoord.setX( element.bbox().x() + element.bbox().width() );
      centerCoord.setY( element.bbox().y() );
      break;
    case ElementSelection::node_lm:
      centerCoord.setX( element.bbox().x() );
      centerCoord.setY( element.bbox().y() + element.bbox().height()/2 );
      break;
    case ElementSelection::node_mm:
      centerCoord.setX( element.bbox().x() + element.bbox().width()/2 );
      centerCoord.setY( element.bbox().y() + element.bbox().height()/2 );
      break;
    case ElementSelection::node_rm:
      centerCoord.setX( element.bbox().x() + element.bbox().width() );
      centerCoord.setY( element.bbox().y() + element.bbox().height()/2 );
      break;
    case ElementSelection::node_lb:
      centerCoord.setX( element.bbox().x() );
      centerCoord.setY( element.bbox().y() + element.bbox().height() );
      break;
    case ElementSelection::node_mb:
      centerCoord.setX( element.bbox().x() + element.bbox().width()/2 );
      centerCoord.setY( element.bbox().y() + element.bbox().height() );
      break;
    case ElementSelection::node_rb:
      centerCoord.setX( element.bbox().x() + element.bbox().width() );
      centerCoord.setY( element.bbox().y() + element.bbox().height() );
      break;
    default:
      centerCoord.setX(0);
      centerCoord.setY(0);
    }
  }

  if (!canvasItem)
  {
    KRenderingStyle *renderStyle = new KRenderingStyle();
    KRenderingPaintServer *fillPainter = m_device->createPaintServer(KCPaintServerType(PS_SOLID));
    KRenderingPaintServerSolid *fillPainterSolid = static_cast<KRenderingPaintServerSolid *>(fillPainter);
    fillPainterSolid->setColor(QColor("blue"));
    renderStyle->fillPainter()->setPaintServer(fillPainter);
    renderStyle->strokePainter()->setStrokeWidth(0.0);

    KCPathDataList itemPathData = KCanvasCreator::self()->createRectangle(
                                    centerCoord.x()-3, centerCoord.y()-3, 6, 6);
    canvasItem = KCanvasCreator::self()->createPathItem(m_canvas, renderStyle, itemPathData);
    element.setContext((ElementSelection::HandleNode)node, canvasItem);
    m_canvas->insertItem(canvasItem, 500010);
  }
  else
  {
    // update Path
    if ( pathChanged )
    {
      KCPathDataList newpathData = KCanvasCreator::self()->createRectangle(
                                     centerCoord.x()-3, centerCoord.y()-3, 6, 6);
      canvasItem->changePath(
        KCanvasCreator::self()->createCanvasPathData( m_canvas, newpathData ) );
      canvasItem->invalidate();
    }
  }
}


void VDrawElements::createPathNodeHandles( ElementSelection & element )
{
  if ( !element.isContextDirty() )
    return;
  VectorElement* ve = element.visualElements().first();

  QPtrList<KCanvasItem> &pathNodes = element.contextPathNodes();
  QPtrListIterator<KCanvasItem> it( pathNodes );
  KCanvasItem *canvasItem;
  while ( (canvasItem = it.current()) != 0 )
  {
    ++it;
    m_canvas->removeItem(canvasItem);
  }
  pathNodes.clear();

  KCPathDataList* pathDataList = ve->vectorPath().kcPathData();
  KCPathDataList::iterator nodeIt = pathDataList->begin();
  KCPathDataList::iterator lastNode = pathDataList->end();
  for ( ; nodeIt != lastNode; ++nodeIt )
  {
    KCPathData& pd = *nodeIt;

    // Style
    KRenderingStyle *renderStyle = new KRenderingStyle();
    KRenderingPaintServer *fillPainter = m_device->createPaintServer(KCPaintServerType(PS_SOLID));
    KRenderingPaintServerSolid *fillPainterSolid = static_cast<KRenderingPaintServerSolid *>(fillPainter);
    fillPainterSolid->setColor(QColor("blue"));
    renderStyle->fillPainter()->setPaintServer(fillPainter);
    renderStyle->strokePainter()->setStrokeWidth(0.0);

    // CTM
    Matrix *ctm = 0;
    ctm = VConsolidateTransform::calcCTM( *ve );
    renderStyle->setObjectMatrix(*new KCanvasMatrix(ctm->qmatrix())); // FIXME: Memory leak?
    delete ctm;

    KCPathDataList itemPathData = KCanvasCreator::self()->createRectangle(
                                    pd.x3-3, pd.y3-3, 6, 6);
    KCanvasItem* canvasItem = KCanvasCreator::self()->createPathItem(m_canvas, renderStyle, itemPathData);
    pathNodes.append(canvasItem);
    m_canvas->insertItem(canvasItem, 500010);
  }
}

void VDrawElements::updatePaintServer( LinearGradient& gradient )
{
  KRenderingPaintServerLinearGradient *fillPainterGradient =
    static_cast<KRenderingPaintServerLinearGradient *>( gradient.context() );

  float x1, y1, y2 = 0;
  float x2 = 100;
  // Set start and end
  if (!m_normalizePaintServers)
  {
    x1 = gradient.getX1(true).animVal().value();
    y1 = gradient.getY1(true).animVal().value();
    x2 = gradient.getX2(true).animVal().value();
    y2 = gradient.getY2(true).animVal().value();
  }
  fillPainterGradient->setGradientStart( QPoint( x1, y1 ) );  // FIXME: do we need a QPoint-like class for floats?
  fillPainterGradient->setGradientEnd( QPoint( x2, y2 ) );

  finalizePaintServer( gradient );
}


void VDrawElements::updatePaintServer( RadialGradient& gradient )
{
  KRenderingPaintServerRadialGradient *fillPainterGradient =
    static_cast<KRenderingPaintServerRadialGradient *>( gradient.context() );

  // Set start and end
  float cx = gradient.getCX(true).animVal().value();
  float cy = gradient.getCY(true).animVal().value();
  float r = gradient.getR(true).animVal().value();
  // fx and fy are cx and cy when not specified (SVG spec)
  float fx, fy;
  if ( gradient.getFX(true).animVal().isValid() )
    fx = gradient.getFX(true).animVal().value();
  else
    fx = cx;
  if ( gradient.getFY(true).animVal().isValid() )
    fy = gradient.getFY(true).animVal().value();
  else
    fy = cy;
  fillPainterGradient->setGradientCenter( QPoint( cx, cy ) );
  fillPainterGradient->setGradientFocal( QPoint( fx, fy ) );
  fillPainterGradient->setGradientRadius( r );

  finalizePaintServer( gradient );
}


void VDrawElements::finalizePaintServer( Gradient& gradient )
{
  KRenderingPaintServerGradient* pServer =
    static_cast<KRenderingPaintServerGradient *>( gradient.context() );

  pServer->gradientStops().clear();
  // Set the gradient stops
  Gradient* currentElement = &gradient;
  while (currentElement)
  {
    ElementNode* currentChild = currentElement->getFirstChild();
    while (currentChild )
    {
      StopElement *stop = ::qt_cast<StopElement*>(currentChild);
      if ( stop )
      {
        QColor *c = &stop->getStopColor().animVal().qColor();
        pServer->gradientStops().addStop(
          stop->getOffset().animVal().floatValue(),
          qRgba(c->red(), c->green(), c->blue(),
                int(stop->getStopOpacity().animVal().floatValue() * 255.) ) );
      }
      currentChild = currentChild->getNext();
    }
    if ( currentElement->ref().getRefElement() )
    {
      Gradient* refGradient = ::qt_cast<Gradient*>( currentElement->ref().getRefElement() );
      if (refGradient)
        currentElement = static_cast<Gradient*>(currentElement->ref().getRefElement());
    }
    else
      currentElement = 0;
  }

  // Set GradientTransform
  if (!m_normalizePaintServers)
  {
    Transform* consolidatedTrans = new Transform();
    gradient.gradientTransformList(true).animVal().consolidate( *consolidatedTrans );
    KCanvasMatrix *gradTrans = new KCanvasMatrix( consolidatedTrans->matrix()->qmatrix() ); // FIXME: Memory leak?
    pServer->setGradientTransform( *gradTrans );
    delete consolidatedTrans;
  }

  // SpreadMethod and BBoxMode
  if (!m_normalizePaintServers)
  {
    bool bbox = ( gradient.gradientUnits(true).animVal().value() ==
                  Gradient::GRADUNITS_OBJECTBOUNDINGBOX );
    pServer->setBoundingBoxMode( bbox );
  } else {
    pServer->setBoundingBoxMode(true);
  }
  KCGradientSpreadMethod spreadmethod;
  switch( gradient.spreadMethod(true).animVal().value() )
  {
  case Gradient::SPREADMETHOD_REPEAT:
    spreadmethod = SPREADMETHOD_REPEAT;
    break;
  case Gradient::SPREADMETHOD_REFLECT:
    spreadmethod = SPREADMETHOD_REFLECT;
    break;
  default:
    spreadmethod = SPREADMETHOD_PAD;
  }
  pServer->setGradientSpreadMethod( spreadmethod );

  pServer->invalidate();
}


KCPathDataList VDrawElements::createKCPathDataList( VectorElement& element )
{
  KCPathDataList itemPathData;

  switch( element.vectorPath().shapeMetaType() )
  {
  case (VectorPath::SHAPE_CIRCLE):
          itemPathData = KCanvasCreator::self()->createCircle(
                           element.vectorPath().getX().animVal().value(),
                           element.vectorPath().getY().animVal().value(),
                           element.vectorPath().getRadius().animVal().value());
    break;
  case (VectorPath::SHAPE_RECT):
          itemPathData = KCanvasCreator::self()->createRectangle(
                           element.vectorPath().getX().animVal().value(),
                           element.vectorPath().getY().animVal().value(),
                           element.vectorPath().getWidth().animVal().value(),
                           element.vectorPath().getHeight().animVal().value());
    break;
  case (VectorPath::SHAPE_RRECT):
    {
      // Some SVG spec user agent calculations for rrects:
      double rx = element.vectorPath().getRX().animVal().value();
      double ry = element.vectorPath().getRY().animVal().value();
      if ( !element.vectorPath().getRX().animVal().isValid() &&
           element.vectorPath().getRY().animVal().isValid() )
        rx = ry;
      else if ( element.vectorPath().getRX().animVal().isValid() &&
                !element.vectorPath().getRY().animVal().isValid() )
        ry = rx;
      itemPathData = KCanvasCreator::self()->createRoundedRectangle(
                       element.vectorPath().getX().animVal().value(),
                       element.vectorPath().getY().animVal().value(),
                       element.vectorPath().getWidth().animVal().value(),
                       element.vectorPath().getHeight().animVal().value(),
                       rx,
                       ry);
    }
    break;
  case (VectorPath::SHAPE_ELLIPSE):
          itemPathData = KCanvasCreator::self()->createEllipse(
                           element.vectorPath().getX().animVal().value(),
                           element.vectorPath().getY().animVal().value(),
                           element.vectorPath().getRadiusX().animVal().value(),
                           element.vectorPath().getRadiusY().animVal().value());
    break;
  case (VectorPath::SHAPE_LINE):
          itemPathData = KCanvasCreator::self()->createLine(
                           element.vectorPath().getX1().animVal().value(),
                           element.vectorPath().getY1().animVal().value(),
                           element.vectorPath().getX2().animVal().value(),
                           element.vectorPath().getY2().animVal().value());
    break;
  case (VectorPath::SHAPE_POLYGON):
          itemPathData = *element.vectorPath().kcPathData();
    break;
  case (VectorPath::SHAPE_PATH):
          itemPathData = *element.vectorPath().kcPathData();
    break;
  default:
    itemPathData = KCanvasCreator::self()->createRectangle(
                     element.vectorPath().getX().animVal().value(),
                     element.vectorPath().getY().animVal().value(),
                     100, 100);
    break;
  }

  return itemPathData;
}

bool VDrawElements::checkHideShow( ElementNode& element, KCanvasItem* canvasItem )
{
  if ( element.getState() == Element::hidden || element.getState() == Element::hidden_locked )
  {
    if ( canvasItem )
      canvasItem->style()->setVisible( false );
    return true;
  }
  else
  {
    if ( canvasItem )
      canvasItem->style()->setVisible( true );
  }
  return false;
}


bool VDrawElements::checkHideShow( ElementSelection& element )
{
  if ( element.getState() == Element::hidden || element.getState() == Element::hidden_locked )
  {
    for (unsigned int i = ElementSelection::node_body; i <= ElementSelection::node_rb; ++i)
      if ( element.context(i) )
      {
        element.context(i)->style()->setVisible( false );
        element.context(i)->invalidate();
      }
    return true;
  }
  else
  {
    for (unsigned int i = ElementSelection::node_body; i <= ElementSelection::node_rb; ++i)
      if ( element.context(i) )
      {
        element.context(i)->style()->setVisible( true );
        element.context(i)->invalidate();
      }
  }
  return false;
}

