/*******************************************************************************
**
** The source file for the Jahshaka jahnodes class
** The Jahshaka Project
** Copyright (C) 2000-2005 The Jahshaka Project
** Released under the GNU General Public License
**
*******************************************************************************/

#include "keyframer.h"

// canvas was 700x200
// main frame was 650x180 (!)
// look out for the magic numbers!


JahKeyframer::JahKeyframer(QWidget*, QWidget* parent, const char* name, WFlags f) 
    : QWidget(parent,name,f),
      zoomlevel( 4.0 ),
      addKeyframe( NULL ),
      removeKeyframe( NULL ),
      prevKeyframe( NULL ),
      nextKeyframe( NULL )
{
    jtrace = JahTrace::getInstance();	//set up tracer
    
    keyframeruiLayout = new QHBoxLayout( this, 11, 6, "keyframeruiLayout"); 

    canvas = new QCanvas( this );
    connect( canvas, SIGNAL( resized() ), this, SLOT( canvasResized() ) );

    QColor back;
    back.setHsv(35,35,35);
    canvas->setBackgroundColor(back);

    keyeditor = new KeyframeEditor( canvas, this );
    connect( keyeditor, SIGNAL( signalKeyframeChanged() ), this, SLOT( slotKeyframeChanged() ) );
    keyframeruiLayout->addWidget( keyeditor );

    keycontrolsLayout = new QVBoxLayout();
    keyframeruiLayout->addLayout( keycontrolsLayout );

    QSpacerItem* spacer_1 = new QSpacerItem( 21, 41, QSizePolicy::Minimum, QSizePolicy::Expanding );
    keycontrolsLayout->addItem( spacer_1 );

    addKeyframe = new QPushButton( this, "addKeyframe" );
    addKeyframe->setFixedSize( QSize( 32, 32 ) );
    keycontrolsLayout->addWidget( addKeyframe );
    connect( addKeyframe, SIGNAL(clicked()), SLOT(emitAddKeyframe() ) );

    removeKeyframe = new QPushButton( this, "removeKeyframe" );
    removeKeyframe->setFixedSize( QSize( 32, 32 ) );
    keycontrolsLayout->addWidget( removeKeyframe );
    connect( removeKeyframe, SIGNAL(clicked()), SLOT(emitRemoveKeyframe() ) );

    QSpacerItem* spacer_2 = new QSpacerItem( 21, 41, QSizePolicy::Minimum, QSizePolicy::Expanding );
    keycontrolsLayout->addItem( spacer_2 );

    prevKeyframe = new QPushButton( this, "prevKeyframe" );
    prevKeyframe->setFixedSize( QSize( 32, 32 ) );
    keycontrolsLayout->addWidget( prevKeyframe );
    connect( prevKeyframe, SIGNAL(clicked()), SLOT(emitPrevKeyframe() ) );

    nextKeyframe = new QPushButton( this, "nextKeyframe" );
    nextKeyframe->setFixedSize( QSize( 32, 32 ) );
    keycontrolsLayout->addWidget( nextKeyframe );
    connect( nextKeyframe, SIGNAL(clicked()), SLOT(emitNextKeyframe() ) );

    QSpacerItem* spacer_3 = new QSpacerItem( 21, 41, QSizePolicy::Minimum, QSizePolicy::Expanding );
    keycontrolsLayout->addItem( spacer_3 );

    languageChange();

    static int r=24;
    srand(++r);

    clear();

    buildInterface();
    addPlayLine();
    setNodelist(NULL);
}

void JahKeyframer::languageChange()
{
    //setCaption( tr( "Form1" ) );
    addKeyframe->setText( tr( "+" ) );
    removeKeyframe->setText( tr( "-" ) );
    prevKeyframe->setText( tr( "<<" ) );
    nextKeyframe->setText( tr( ">>" ) );
}

JahKeyframer::~JahKeyframer()
{   //delete printer; 
}

void JahKeyframer::clear() 
{   
    m_interfaceH.reset( NULL );
    m_interfaceV.reset( NULL );
    m_center_line.reset(NULL);
    keyeditor->cleareditor();
}

void JahKeyframer::enlarge()
{    
    //canvas->resize(canvas.width()*4/3, canvas.height()*4/3);
}

void JahKeyframer::shrink()
{    
    //canvas->resize(canvas.width()*3/4, canvas.height()*3/4);
}

void JahKeyframer::zoomIn()
{   
    QWMatrix m = keyeditor->worldMatrix();    
    m.scale( 2.0, 2.0 );    
    keyeditor->setWorldMatrix( m );
}

void JahKeyframer::zoomOut()
{    
    QWMatrix m = keyeditor->worldMatrix();    
    m.scale( 0.5, 0.5 );    
    keyeditor->setWorldMatrix( m );
}


//qt signals are here
void JahKeyframer::emitAddKeyframe(void)    { emit AddKeyframe(); }
void JahKeyframer::emitRemoveKeyframe(void) { emit RemoveKeyframe(); }
void JahKeyframer::emitPrevKeyframe(void)   { emit PrevKeyframe(); }
void JahKeyframer::emitNextKeyframe(void)   { emit NextKeyframe(); }

