#include "testApp.h"

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

    ofBackground(255,255,255);

	#ifdef _USE_LIVE_VIDEO
        vidGrabber.initGrabber(320,240); //720x576 BBC Screen
	#else
        vidPlayer.loadMovie("city02.mov");
        vidPlayer.play();
        vidPlayer.setVolume(0);
	#endif

    colorImg.allocate(320,240);
    gauss_foregroundImg.allocate(320,240);
    gauss_backgroundImg.allocate(320,240);

    // not needed unless bgModel is used instead of gauss_bgModel below
    CvGaussBGStatModelParams* params = new CvGaussBGStatModelParams;
    params->win_size=200;//2; /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */
    params->n_gauss=5;//5;
    params->bg_threshold=0.7;//0.7;
    params->std_threshold=3.5;//3.5;
    params->minArea=15;//15;
    params->weight_init=0.05;//0.05;
    params->variance_init=30;//30;

    gauss_bgModel = cvCreateGaussianBGModel(colorImg.getCvImage() ,params);
    //gauss_bgModel = cvCreateGaussianBGModel(colorImg.getCvImage()); // WORKS WELL

    myFont.loadFont("gothic.ttf", 10);

    // DRAWING
    nPts = 0;

	// COLLISION
	simpleAmount     = 6.0;//1.0;
	threshold        = 80;
	blurb            = 2;

	colorCollision.allocate(320, 240);

	box2dCollision.init();
	box2dCollision.setGravity(0, 20);//(0, 20);
	box2dCollision.registerGrabbing();
	box2dCollision.createBounds(700, 40, 320, 240);//(20, 300, 320, 240);
	box2dCollision.setFPS(30.0);

	// BLOB TRAILS
	bt.setListener(this);
}

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

    ofSetWindowTitle(ofToString(ofGetFrameRate(), 2.0));

    bool bNewFrame = false;
	#ifdef _USE_LIVE_VIDEO
        vidGrabber.grabFrame();
        bNewFrame = vidGrabber.isFrameNew();
    #else
        vidPlayer.idleMovie();
        bNewFrame = vidPlayer.isFrameNew();
	#endif

   	if (bNewFrame){
        #ifdef _USE_LIVE_VIDEO
            colorImg.setFromPixels(vidGrabber.getPixels(), 320,240);
            colorCollision.setFromPixels(vidGrabber.getPixels(), 320,240);
	    #else
            colorImg.setFromPixels(vidPlayer.getPixels(), 320,240);
            colorCollision.setFromPixels(vidPlayer.getPixels(), 320,240);
        #endif

        // Update models
        cvUpdateBGStatModel(colorImg.getCvImage() ,gauss_bgModel);
        gauss_foregroundImg = gauss_bgModel->foreground;
        gauss_backgroundImg = gauss_bgModel->background;

        //gauss_foregroundImg.absDiff( gauss_backgroundImg );
        gauss_foregroundImg.blur( blurb );
        gauss_foregroundImg.threshold( threshold );

        // between the size of 20 pixels and 1/3 the w*h pixels
		// find holes is set to true so we will get interior contours too....
		contourFinder.findContours(gauss_foregroundImg, 20, (340*240)/3, 10, false);
    }

    // COLLISON
    box2dCollision.update();

    // BLOB TRAILS
    bt.trackBlobs(contourFinder.blobs);
}

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

   ofSetColor(0xffffff);

   gauss_foregroundImg.draw(20,40); //moving people

   	// CONTOURS
	ofFill();
	ofSetColor(0x333333);
	ofRect(360,40,320,240);
	ofSetColor(0xffffff);
	contourFinder.draw(360,40);

    // TEXT
    ofSetColor(0x000000);
    myFont.drawString("Foreground", 20,300);
	myFont.drawString("Contours", 360,300);
	myFont.drawString("Trails", 700,300);
	myFont.drawString("Pixels", 20,580);
    myFont.drawString("Colored Blobs", 360,580);
    myFont.drawString("Centroids", 700,580);
    myFont.drawString("Draw something! (Right click to clear...)", 20,790);

	char info[255]; char info2[255]; char info3[255]; char info4[255];
    sprintf(info, "\nThreshold: %d", threshold);
    sprintf(info2, "\nSimple Amount [left/right]: %f", simpleAmount);
    sprintf(info3, "\nBlur: %d", blurb);
    myFont.drawString(info, 20,630);
    myFont.drawString(info2, 20,650);
    myFont.drawString(info3, 20,670);

    // COLLISION
    ofSetColor(0xffffff);
	colorCollision.draw(700, 40);
    //gauss_foregroundImg.draw(20,300);

    // VIDEO
    ofFill();
	ofSetColor(0x333333);
	ofRect(20,320,320,240);
    ofSetColor(0xffffff);
    #ifdef _USE_LIVE_VIDEO
        unsigned char * pixels = vidGrabber.getPixels();
    #else
        unsigned char * pixels = vidPlayer.getPixels();
    #endif
    // let's move through the "RGB" char array
    // using the red pixel to control the size of a circle.
    for (int i = 4; i < 320; i+=8){
        for (int j = 4; j < 240; j+=8){
            unsigned char r = pixels[(j * 320 + i)*3];
            float val = 1 - ((float)r / 255.0f);
            ofCircle(20 + i,320+j,5*val);
        }
    }

    // RANDOM COLOR CONTOURS
    ofEnableAlphaBlending();
    ofFill();
	ofSetColor(0x333333);
	ofRect(360,320,320,240);
    for (int i = 0; i < contourFinder.nBlobs; i++){
        int r=ofRandom(0,255);
        int g=ofRandom(0,255);
        int b=ofRandom(0,255);
        int a=150;
        ofSetColor(r,g,b,a);

        ofFill();
        ofBeginShape();
        for (int j = 0; j < contourFinder.blobs[i].nPts; j++){
            ofVertex(contourFinder.blobs[i].pts[j].x + 360,
                     contourFinder.blobs[i].pts[j].y + 320);
        }
        ofEndShape(true);
        ofNoFill();
    }
    ofDisableAlphaBlending();

    // TRAILS
    ofFill();
	ofSetColor(0x333333);
	ofRect(700,320,320,240);
    bt.BlobLineCol = 0xff00ff;
    bt.HistLineCol = 0xff00ff;
    ofNoFill();
    bt.draw(700,40);
    bt.HistStartAlpha = 175;
    bt.HistEndAlpha = 50;
    bt.drawHistory(8,700,40);
    bt.drawCentroids(700,320);

    // BALLS
	for(int i=0; i<customParticles.size(); i++) {
		customParticles[i].draw();
	}

    // DRAWING
    ofSetColor(0x8000FF);
    ofNoFill();
    ofSetLineWidth(4);
    ofBeginShape();
    for (int i = 0; i < nPts; i++){
     if (pts[i].x ==-1 && pts[i].y==-1){
         ofEndShape();
         ofBeginShape();
     } else {
         ofVertex(pts[i].x, pts[i].y);
     }
    }
    ofEndShape();
	for(int i=0; i<drawingLine.size(); i++){
        drawingLine[i].draw();
    }
    ofSetLineWidth(1);
}

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

	// BLUR
	if(key == OF_KEY_UP) {
		blurb += 1.0;
		if(blurb > 20.0) blurb = 20.0;
	}
	if(key == OF_KEY_DOWN) {
		blurb -= 1.0;
		if(blurb < 0.0) blurb = 0.0;
	}

	// THRESHOLD
	if(key == OF_KEY_PAGE_UP) {
		threshold += 1.0;
		if(threshold > 200.0) threshold = 200.0;
	}
	if(key == OF_KEY_PAGE_DOWN) {
		threshold -= 1.0;
		if(threshold < 1.0) threshold = 1.0;
	}

	// the simple amount
	if(key == OF_KEY_LEFT) {
		simpleAmount += 1.0;
		if(simpleAmount > 100.0) simpleAmount = 100.0;
	}
	if(key == OF_KEY_RIGHT) {
		simpleAmount -= 1.0;
		if(simpleAmount < 1.0) simpleAmount = 1.0;
	}

	// big balls
	if(key == ' ') {
		float r = ofRandom(5, 15);
		CustomParticle p;
		// Mass Bounce Friction
		p.setPhysics(0.0001, 0.79, 0.01);
		p.setup(box2dCollision.getWorld(), mouseX, mouseY, r);
		p.c = (int)ofRandom(30, 100);
		customParticles.push_back(p);
	}

	// small balls
	if(key == 'b') {
		float r = ofRandom(3, 8);
		CustomParticle p;
		// Mass Bounce Friction
		p.setPhysics(0.0001, 0.73, 0.9);
		p.setup(box2dCollision.getWorld(), mouseX, mouseY, r);
		p.c = (int)ofRandom(100, 255); //(3, 255);
		customParticles.push_back(p);
	}
}

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

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
     drawingLine[drawingLine.size()-1].addPoint(x, y);
     drawingLine[drawingLine.size()-1].createShape();
  		    ofxBox2dLine l;
 			l.setWorld(box2dCollision.getWorld());
            l.addPoint(x, y);
            drawingLine.push_back(l);
}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
    if (button==2){ // 2 = Right Mouse Button, 1 = Center
        for(int i=0; i<drawingLine.size(); i++){
            drawingLine[i].clear();
        }
        drawingLine.clear();
    }
    if (button==0){
  		    ofxBox2dLine l;
 			l.setWorld(box2dCollision.getWorld());
            l.addPoint(x, y);
            drawingLine.push_back(l);
    }
}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button) {
     drawingLine[drawingLine.size()-1].addPoint(x, y);
     drawingLine[drawingLine.size()-1].createShape();
}

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

void testApp::blobOn( int x, int y, int id, int order ) {  }
void testApp::blobMoved( int x, int y, int id, int order ) {  }
void testApp::blobOff( int x, int y, int id, int order ) {  }
