/***************************************************************************
 *   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 "gradienteditorwidget.h"

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

// Elements
#include "elements/gradient.h"
#include "elements/lineargradient.h"
#include "elements/animatedenum.h"
#include "elements/enumeration.h"
#include "elements/number.h"
#include "elements/animatednumber.h"
#include "elements/colorattribute.h"
#include "elements/animatedcolorattr.h"
#include "elements/stopelement.h"
#include "elements/defselement.h"
#include "elements/elementselection.h"
#include "elements/fillattribute.h"
#include "elements/vectorelement.h"
#include "elements/urireference.h"

// Visitors
#include "visitors/deepclonevisitor.h"

// Commands
#include "commands/efillcmd.h"

// Widgets
#include "gradientpreview.h"
#include "stopseditorwidget.h"

// Qt
#include <qlayout.h>
#include <qlabel.h>
#include <qgroupbox.h>

// KDE
#include <kdebug.h>
#include <klocale.h>
#include <knuminput.h>
#include <kpushbutton.h>
#include <kcolorbutton.h>

GradientEditorWidget::GradientEditorWidget(QWidget *parent, const char *name)
    : QWidget(parent, name),
    m_gradient(0),
    m_currentStop(0)
{
  QGridLayout *layout = new QGridLayout(this, 4,1);
  m_gradient = new LinearGradient();
  m_gradPreview = new GradientPreview(this, "GradientEditorWidget.GradientPreview");
  layout->addWidget(m_gradPreview,0,0);
  m_stopsEditor = new StopsEditorWidget(this, "GradientEditorWidget.StopsEditor");
  layout->addWidget(m_stopsEditor,1,0);

  // The Stops GroupBox
  QGroupBox *gb = new QGroupBox(5, Qt::Horizontal, i18n("Stops"), this);
  layout->addWidget(gb,2,0);

  // Location NumInput
  QLabel *stopOffseLbl1 = new QLabel(i18n("Location:"),gb);
  stopOffseLbl1->setAlignment( Qt::AlignRight );
  m_stopOffsetNInput = new KIntNumInput(gb);
  stopOffseLbl1->setBuddy( m_stopOffsetNInput );
  m_stopOffsetNInput->setMinValue(0);
  m_stopOffsetNInput->setMaxValue(100);
  m_stopOffsetNInput->setSuffix(i18n("%"));
  //   new QLabel(i18n("%"),gb);
  connect ( m_stopOffsetNInput, SIGNAL(valueChanged(int )),
            this, SLOT(slotOffsetNInputChanged(int )) );

  // Color Button
  QLabel *colorLbl1 = new QLabel(i18n("Color:"),gb);
  colorLbl1->setAlignment( Qt::AlignRight );
  m_colorBtn = new KColorButton(gb);
  colorLbl1->setBuddy( m_colorBtn );
  gb->addSpace(1);
  connect ( m_colorBtn, SIGNAL(changed(const QColor& )),
            this, SLOT(slotColorBtnChanged(const QColor& )) );


  // Opacity NumInput
  QLabel *stopOpacityLbl1 = new QLabel(i18n("Opacity:"),gb);
  stopOpacityLbl1->setAlignment( Qt::AlignRight );
  m_stopOpacityNInput = new KIntNumInput(gb);
  stopOpacityLbl1->setBuddy( m_stopOpacityNInput );
  m_stopOpacityNInput->setMinValue(0);
  m_stopOpacityNInput->setMaxValue(100);
  m_stopOpacityNInput->setSuffix(i18n("%"));
  //   new QLabel(i18n("%"),gb);
  connect ( m_stopOpacityNInput, SIGNAL(valueChanged(int )),
            this, SLOT(slotOpacityNInputChanged(int )) );

  // Del Button
  gb->addSpace(2);
  m_delBtn = new KPushButton(i18n("Delete"), gb);
  connect ( m_delBtn, SIGNAL(clicked()),
            this, SLOT(slotDeleteBtnChanged()) );

  // Apply Button
  m_applyBtn = new KPushButton(i18n("Apply"), this);
  layout->addWidget(m_applyBtn,3,0);
  connect ( m_applyBtn, SIGNAL(clicked()),
            this, SLOT(slotApplyBtnChanged()) );

  connect( m_stopsEditor, SIGNAL(stopsModified(StopElement*)),
           this, SLOT(slotStopModified(StopElement*)));
  connect( m_stopsEditor, SIGNAL(stopSelected(StopElement* )),
           this, SLOT(slotStopSelected(StopElement* )) );

  slotStopSelected(0);
}

GradientEditorWidget::~GradientEditorWidget()
{
  delete m_gradient;
}

void GradientEditorWidget::setGradient( Gradient &g )
{
  kdDebug() << k_funcinfo << endl;
  m_gradient->deleteSubTree();
  m_gradient = 0;
  slotStopSelected(0);
  DeepCloneVisitor* deepCloner = new DeepCloneVisitor();
  g.accept( *deepCloner );
  m_gradient = ::qt_cast<Gradient*>(deepCloner->getClone());  // This is only safe because we already know it's type
  delete deepCloner;

  applyGradient();
}

void GradientEditorWidget::applyGradient( )
{
//   kdDebug() << k_funcinfo << endl;
  m_gradient->setDirty();
  m_gradPreview->setGradientRef( m_gradient );
  m_stopsEditor->setGradient( m_gradient );
}

void GradientEditorWidget::slotStopModified( StopElement* stop )
{
//   kdDebug() << k_funcinfo << endl;
  if (stop == m_currentStop)
  {
    slotStopSelected(m_currentStop);
  }
  updatePreview();
}

void GradientEditorWidget::updatePreview( )
{
//   kdDebug() << k_funcinfo << endl;

  m_gradPreview->updatePreview();
  //m_gradPreview->setGradient( *m_gradient );
  //m_gradPreview->setGradientRef( m_gradient );  // FIXME: Faster but doesn't clean up stops on call?!!
}

void GradientEditorWidget::slotStopSelected( StopElement *stop )
{
//   kdDebug() << k_funcinfo << endl;
  m_currentStop = stop;
  if (!m_currentStop)
  {
    m_stopOpacityNInput->parentWidget()->setDisabled(true);
    return;
  }

  m_stopOpacityNInput->blockSignals(true);
  m_stopOffsetNInput->blockSignals(true);
  m_colorBtn->blockSignals(true);

  m_stopOpacityNInput->parentWidget()->setDisabled(false);
  m_stopOpacityNInput->setValue( (int)m_currentStop->getStopOpacity().baseVal().percentValue() );
  m_stopOffsetNInput->setValue( (int)m_currentStop->getOffset().baseVal().percentValue() );
  m_colorBtn->setColor( m_currentStop->getStopColor().baseVal().qColor() );

  m_stopOpacityNInput->blockSignals(false);
  m_stopOffsetNInput->blockSignals(false);
  m_colorBtn->blockSignals(false);
}

void GradientEditorWidget::slotOffsetNInputChanged( int i )
{
//   kdDebug() << k_funcinfo << endl;
  if (!m_currentStop)
    return;
  m_currentStop->getOffset().baseVal() = Number(i, Number::NUM_PERCENTAGE);
  m_stopsEditor->slotStopModifiedFromOutside(m_currentStop);
  updatePreview();
}

void GradientEditorWidget::slotOpacityNInputChanged( int i )
{
//   kdDebug() << k_funcinfo << endl;
  if (!m_currentStop)
    return;
  m_currentStop->getStopOpacity().baseVal() = Number(i, Number::NUM_PERCENTAGE);
  updatePreview();
}

void GradientEditorWidget::slotColorBtnChanged( const QColor &q )
{
//   kdDebug() << k_funcinfo << endl;
  if (!m_currentStop)
    return;
  m_currentStop->getStopColor().baseVal() = ColorAttribute(q);
  m_stopsEditor->slotStopModifiedFromOutside(m_currentStop);
  updatePreview();
}

void GradientEditorWidget::slotDeleteBtnChanged( )
{
//   kdDebug() << k_funcinfo << endl;
  m_gradient->removeChild( m_currentStop );
  delete m_currentStop;
  m_currentStop = 0;
  applyGradient();
}

void GradientEditorWidget::fireGradientUpdate( )
{
  kdDebug() << k_funcinfo << endl;
  VectorElement* targetElem = Kast::self()->elementDB().selection().visualElements().first();
  if (!targetElem)
    return;

  FillAttribute newFill(targetElem);
  newFill = targetElem->fill();
  newFill.setFillType( FillAttribute::FILL_REF );

  DeepCloneVisitor* deepCloner = new DeepCloneVisitor();
  m_gradient->accept( *deepCloner );
  Gradient* gradClone = ::qt_cast<Gradient*>(deepCloner->getClone());
  delete deepCloner;

  gradClone->setDirty();
  gradClone->setId( Kast::self()->elementDB().genUniqueID() );
  newFill.ref().setRefElement(gradClone);

  EFillCMD *cmd = new EFillCMD( targetElem, newFill, gradClone );
  Kast::self()->addCommand(cmd);
}

void GradientEditorWidget::slotApplyBtnChanged( )
{
//   kdDebug() << k_funcinfo << endl;
  fireGradientUpdate();
}


#include "gradienteditorwidget.moc"