//this one draws random keyframes for testing purposes
void JahKeyframer::updateKeyframes()
{ 
    clear();
    buildInterface();
    buildKeyframes();

    canvas->setAllChanged();
    canvas->update();

    keyeditor->update();
}

void JahKeyframer::updateKeyframes(int max_frame, int current_frame, QPtrList<motionNode>* nodelist)
{   
    clear();
    buildInterface();
    buildKeyframes(max_frame, current_frame, nodelist);
    setMaxFrame(max_frame);
    setCurrentFrame(current_frame);
    setNodelist(nodelist);

    canvas->setAllChanged();
    canvas->update();

    keyeditor->update();
}

void JahKeyframer::buildInterface()
{
    if ( m_interfaceH.get() || m_interfaceV.get() || m_center_line.get() )
    {
        return;
    }

    const int OFFSET = 3;
    int w = canvas->width();
    int h = canvas->height();
    //int insetW = w - OFFSET;
    int insetH = h - OFFSET;

    m_interfaceH.reset( new QCanvasLine(canvas) );
    m_interfaceH->setPen( QPen(Qt::green) );
    m_interfaceH->setPoints( 0, insetH, w, insetH );
    m_interfaceH->setZ(128);
    m_interfaceH->show();

    m_interfaceV.reset( new QCanvasLine(canvas) );
    m_interfaceV->setPen( QPen(Qt::green) );
    m_interfaceV->setPoints( OFFSET, 0, OFFSET, h );
    m_interfaceV->setZ(128);
    m_interfaceV->show();

    m_center_line.reset( new QCanvasLine(canvas) );
    m_center_line->setPen( QPen(Qt::green) );
    m_center_line->setPoints( 0, h / 2, w, h / 2 );
    m_center_line->setZ(128);
    m_center_line->show();
}

void JahKeyframer::drawLine(int x1, int y1, int x2, int y2)
{
    QCanvasLine* i = new QCanvasLine(canvas);
    i->setPoints( x1, y1,	  x2,y2 );
    i->setPen( QPen(Qt::white) );
    i->setZ(128);
    i->show();

}

//////////////////////////////////////////
// adds the playbar vertical line
void JahKeyframer::addPlayLine()
{
    playline.reset( new SliderItem(canvas) );
    playline->setPoints(0, 0, 0, canvas->height() );

    playline->setPen( QPen(QColor(100,0,0), 6) );
    playline->setZ(3);
    playline->show();
}

void JahKeyframer::movePlayLine( int keyframe )
{
    //printf("movePlayLine keyframe %i\n", keyframe );
    if ( playline.get() )
    {   
        int x_location = int( double(keyframe) * zoomlevel );
        x_location = jahstd::Max<int>(x_location, 5);
        playline->move( x_location, playline->y() );
        
        canvas->update();
    }
}

//initially this will be display only :)
//with zoom and scroll and timeline 
void JahKeyframer::buildKeyframes()
{
    //jtrace->debug("JahKeyframer::buildKeyframes()","in empty buildkeyframes");
}

//initially this will be display only :)
//with zoom and scroll and timeline 
void JahKeyframer::buildKeyframes(int max_frame, int current_frame, QPtrList<motionNode> * nodelist)
{
    jtrace->debug( "JahKeyframer::","running buildKeyframes");
    jtrace->debug( "numnodes", nodelist->count());

    buildKeyframeSequence(max_frame, current_frame, "tx", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "ty", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "tz", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "rx", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "ry", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "rz", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "sx", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "sy", nodelist );
    buildKeyframeSequence(max_frame, current_frame, "sz", nodelist );
}

