#pragma once

#define OF_ADDON_USING_OFXVECTORMATH
#define OF_ADDON_USING_OFXOPENCV

#include "ofMain.h"
#include "ofAddons.h"

#define CARD_CV_W 64
#define CARD_CV_H 80

#define CARD_CV_HIGHRES_W (64*3)
#define CARD_CV_HIGHRES_H (80*3)


#define MAX_TRACKED_CARDS		70			// something big 


//Not really using this at the moment
//but this is a basic representation of a card
class basicCard{
	public:
	void operator = (const basicCard &A){
		memcpy(this, &A, sizeof(basicCard));
	}

	//---------------------------------------------	
	basicCard(){
		reset();
	}

	//---------------------------------------------	
	void reset(){
		id			= -1;
		activity	= 20.0;
	
		pta	= ptb = ptc = ptd = 0;
		cached = false;
		bFirstFrameCached = true;
		
		angle = 0.0;
		
		for(int i = 0; i < 4; i++)c[i] = 0;
		
		center.x = 0;
		center.y = 0;
		center.z = 0;
	}

	//---------------------------------------------	
	void cache(){
		cached = true;
	}

	//---------------------------------------------	
	void uncache(){
		cached = false;
	}

	//---------------------------------------------
	void setPoints(ofxVec2f pt1, ofxVec2f pt2, ofxVec2f pt3, ofxVec2f pt4){
		c[0] = pt1;
		c[1] = pt2;
		c[2] = pt3;
		c[3] = pt4;
		
		ptsSet = true;
	}	
		
	//corner points
	ofxVec2f c[4];					//the points describing the four corners
	int pta;						//refers to the index of c[4] - once the points are found
	int ptb;						//pta -> ptd should be 0, 1, 2, 3
	int ptc;
	int ptd;
	bool ptsSet;					//have pts been set for this card
	
	//caching and blob tracking
	int id;							//the id of the card for blob tracking
	float activity;					//how much the card/blob is moving
	bool cached;					//are we are cached card?
	bool bFirstFrameCached;			// 

	//other
	ofxVec2f center;				//the center of the card
	float angle;					//angle of card	
		
};


//this card can have more properties
//images for drawing / comparing etc
class card : public basicCard{

	public:
	//---------------------------------------------
	void operator = (const card &A){
       memcpy(this, &A, sizeof(card));
    }	
	
	//---------------------------------------------	
	void operator = (const basicCard &A){
		for(int i = 0; i < 4; i++)c[i] = A.c[i];
		pta			= A.pta;
		ptb			= A.ptb;
		ptc			= A.ptc;
		ptd			= A.ptd;
		ptsSet		= A.ptsSet;
		cached		= A.cached;
		id			= A.id;
		activity	= A.activity;
		center		= A.center;
		angle		= A.angle;
	}	

	//---------------------------------------------
	card(){
		reset();
	}

	//---------------------------------------------
	int getSuit(){
		suit = whichCard / 13;
		return suit;
	}

	//---------------------------------------------
	int getCard(){
		cardNumber = (whichCard) % 13;
		return cardNumber;
	}
	
	//cards have a 16:9 ratio 
	//so we find the largest square
	//----------------------------------------------
	void computeSqPoints(){
			for(int i = 0; i < 4; i++)sqPts[i] = c[i];
			
			sqPts[0].x *= 0.85; 
			sqPts[0].x += 0.15 * c[3].x;
			sqPts[0].y *= 0.85; 
			sqPts[0].y += 0.15 * c[3].y;			 

			sqPts[1].x *= 0.85; 
			sqPts[1].x += 0.15 * c[2].x;
			sqPts[1].y *= 0.85; 
			sqPts[1].y += 0.15 * c[2].y;
			
			sqPts[2].x *= 0.85; 
			sqPts[2].x += 0.15 * c[1].x;
			sqPts[2].y *= 0.85; 
			sqPts[2].y += 0.15 * c[1].y;			 

			sqPts[3].x *= 0.85; 
			sqPts[3].x += 0.15 * c[0].x;
			sqPts[3].y *= 0.85; 
			sqPts[3].y += 0.15 * c[0].y;	
	}
	
