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

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

// Elements
#include "elements/elementnode.h"
#include "elements/animateelement.h"
#include "elements/elementselection.h"
#include "elements/timeattribute.h"

// Qt
#include <qpainter.h>
#include <qdrawutil.h>
#include <qpaintdevice.h>
#include <qlabel.h>

// KDE
#include <kdebug.h>
#include <kruler.h>

TimelineView::TimelineView(QWidget *parent, const char *name)
    : QFrame(parent, name), Visitor(),
    m_currentTLPos(0),
    m_PXPerSecond(10)
{
  Kast::self()->elementDB().addElementListener(this);
  Kast::self()->elementDB().selection().addElementSelectionListener(this);

  setPaletteBackgroundColor(Qt::white);
  setFrameShape( QFrame::GroupBoxPanel );
  // TODO: Introduce some kind of KRuler displaying the time here
}


TimelineView::~TimelineView()
{}

void TimelineView::paintEvent( QPaintEvent *e )
{
  QPainter p( this );
  QRect r = e->rect();
  QColorGroup cg( colorGroup() );

  //p.fillRect ( 0, 0, r.width(), r.height(), QBrush( cg.light(), QBrush::SolidPattern ) );
  // rect
  //   p.setBrush( cg.light() );
  //   qDrawShadeRect( &p, 0, 0, r.width(), r.height(), cg, true, 1, 1, &p.brush() );

  //p.setPen( QPen( cg.shadow(), 1 ) );
  //p.drawRect ( 0, 0, r.width(), r.height() );

  QFrame::paintEvent(e);
  // crossed lines
  p.setBrush( cg.midlight() );

  p.drawText( m_currentTLPos + 2, height() -20, 100, 20, Qt::AlignBottom,
              (QString().setNum( (double)m_currentTLPos / (double)m_PXPerSecond ).append(" s") ) );
  p.drawLine( m_currentTLPos, 0, m_currentTLPos, height() );
}

void TimelineView::mouseMoveEvent( QMouseEvent *e )
{
  if( e->state() ==  Qt::LeftButton )
    timelineClicked(e->pos());
  e->accept();
}

void TimelineView::mousePressEvent( QMouseEvent *e )
{
  if( e->button() == Qt::LeftButton )
    timelineClicked(e->pos());
  e->accept();
}

void TimelineView::timelineClicked( const QPoint& p )
{
  m_currentTLPos = p.x();
  repaint();
  Kast::self()->timeServer().setTime(((double)m_currentTLPos / (double)m_PXPerSecond));
}

void TimelineView::clear( )
{
  kdDebug() << k_funcinfo << endl;
  QPtrDictIterator<AnimationLabel> it(m_elementsToLabels);
  while( it.current() )
  {
    it.current()->hide();
    ++it;
  }
}

void TimelineView::showElement( ElementNode* e, int ypos )
{
  // kdDebug() << k_funcinfo << endl;
  appendAnimLabel(e); // Always call append first. It will try to add the label if it does not exist
  AnimationLabel* label = m_elementsToLabels.find(e);
  if (label)
  {
    AnimateElement* a = static_cast<AnimateElement*>(e);
    label->setGeometry( (int)a->getStartTime().value()*m_PXPerSecond, ypos,
                        (int)a->getSimpleDuration().value()*m_PXPerSecond, 20);
    label->show();
  }
}

bool TimelineView::visit( AnimateTransformElement & element )
{
  /*// Element already in list?
  if ( m_elementsToLabels.find(&element) )
    return false;*/
  kdDebug() << k_funcinfo << endl;

  AnimationLabel *animLabel = new AnimationLabel(&element, this);
  animLabel->setText(element.className());

  // Add to dictionary
  m_elementsToLabels.insert(&element, animLabel);

  return true;
}

bool TimelineView::visit( AnimateLengthElement & element )
{
  //   // Element already in list?
  //   if ( m_elementsToLabels.find(&element) )
  //     return false;
  kdDebug() << k_funcinfo << endl;

  AnimationLabel *animLabel = new AnimationLabel(&element, this);
  animLabel->setText(element.className());

  // Add to dictionary
  m_elementsToLabels.insert(&element, animLabel);

  return true;
}

