#include "testApp.h"
#include "stdio.h"


//--------------------------------------------------------------
testApp::testApp(){

    camW    = 320;
    camH    = 240;
    camId   = 1;
    screenW = ofGetWidth();
    screenH = ofGetHeight();
    bUseVideoFiles = false;
    bShowInfo = true;
    loadCounter = 0;

}

//--------------------------------------------------------------
void testApp::setup(){



    loadConfigSettings( "settings/config.xml" );


    //----------- video settings
	if (bUseVideoFiles == true){

		videoSource			= new ofVideoPlayer();
		((ofVideoPlayer *)videoSource)->loadMovie("fingers.mov");
		((ofVideoPlayer *)videoSource)->play();
		((ofVideoPlayer *)videoSource)->setLoopState(OF_LOOP_NORMAL);
		((ofVideoPlayer *)videoSource)->setSpeed(1);

	} else {

		videoSource			= new ofVideoGrabber();
		((ofVideoGrabber *)videoSource)->setVerbose(true);
		((ofVideoGrabber *)videoSource)->listDevices();
		((ofVideoGrabber *)videoSource)->setDeviceID(camId);
		((ofVideoGrabber *)videoSource)->initGrabber(camW, camH);
	}

    //----------- tracking setup
    TR = new tracker();
    TR->setup(camW,camH);
    TR->loadFromXML("trackingConfig.xml");

    //----------- "mouse" recording
	PR = new grafRecorder();
    PR->setup(camW,camH);

    //----------- editing
    GE = new grafEditor();
    GE->setup(20,screenH-40,200,18);

    //----------- saving data
    DM = new grafIO();

    //----------- physics
    VF = new vectorField();
    PS = new particleSystem();


	//----------- setup physics
	PS->setup(FIELD_SIZE,WIDTH_FIELD,HEIGHT_FIELD,VF);


	//----------- app setup
	lastX           = 0;
	lastY           = 0;
	mouse_mode      = 3;


    PR->rotation.set(0,0,0);
    PR->position.set(0,0,1);

    bUseMouseCapture = false;
    bShowCVPanel     = false;
	bShiftOn         = false;
	bShowEditPanel   = false;


    //-----------
    ofSetFrameRate(60);
    ofBackground(0.0f, 0.0f, 0.0f);

    loadToEdit();



}

//--------------------------------------------------------------
void testApp::update(){

    screenW = ofGetWidth();
    screenH = ofGetHeight();

    ofBackground(0,0,0);

    //----------- video capture
    videoSource->update();


    //-----------
    if(!bUseMouseCapture) TR->update( videoSource->getPixels() );


	//-----------
    ofPoint addPoint;
    if(bUseMouseCapture)    addPoint.set(lastX,lastY,1 );
    else                    addPoint.set(TR->getX(), TR->getY(),1);


    PR->update(addPoint);
	if(PR->bAmRecording) GE->updateMax( PR->getNumPts()-1 );


    //-----------
    if(PR->getIdCurrent() > PR->getStartPt()+1)
    {
        PS->update(1.0f);
        VF->fadeField(0.99f);

        if(PR->pts.size() > 1)
            VF->update( PR->getCurrentPoint(), PR->getVelocityForTime( PR->getCurrentTime() ), screenW, screenW, screenH);
    }

    if( !PR->bAmRecording && PR->bReset)
    {
        reset_vfield();
        PR->bReset = false;
    }







}


//--------------------------------------------------------------
void testApp::draw(){


   	//----------- draw
   	if( bShowEditPanel ) GE->draw();

   	//----------- draw computer vision control panel
   	if( bShowCVPanel)   TR->draw();


    ofNoFill();

    //-----------  render
    glPushMatrix();

        glTranslatef(screenW/2, screenH/2, 0);

        glScalef(PR->position.z,PR->position.z,PR->position.z);

        glRotatef(PR->rotation.x,0,1,0);
        glRotatef(PR->rotation.y,1,0,0);
        glRotatef(PR->rotation.z,0,0,1);

        glTranslatef(PR->position.x,PR->position.y,PR->position.z);


        glPushMatrix();

            glTranslatef(-screenW/2, -screenH/2, 0);
            PS->draw(  PR->getCurentZDepth() );

        glPopMatrix();


        glPushMatrix();

            glTranslatef(-screenW/2, -screenH/2, 0);
            glScalef(screenW,screenW,1);

            ofSetColor(255,255,255);
            PR->draw(screenW);

        glPopMatrix();



        ofSetColor(255,0,0);
        glPushMatrix();
            glTranslatef(-screenW/2, -screenH/2, 0);
            glTranslatef(0,0,PR->getCurentZDepth() );
            ofCircle( (TR->getX()/camW) * screenW, (TR->getY()/camW)*screenW, 4 );

         glPopMatrix();



    glPopMatrix();

    if(bShowInfo)
    {
    ofSetColor(0xffffff);
    ofDrawBitmapString( ofToString( ofGetFrameRate(), 2 ),20,500);
    ofDrawBitmapString( "Name: " + GE->getName(),20,520);
    ofDrawBitmapString( "Total Points: " + ofToString(PR->getNumPts()),20,540);
    ofDrawBitmapString( "' ': toggle recording ",20,570);
    ofDrawBitmapString( "c: toggle camera/cv panel ",20,590);
    ofDrawBitmapString( "e: toggle edit panel ",20,610);
    ofDrawBitmapString( "h: toggle info panel ",20,630);

    if(bShowEditPanel)
    ofDrawBitmapString( "To Save: click out of graf name text box + hit 's' ",20,650);
    }

}


