#include "sonarScene.h"
#include "notes.h"

int pnpoly(int npol, ofPoint *pts, float x, float y);
int pnpoly(int npol, ofPoint *pts, float x, float y)
{
	int i, j, c = 0;
	for (i = 0, j = npol-1; i < npol; j = i++) {
        if ((((pts[i].y <= y) && (y < pts[j].y)) ||
             ((pts[j].y <= y) && (y < pts[i].y))) &&
            (x < (pts[j].x - pts[i].x) * (y - pts[i].y) / (pts[j].y - pts[i].y) + pts[i].x))
			c = !c;
	}
	return c;
}  // thanks paul bourke !! 

/*
bool pointInPolygon(float x, float y, vector<ofPoint>pts);
bool pointInPolygon(float x, float y, vector<ofPoint>pts)
{
	
	// code via Zach Lieberman via Randolph Franklin...
	int i, j, c = 0;
	int nPts = pts.size();
	
	for (i = 0, j = nPts-1; i < nPts; j = i++) {
		if ((((pts[i].y <= y) && (y < pts[j].y)) ||
			 ((pts[j].y <= y) && (y < pts[i].y))) &&
			(x < (pts[j].x - pts[i].x) * (y - pts[i].y) / (pts[j].y - pts[i].y) + pts[i].x))
			c = !c;
	}
	return (bool) c;
}
 */


//---------------------------------------
sonarScene::sonarScene(){

}

//---------------------------------------
void sonarScene::setupScene(){
	sceneName = "sonarScene";
	addAppListener();
	addMouseListener();
	addKeyboardListener();
	setAutoRender(true);
	
	
	angleOfScanner = 0;
	
	fakeMarker.setup(camW, camH, 60, true);
	hsvImg.loadImage("hsv.jpg");
	unsigned char * pixels = hsvImg.getPixels();
	for (int i = 0; i < 13; i++){
		//colors[i].set
		// gettt colors out: 
		
		int width = hsvImg.width;
		float div = (float)((float)width / 14.0f);
		unsigned char * pixcombo = pixels + (int)((div * i)*3);		
		colors[i].set(pixcombo[0], pixcombo[1], pixcombo[2]);
	}
	
	
	for (int i = 0; i < 70; i++){
		snds[i].loadSound("blip.wav");	
	}
	
}

//---------------------------------------
void sonarScene::render(){
	if( hide || pause ) return;
	
		
		glPushMatrix();		
		ofEnableAlphaBlending();
			for (int i = 0; i < feedback.size(); i++){
				
				
				
				// get the id of the responders
				int whichCard = feedback[i].whichCard % 13;
				if (whichCard < 0) whichCard = 0;
				float val = ofGetElapsedTimef() - feedback[i].startTime;
				
				if (val > 0.2f) val = 0.2f;
				float pct = val / 0.2f;
				
				fakeMarker.setMarkerPoints(feedback[i].sqPts[0], feedback[i].sqPts[1], feedback[i].sqPts[2], feedback[i].sqPts[3]);
				if( fakeMarker.isMarkerSet()){
					fakeMarker.loadARMatrix();
					ofSetRectMode(OF_RECTMODE_CENTER);
					glTranslatef(0, 0,  feedback[i].zVal);
					ofSetColor(colors[whichCard].x, colors[whichCard].y, colors[whichCard].z,  powf(pct, 1.3) * 140 * (1-(feedback[i].zVal/200.0f)));
					ofRect(0,0,60,90);
					ofSetRectMode(OF_RECTMODE_CORNER);

					fakeMarker.unloadARMatrix();
			
				}
			}	
		ofDisableAlphaBlending();
		glPopMatrix();		
			
	ofEnableAlphaBlending();
		
	//draw a circle for each card found
	if( planePtr->isMarkerSet()){
		planePtr->loadARMatrix();
		
				//glScalef(1,-1,1);
			
				ofSetColor(255,255,255);
				ofPoint pt;
				ofPoint ptb;	
				
				pt.set(320,240);
				pt = planePtr->screenToMarker(pt.x, pt.y);
				for (int i = 0; i < 20; i++){
					for (int j = 0; j < prevAnglesOfScanner.size(); j++){
						ptb.set(320 + i * 20 * cos(prevAnglesOfScanner[j]), 240 + i *20 * sin(prevAnglesOfScanner[j]));
						ptb = planePtr->screenToMarker(ptb.x, ptb.y);
						glPushMatrix();
							ofSetColor(180, 180, 255, 100 * (1- powf(((float)i/20.0f), 1.5f)) - 90 * (1-(j/10.0f)));
							glTranslatef(0, 0, 30);
						ofCircle(ptb.x, ptb.y, (5 - 2 * (1-(j/10.0f))) * (1- powf(((float)i/20.0f), 1.5f)) );
						glPopMatrix();
					}
				}
		
				glTranslatef(0,	0, 0);
				//ofLine(pt.x, pt.y,ptb.x, ptb.y);
						
			
		
		planePtr->unloadARMatrix();
		
		
		
	}
	
	//show the plane points we are marking out
	if(recordingPts){
		ofNoFill();
			ofSetColor(255, 0, 130);
			ofBeginShape();
				for(int i = 0; i < whichPt; i++){
					ofVertex(planePts[i].x, planePts[i].y);
				}
			ofEndShape(false);
			for(int i = 0; i < whichPt; i++){
				ofCircle(planePts[i].x, planePts[i].y, 4);
			}
		ofFill();
	}
	
	//show our debug text
	if(debug){
		//drawTxtMsg("scene is: "+sceneName, 0, camH - 40);
		//drawDebugTxt(0, camH - 20);	
	}

}