	//------------------------------------------------------------------------------------------
	void drawAnalysisResults(int x, int y){
		
		// TODO: make this drawing much better, less hard constants, etc
		
		glPushMatrix();
		glTranslatef(x,y,0);
		
		ofSetColor(20, 20, 160, 190);
		ofRect(-8, -12 +60, 56, 23);
		ofSetColor(0x00FF00);	
		ofDrawBitmapString("pct edge white " + ofToString(pctEdgeDetectionWhite, 4),  - 4,  + 2 + 60);
		
		ofSetColor(20, 20, 160, 190);
		ofRect(-8, -12+90, 56, 23);
		ofSetColor(0x00FF00);	
		ofDrawBitmapString( bFaceCard == true ? "face card" : "number card" ,  - 4,  + 2 + 90);
		
		ofSetColor(20, 20, 160, 190);
		ofRect(-8, -12+105, 56, 23);
		ofSetColor(0x00FF00);	
		ofDrawBitmapString( bRedSuit == true ? "red" : "black" ,  - 4,  + 2 + 105);
		
		
		ofSetColor(20, 20, 160, 190);
		ofRect(-8, -12+130, 56, 23);
		ofSetColor(0x00FF00);	
		ofDrawBitmapString( "picture id: " + ofToString(pictureId) ,  - 4,  + 2 + 130);
		
		
		
		//ofDrawBitmapString( bRedSuit == true ? "red" : "black" ,  - 4,  + 2 + 105);
		
		//ofSetColor(avgColor.x, avgColor.y, avgColor.y);
		//ofRect(0,120,100,100);
		
		/*  n o t g o o d 
			glPushMatrix();
			glTranslatef(0, 120, 0);
				ofBeginShape();
					for (int i = 0; i < 256; i++){
						ofVertex(suitContour[i].x, suitContour[i].y);
					}
				ofEndShape();
			glPopMatrix();
		*/

		glPopMatrix();
		
	}
	
	
	//---------------------------------------------
	void reset(){
		
		basicCard::reset();
		
		energy			= 0;
		energySmoothed	= 0;
		
		pixelRatio	= 0.0;
		whichCard	= -1;
		suit		= -1;
		cardNumber	= -1;
		hu			= 0.0;
		
		assigned		= false;
		lastAliveTime	= 0;	
		birthTime		= 0;			
		speed			= 0;				
		prevPos			= 0;			
		movementVec		= 0;	
		
		angleVec		= 0;
		
		for(int i = 0; i < 4; i++)sqPts[i] = 0;						
		
		boundingRect.x = 0;
		boundingRect.y = 0;
		boundingRect.width = 0;
		boundingRect.height = 0;
		
		pctWhitePixels = 0;
		nonFaceCardBlobCount = 0;
		
		//for (int i = 0; i < 256; i++){
//			suitContour[i].set(-1,-1);	
//		}
		
		pictureId = -1;
	}

	//-------------------
	//-------------------
	
	//identification
	int		whichCard;				//which card is this? 0-52
	int		suit;					//which suit? 0-3
	int		cardNumber;				//which card 1-13
	
	//	note: this is stuff I use to cut down on comparisons, etc....  helps a great deal.
	//	computed in cvCardAnalysis. 
	
	int		nonFaceCardBlobCount;	// if I am not a face card, this is a count of my inner blobs
	bool	bFaceCard;				//is a face card?
	bool	bRedSuit;				//is red?
	
	
	int			pictureId;			// zach -- this is my id in the picture in the ARRAY, if = -1, I'm not in.
									// otherwise, should be between 0 and MAX_TRACKED_CARDS...
									// if the card tracker maxes out this is kept as -1 and that image is lost 
	
	//tracking stuff
	bool		assigned;			//whether or not the card has been matched
	long		lastAliveTime;		//when was the last time this card was seen
	long		birthTime;			//when was it born
	float		speed;				//how fast is it moving
	ofxPoint2f	prevPos;			//previous position
	ofxVec2f	movementVec;		//direction it is moving
	
	//pixel stuff
	float		pixelRatio;					//not sure
	float		pctWhitePixels;				//ratio of white to non white pixels
	ofPoint		avgColor;					//avg color of card?
	float		pctEdgeDetectionWhite;		// pct of EDGE pixels that are white, great for face card detection.
	
	//moments
	CvMoments Moments;				//all the moments
	CvHuMoments HuMoments;			//just the hu moments
	int whichCardHu[3];				//not sure
	float diffHu[3];				//not sure
	float hu;						//simple hu comparison
	
	ofxVec2f sqPts[4];				//points that represent the largest square inside the card
	
	ofxVec2f angleVec;				//the angle as a vector

	//other
	float	diff;					//not sure
	ofRectangle boundingRect;		//bounding box of card
	
	// zach my attempt at a 0-1 how "alive this card is"
	float energy;
	float energySmoothed;
	
				
};


class cardImageSet{
	
	public: 
	
	cardImageSet(){
		//BUG - fixed - four lines bellow were allocating the same image
		cardImage.allocate(CARD_CV_W, CARD_CV_H, OF_IMAGE_GRAYSCALE);
		cardImageFlipped.allocate(CARD_CV_W, CARD_CV_H, OF_IMAGE_GRAYSCALE);
		thresholdedImage.allocate(CARD_CV_W, CARD_CV_H, OF_IMAGE_GRAYSCALE);
		thresholdedImageFlipped.allocate(CARD_CV_W, CARD_CV_H, OF_IMAGE_GRAYSCALE);
		colorImageHighRes.allocate(CARD_CV_HIGHRES_W, CARD_CV_HIGHRES_H, OF_IMAGE_COLOR);
	
		for (int i = 0; i < 10; i++){
			colorImagesPlanes[i].allocate(CARD_CV_HIGHRES_W, CARD_CV_HIGHRES_H, OF_IMAGE_COLOR);
			boundingRectanges[i].x		= 0;
			boundingRectanges[i].y		= 0;
			boundingRectanges[i].width	= 0;
			boundingRectanges[i].height = 0;
			nPlanes						= 0;
		}
	}
	
	
	// I got some images in here too ! 

	ofImage cardImage;
	ofImage cardImageFlipped;
	ofImage thresholdedImage;
	ofImage thresholdedImageFlipped;
	
	ofImage colorImageHighRes;
	ofImage colorImagesPlanes[10];
	ofRectangle	boundingRectanges[10];
	int			nPlanes;
	
};