//--------------------------------------------------------------
void testApp::keyPressed  (int key){


    if( GE->isEnteringName() )
    {
        GE->editName( key );
        return;
    }

    switch(key){

  		case 'b':
            TR->bCaptureBg = true;
            break;
        case 'c':
            bShowCVPanel = !bShowCVPanel;
            break;
        case 'e':
            bShowEditPanel = !bShowEditPanel;
            PR->toggleEditing(bShowEditPanel);
            break;
        case 'h': bShowInfo = !bShowInfo; break;
        case ' ':
  			PR->toggleRecording();
            reset_vfield();
            if( PR->bAmRecording ) bShowEditPanel = false;
  			break;
  		case '1':
  			//FRONT ELEVATION
  			PR->rotation.set(0.0,0.0,0.0);
  			break;
  		case '2':
  			//SIDE ELEVATION
  			PR->rotation.set(90.0,0.0,0.0);
  			break;
  		case '3':
  			//TOP ELEVATION
  			PR->rotation.set(180.0,90.0,0.0);
  			break;
  		case 's':
  			PR->resetForEditing();
  			GE->checkNameForSaving();
  			DM->saveGrafTag(GE->getName(),PR);
  			break;
  		case 'p':
            PR->togglePaused();
            break;
        case 'm':
            bUseMouseCapture = !bUseMouseCapture;
            if(bUseMouseCapture){ PR->width = screenW; PR->height = screenH; }
            else{ PR->width = camW; PR->height = camH; }
        case OF_KEY_RIGHT:
            loadToEdit();
            break;
        default:
  			break;

  }



}

//--------------------------------------------------------------
void testApp::keyReleased(int key){

}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){

	lastX   = x;
	lastY   = y;
}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){

	if(bShowCVPanel)
	{
	    TR->mouseDragged(x,y,button);
    }

    bool bEdit = false;
    if( bShowEditPanel )
    {
        bEdit = GE->update(x,y) ;
        if ( bEdit )
        {
        PR->setEndPt( GE->getEnd());
        PR->setStartPt( GE->getStart());
        PR->resetForEditing();
        }
    }


    if(!bShowCVPanel && !bEdit)
	{
	    if( button == 0 )
	    {
            if( bShiftOn )
            {
                PR->rotation.x += x - lastX;
                PR->rotation.y += y - lastY;
            }else{

                PR->position.x += x-lastX;
                PR->position.y += y-lastY;
            }

        }else{
            PR->position.z += (y - lastY) * .01f;
        }

	}







	lastX   = x;
	lastY   = y;

}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){

    lastX = x;
	lastY = y;

	if(glutGetModifiers() == GLUT_ACTIVE_SHIFT) bShiftOn = true;

    if(bShowCVPanel) TR->mousePressed(x,y,button);
    if(bShowEditPanel) GE->update(x,y) ;
}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){

    bShiftOn = false;

}

//--------------------------------------------------------------
void testApp::resized(int w, int h){

}


void testApp::reset_vfield(){

    PS->reset(WIDTH_FIELD,HEIGHT_FIELD);
    VF->clearField();

}


void testApp::loadConfigSettings(string filename)
{
    ofxXmlSettings  xml;

    xml.loadFile(filename);

    bUseVideoFiles = xml.getValue("useVideo",false);
    camW    = xml.getValue("camWidth",320);
    camH    = xml.getValue("camHeight",240);
    camId   = xml.getValue("camId",0);

}

void testApp::loadToEdit()
{
    if( DM->loadGrafTagToEdit(PR,loadCounter) )
    {
            GE->updateMax( PR->getNumPts()-1 );
            loadCounter++;
    }

}