//---------------------------------------
void sonarScene::update(){
	
		if( pause ) return;
	
	float speedm = 10.5 * ( 1.0 / ofGetFrameRate());
	
	
	float prevAngle = angleOfScanner;
	angleOfScanner += ((float)(mx-320.0f)/640.0f) * 0.2f * speedm;
	
	//if (angleOfScanner > TWO_PI) angleOfScanner -= TWO_PI;
	
	if (prevAnglesOfScanner.size() == 0){
		for (int i = 0; i < 10; i++) prevAnglesOfScanner.push_back(prevAngle);
	} else {
			prevAnglesOfScanner.erase(prevAnglesOfScanner.begin());
			prevAnglesOfScanner.push_back(prevAngle);
		
	}
	

	for (int i = 0; i < responders.size(); i++){
		responders[i].bMatchedThisFrame = false;
	}
	
	if (allCards.size() > 0){
		
		for (int i = 0; i < allCards.size(); i++){
			int id = allCards[i].id;
			bool bAnyMatch = false;
			for (int j = 0; j < responders.size(); j++){
				
				if (responders[j].id == id){
					responders[j].bMatchedThisFrame = true;
					responders[j].energy			= allCards[i].energySmoothed;
					
					for (int k = 0; k < 4; k++){
						responders[j].cornerPts[k] = allCards[i].c[k];
						responders[j].sqPts[k] = allCards[i].sqPts[k];
					}
					responders[j].center.x				= allCards[i].center.x;
					responders[j].center.y				= allCards[i].center.y;
					responders[j].whichCard				= allCards[i].whichCard;
				
					bAnyMatch = true;
					break;
				}				
			}
			
			if (!bAnyMatch){
				
				sonarResponder responder;
				responder.id					= allCards[i].id;
				responder.energy				= allCards[i].energySmoothed;
				responder.center.x				= allCards[i].center.x;
				responder.center.y				= allCards[i].center.y;
				responder.whichCard				= allCards[i].whichCard;
				
				for (int j = 0; j < 4; j++){
					responder.cornerPts[j] = allCards[i].c[j];
					responder.sqPts[j] = allCards[i].sqPts[j];
				}
				
				responder.hitEnergy				= 0;
				responder.hitEnergyTarget		= 0;
				responder.bMatchedThisFrame		= true;
				responders.push_back(responder);
				
			}
		}
	}
	
	
	vector <int> eraseList;
	eraseList.clear();
	
	//we do it in reverse order so when we erase from the list it doesn't mess up the other indexes
	for(int j = responders.size()-1; j >= 0; j--){
		if( responders[j].bMatchedThisFrame == false){		
			printf("deleting \n");
			eraseList.push_back(j);
		}
	}
	
	//now kill the old stored cards
	for(int j = 0; j < eraseList.size(); j++){
		responders.erase(responders.begin() + eraseList[j]);
	}
	
	eraseList.clear();
	
	for(int i = 0; i < responders.size(); i++){
		responders[i].update();
	}
	
	
	// ----------------------------------- check hits
	if( responders.size() > 0){
			
			
			for(int j = 0; j < responders.size(); j++){
				
				bool bAnyHit = false;
				bool bOnCenter = false;
				printf("here --- checking \n");
				for (int i = 0; i < 80; i++){
					
					ofPoint ptToCheck;
					ptToCheck.x = 320 + ((float)i/80.0f)*800.0f*cos(angleOfScanner);
					ptToCheck.y = 240 + ((float)i/80.0f)*800.0f*sin(angleOfScanner);
					
					if (pnpoly(4, responders[j].cornerPts, ptToCheck.x, ptToCheck.y)){
						bAnyHit = true;
						printf("hit \n");
						if (i == 0){
							bOnCenter = true;
						}
					}
				}
				
				if (!bOnCenter){
					if (bAnyHit == true ){
						
						float diffTime = ofGetElapsedTimef() - responders[j].endTime;
						if (diffTime > 0.1f){
							if (responders[j].hitEnergyTarget < 1){
								printf("note on \n");
								// start midi note
								int theChannel =2;
								
								float pitch	 =  (float)(responders[j].whichCard % 13) / 13.1;
								float pitchNote	= pitch;
								pitchNote *= NUM_NOTES;
								int currentNote = notes[(int)pitchNote];
								
								midi.sendNoteOn(theChannel, currentNote, responders[j].energy * 100);
								
								responders[j].startPlayback();
								
								feedback.push_back(responders[j]);
								responders[j].hitEnergyTarget = 1; // center ones cause trouble and are always on...
								
								/*static int counterPlay = 0;
								counterPlay++;
								counterPlay %= 70;
								snds[counterPlay].setVolume(0.3f);
								snds[counterPlay].setSpeed(1 + 0.1f + pitch);
								snds[counterPlay].play();*/
							}
							
							
						}
					} else {
						
						if (responders[j].hitEnergyTarget > 0){
								
								responders[j].endTime = ofGetElapsedTimef();
							
								printf("note off \n");
								//responders[j].hitEnergy				= 0;

								int theChannel = 2;
								float pitch	 =  (float)(responders[j].whichCard % 13) / 13.1;
								pitch		*= NUM_NOTES;
								int currentNote = notes[(int)pitch];
								
								midi.sendNoteOff(theChannel, currentNote,  responders[j].energy * 100);
								
								responders[j].hitEnergyTarget = 0;
						}
						
						
						
						
					}
				}

			}
	}
	
	
	
	for(int i = 0; i < feedback.size(); i++){
		feedback[i].update();
	}
	
	eraseList.clear();
	
	//we do it in reverse order so when we erase from the list it doesn't mess up the other indexes
	for(int j = feedback.size()-1; j >= 0; j--){
		if( feedback[j].zVal > 198){		
			eraseList.push_back(j);
		}
	}
	
	//now kill the old stored cards
	for(int j = 0; j < eraseList.size(); j++){
		feedback.erase(feedback.begin() + eraseList[j]);
	}
	
	
}

//---------------------------------------		
void sonarScene::keyPressed( int key ){
	if( pause ) return;
}

//---------------------------------------
void sonarScene::keyReleased( int key ){
	if( pause ) return;

}
	
//---------------------------------------
void sonarScene::mouseMoved(int x, int y ){
	if( pause ) return;
	
	
	mx = x;
	my = y;

}

//---------------------------------------
void sonarScene::mouseDragged( int x, int y, int button ){
	if( pause ) return;

}

//---------------------------------------
void sonarScene::mousePressed( int x, int y, int button ){
	if( pause ) return;


}

//---------------------------------------
void sonarScene::mouseReleased(int x, int y, int button ){
	if( pause ) return;
	

}	