bool TimelineView::visit( AnimateNumberElement & element )
{
  //   // Element already in list?
  //   if ( m_elementsToLabels.find(&element) )
  //     return false;
  kdDebug() << k_funcinfo << endl;

  AnimationLabel *animLabel = new AnimationLabel(&element, this);
  animLabel->setText(element.className());

  // Add to dictionary
  m_elementsToLabels.insert(&element, animLabel);

  return true;
}

void TimelineView::onElementInserted( ElementNode * )
{
  // kdDebug() << k_funcinfo << endl;
  // appendAnimLabel(e); // appendAnimLabel is now called only on demand in showElement()
}

void TimelineView::onElementRemoved( ElementNode *e )
{
  // kdDebug() << k_funcinfo << endl;
  AnimationLabel* item = m_elementsToLabels.find(e);
  m_elementsToLabels.remove( e );
  delete item;
}

void TimelineView::onElementModified( ElementNode * )
{}

void TimelineView::onSelectionModified( )
{}

void TimelineView::appendAnimLabel( ElementNode* e, bool addNeighbours )
{
  // kdDebug() << k_funcinfo << endl;
  if (!e)
    return;

  if ( m_elementsToLabels.find(e) )
    return;

  e->accept(*this);

  if (e->getFirstChild())
  {
    // Ignore UseElement's children (they are only cloned Def's and Symbols)
    if( !e->isA("UseElement") )
      appendAnimLabel(e->getFirstChild(), true);
  }
  if (addNeighbours && e->getNext())
    appendAnimLabel(e->getNext(), true);
}

double TimelineView::getTimeFromPX( int px )
{
  return (double)px / (double)m_PXPerSecond;
}




#include "commands/esetgenericattrcmd.h"

#include <kcursor.h>

AnimationLabel::AnimationLabel( AnimateElement * element, TimelineView * parent ) :
    QLabel(parent),
    m_parentTLView(parent),
    m_element(element),
    m_dragactive(false),
    m_xoffset(0),
    m_resizeactive(false)
{
  setLineWidth(1);
  setPaletteBackgroundColor( Qt::white );
  setFrameShape( QFrame::Box );
  setMouseTracking(true);
}

void AnimationLabel::mousePressEvent( QMouseEvent * e )
{
  int x = e->pos().x();
  int w = width();

  if ( x > w - 10 )
  {
    setCursor(KCursor::sizeHorCursor());
    // starting resize
    m_dragactive = false;
    m_resizeactive = true;
  }
  else
  {
    // starting Drag
    setCursor(KCursor::sizeAllCursor());
    m_dragactive = true;
    m_resizeactive = false;
    m_xoffset = x;
  }
}

void AnimationLabel::mouseMoveEvent( QMouseEvent * e )
{
  int x = e->pos().x();
  int w = width();

  if ( x > w - 10 )
    setCursor(KCursor::sizeHorCursor());
  else
    setCursor(KCursor::arrowCursor());

  if( e->state() == LeftButton && m_dragactive )
  {
    setCursor(KCursor::sizeAllCursor());
    move( pos().x() + (x - m_xoffset), pos().y() );
  }
  else if( e->state() == LeftButton && !m_dragactive && x > 8 )
  {
    //setCursor(KCursor::sizeHorCursor());
    resize( x+5, height() );
  }

  e->accept();
}

void AnimationLabel::mouseReleaseEvent( QMouseEvent * )
{
  // FIXME: CMDs here
  if (m_resizeactive)
  {
    TimeAttribute newDuration( m_parentTLView->getTimeFromPX(width()) );
    kdDebug() << "AnimationLabel::mouseReleaseEvent() - Setting duration to " << newDuration.value() << endl;
    ESetGenericAttrCMD *cmd = new ESetGenericAttrCMD( m_element, m_element->getSimpleDuration(), newDuration );
    Kast::self()->addCommand(cmd);
  }
  else if (m_dragactive)
  {
    TimeAttribute newStart( m_parentTLView->getTimeFromPX(x()) );
    kdDebug() << "AnimationLabel::mouseReleaseEvent() - Setting begin to " << newStart.value() << endl;
    ESetGenericAttrCMD *cmd = new ESetGenericAttrCMD( m_element, m_element->getStartTime(), newStart );
    Kast::self()->addCommand(cmd);
  }
}



#include "timelineview.moc"