void JahKeyframer::buildKeyframeSequence(int, int current_frame, QString property_qstring, QPtrList<motionNode> * nodelist)
{
    int nodecount = nodelist->count();
    std::string property_string = property_qstring.data();
    int last_keyframe_time = nodelist->last()->m_frame_number;

    zoomlevel = 4.0;

    if ( nodelist->count() )
    {
        if (last_keyframe_time > 0.0)
        {
            zoomlevel = (double)canvas->width() / (last_keyframe_time + 1.0);
        }
    }

    movePlayLine(current_frame);

    QMemArray<KeyframeItem*> lastRow(nodecount);

    KeyframeItem* previous_keyframe_item = NULL;

    motionNode* keyframe = nodelist->first();

    QColor point_color = pointColor(property_string);

    for ( ; keyframe; keyframe = nodelist->next() )
    {
        float* keyframe_value_ptr = propertyPtr(property_string, keyframe);
        KeyframeItem* new_keyframe_item = new KeyframeItem(point_color, canvas, keyframe_value_ptr);

        int xval; 
        int yval = 0;

        xval = int( double(keyframe->m_frame_number) * zoomlevel );

        float current_keyframe_value = *keyframe_value_ptr;

        if (property_qstring == "sx" || property_qstring == "sy" || property_qstring == "sz")
        {
            yval = -(int)( (current_keyframe_value - 1.0f) * 100.0f / KEYFRAMER_Y_SCALE_FACTOR );
        }
        else
        {
            yval = -(int)( current_keyframe_value / KEYFRAMER_Y_SCALE_FACTOR );
        }
        
        yval += ( canvas->height() / 2);

        new_keyframe_item->move( xval, yval);

        // This is necessary to restore because the move() call will change the keyframe value
        *keyframe_value_ptr = current_keyframe_value;

        KeyEdgeItem* new_key_edge_item = NULL;

        //if i=0 first keyframe draw line from offscreen infinity to current point
        if ( keyframe == nodelist->getFirst() )  
        { 
            //new_key_edge_item = new KeyEdgeItem( 0, yval, new_keyframe_item, canvas );
        }

        //if i=nodes last keyframe draw line to offscreen infinity from current point
        if ( keyframe == nodelist->getLast() ) 
        { 
            //new_key_edge_item = new KeyEdgeItem( new_keyframe_item, 800, yval, canvas );
        }

        if ( previous_keyframe_item ) 
        { 
            new_key_edge_item = new KeyEdgeItem( previous_keyframe_item, new_keyframe_item, canvas );
        }

        if ( keyframe != nodelist->getFirst() ) 
        {
            lastRow[nodelist->at()-1] = previous_keyframe_item;
        }

        previous_keyframe_item = new_keyframe_item;

        if (new_key_edge_item)
        {
            new_key_edge_item->show();
        }

        if (new_keyframe_item)
        {
            new_keyframe_item->show();
        }
    }
}

QColor 
JahKeyframer::pointColor(std::string property)
{
    if ( property == "tx" )
    {
        return (Qt::red);
    }
    else if ( property == "ty" )
    {
        return (Qt::green);
    }
    else if ( property == "tz" )
    {
        return (Qt::blue);
    }
    else if ( property == "rx" )
    {
        return (Qt::cyan);
    }
    else if ( property == "ry" )
    {
        return (Qt::magenta);
    }
    else if ( property == "rz" )
    {
        return (Qt::yellow);
    }
    else if ( property == "sx" )
    {
        return (KEYFRAMER_SCALE_X_COLOR);
    }
    else if ( property == "sy" )
    {
        return (KEYFRAMER_SCALE_Y_COLOR);
    }
    else if ( property == "sz" )
    {
        return (KEYFRAMER_SCALE_Z_COLOR);
    }
    else 
    {
        return (Qt::red);
    }
}

float* 
JahKeyframer::propertyPtr(std::string property, motionNode* keyframe)
{
    if ( property == "tx" )
    {
        return ( &keyframe->tx );
    }
    else if ( property == "ty" )
    {
        return ( &keyframe->ty );
    }
    else if ( property == "tz" )
    {
        return ( &keyframe->tz ); 
    }
    else if ( property == "rx" )
    {
        return ( &keyframe->rx ); 
    }
    else if ( property == "ry" )
    {
        return ( &keyframe->ry ); 
    }
    else if ( property == "rz" )
    {
        return ( &keyframe->rz ); 
    }
    else if ( property == "sx" )
    {
        return ( &keyframe->sx ); 
    }
    else if ( property == "sy" )
    {
        return ( &keyframe->sy ); 
    }
    else if ( property == "sz" )
    {
        return ( &keyframe->sz ); 
    }
    else 
    {
        return NULL; 
    }
}

int JahKeyframer::propertyValue(std::string property, motionNode* keyframe )
{
    if ( property == "tx" )
    {
        return ( int( keyframe->tx ) );
    }
    else if ( property == "ty" )
    {
        return ( int( keyframe->ty ) );
    }
    else if ( property == "tz" )
    {
        return ( int( keyframe->tz ) ); 
    }
    else if ( property == "rx" )
    {
        return ( int( keyframe->rx ) ); 
    }
    else if ( property == "ry" )
    {
        return ( int( keyframe->ry ) ); 
    }
    else if ( property == "rz" )
    {
        return ( int( keyframe->rz ) ); 
    }
    else if ( property == "sx" )
    {
        return ( int( keyframe->sx ) ); 
    }
    else if ( property == "sy" )
    {
        return ( int( keyframe->sy ) ); 
    }
    else if ( property == "sz" )
    {
        return ( int( keyframe->sz ) ); 
    }
    else 
    {
        return 0; 
    }
}

void JahKeyframer::canvasResized()
{
    m_interfaceV.reset( NULL );
    m_interfaceH.reset( NULL );
    m_center_line.reset( NULL );
    playline.reset( NULL );
    
    buildInterface();
    addPlayLine();  

    if ( getNodelist() )
    {
        updateKeyframes( getMaxFrame(), getCurrentFrame(), getNodelist() );
    }
}

void
JahKeyframer::slotKeyframeChanged()
{
    emit signalKeyframeChanged();
}

