#include "cardManager.h"


// TODO : remove HU crap that doesn't work anyway...

//---------------------------
void cardManager::setup(string xmlFile){
	xmlCardBank = xmlFile;
	xml.setVerbose(true);
	
	loadFromXML();
	loadCardImages();
}	


//---------------------------
void cardManager::loadCardImages(){
	for (int i = 0; i < 52; i++){
		cardImages[i].loadImage("images/" + ofToString(i) + "_cards.png");
		printf("%i %i \n", cardImages[i].width, cardImages[i].height);
	}
	
}

//---------------------------
void cardManager::saveCardAs(card &theCard, int whichCard){
	if( whichCard <= 52 ){
		theCard.whichCard = whichCard;
		int index = whichCard -1;
		cardBank[index] = theCard;
		saveToXML(cardBank[index]);
	}
}

//---------------------------
bool cardManager::loadFromXML(){

	xml.loadFile(xmlCardBank);
	
	for(int i = 0; i < 52; i++){
		string whichCardStr = "card_"+ofToString(i+1);
		if( xml.tagExists(whichCardStr+":hu_1") ){
		
			cardBank[i].HuMoments.hu1 = xml.getValue(whichCardStr+":hu_1", 0.0) / 10000;
			cardBank[i].HuMoments.hu2 = xml.getValue(whichCardStr+":hu_2", 0.0) / 100000;
			cardBank[i].HuMoments.hu3 = xml.getValue(whichCardStr+":hu_3", 0.0) / 1000000;
			cardBank[i].HuMoments.hu4 = xml.getValue(whichCardStr+":hu_4", 0.0) /  10000000;
			cardBank[i].HuMoments.hu5 = xml.getValue(whichCardStr+":hu_5", 0.0) / 10000000;
			cardBank[i].HuMoments.hu6 = xml.getValue(whichCardStr+":hu_6", 0.0) / 10000000;
			cardBank[i].HuMoments.hu7 = xml.getValue(whichCardStr+":hu_7", 0.0) / 10000000;
			
			cardBank[i].whichCard = i + 1;
			cardBank[i].ptsSet = true;
			
			printf("card[%i] h1 is %f - which card %i \n", i, cardBank[i].HuMoments.hu1, cardBank[i].whichCard); 
			
		}
	}
}

//---------------------------
bool cardManager::saveToXML(card &theCard){	

		printf("Trying Saving card\n");	
		if(theCard.whichCard == -1)return false;
		printf("Saving card\n");

		string whichCardStr = "card_"+ofToString(theCard.whichCard);
		
		xml.setValue(whichCardStr+":hu_1", theCard.HuMoments.hu1 * 10000);
		xml.setValue(whichCardStr+":hu_2", theCard.HuMoments.hu2 * 100000);
		xml.setValue(whichCardStr+":hu_3", theCard.HuMoments.hu3 * 1000000);
		xml.setValue(whichCardStr+":hu_4", theCard.HuMoments.hu4 * 10000000);
		xml.setValue(whichCardStr+":hu_5", theCard.HuMoments.hu5 * 10000000);
		xml.setValue(whichCardStr+":hu_6", theCard.HuMoments.hu6 * 10000000);
		xml.setValue(whichCardStr+":hu_7", theCard.HuMoments.hu7 * 10000000);

		xml.saveFile(xmlCardBank);
}

//---------------------------
//void cardManager::resetCards(){
//	for(int i = 0; i < NUM_CARDS; i++){
//		cards[i].reset();
//	}
//}

//---------------------------
int cardManager::identifyCardSimple(card &theCard, float matchThresh){
	
	/*
	float smallestAmnt = 9999999;
	int smallestIndex  = -1;
	
	// zach changed from 52 to 13 just for a sec.
	for(int i = 0; i < 13; i++){
		if(!cardBank[i].ptsSet)continue;
	
		float diff = fabs(newCardBank[i].HuMoments.hu1 - theCard.HuMoments.hu1);
		
		if(diff < smallestAmnt ){
			smallestAmnt = diff;
			smallestIndex = i+1;
		}
	}
	
		
	theCard.diff = smallestAmnt*100000.0;
	theCard.whichCard = smallestIndex;		
	*/
	 return 0;
}


//---------------------------
int cardManager::identifyCardViaHu(card &theCard, float matchThresh){
	/*	
	for (int j = 0; j < 3; j++) {
	
		float smallestAmnt = 9999999;
		int smallestIndex  = -1;
		for(int i = 0; i < 52; i++){
			if(!cardBank[i].ptsSet)continue;
			
			//float diff = fabs(cardBank[i].HuMoments.hu1 - theCard.HuMoments.hu1);
			
			float diff = (float)returnShapeMatchFromOpencvMethod(newCardBank[i].HuMoments, theCard.HuMoments, j+1);
			printf("vs %i -- %f \n", i, (float)diff);
			
			if(diff < smallestAmnt ){
				smallestAmnt = diff;
				smallestIndex = i+1;
			}
		}
		
		theCard.whichCardHu[j] = smallestIndex;
		theCard.diffHu[j] = smallestAmnt;
	}
	//else theCard.whichCard = -1;
	*/
	return 0;
}


int cardManager::identifyCardViaPixels(card &theCard, cardImageSet &theCardImageSet){		
	
	
	theCard.whichCard  = -1; // unknown.
	
	float smallestAmnt = 9999999;
	int smallestIndex  = -1;
	float minDev = 0;
	
	for(int i = 0; i < 52; i++){
		
		// get the diff versus both upside down and right side up.
		// 
		
		if (theCard.bRedSuit	!= newCardBank[i].bRedSuit)				continue;
		if (theCard.bFaceCard	!= newCardBank[i].bFaceCard)			continue;
		
		unsigned char * pixelsMe			= theCardImageSet.thresholdedImage.getPixels();
		unsigned char * pixelsThem			= newCardBankImages[i].thresholdedImage.getPixels();
		unsigned char * pixelsThemFlipped	= newCardBankImages[i].thresholdedImageFlipped.getPixels();
		int totalPixelCount					= CARD_CV_W*CARD_CV_H;
		float diff = 0;
		float diff2 = 0;
		
		
		for (int j = 0; j < totalPixelCount; j++){
			diff	+= sqrt((pixelsMe[j] - pixelsThem[j])*(pixelsMe[j] - pixelsThem[j]));
			diff2	+= sqrt((pixelsMe[j] - pixelsThemFlipped[j])*(pixelsMe[j] - pixelsThemFlipped[j]));
		}
		
		/*
		for (int j = 0; j < totalPixelCount; j++){
			diff	+= pixelsMe[j] != pixelsThem[j] ? 1 : 0;        //sqrt((pixelsMe[j] - pixelsThem[j])*(pixelsMe[j] - pixelsThem[j]));
			diff2	+= pixelsMe[j] != pixelsThemFlipped[j] ? 1 : 0;		//sqrt((pixelsMe[j] - pixelsThemFlipped[j])*(pixelsMe[j] - pixelsThemFlipped[j]));
		}
		*/
		//diff /= (float)totalPixelCount;
		//diff2 /= (float)totalPixelCount;
		
		bool bFlippedLower = diff2 < diff ? true : false;
		
		float minDiff = MIN(diff, diff2);
		
		/*
		 std dev didn't prove valuable, really. 
		float stdDev = 0;
		for (int j = 0; j < totalPixelCount; j++){
			
			float diff = 0;
			if (bFlippedLower == false) diff = sqrt((pixelsMe[j] - pixelsThem[j])*(pixelsMe[j] - pixelsThem[j]));
			else diff = sqrt((pixelsMe[j] - pixelsThemFlipped[j])*(pixelsMe[j] - pixelsThemFlipped[j]));
				
				stdDev	+= (minDiff - diff)*(minDiff - diff);
			//else  stdDev	+= sqrt(powf((minDiff - (pixelsMe[j] - pixelsThemFlipped[j])*(pixelsMe[j] - pixelsThemFlipped[j])), 2));
		}
		
		stdDev /= (float)totalPixelCount;
		stdDev = sqrt(stdDev);
		//printf("%f \n", stdDev);
		 */
				
		if(minDiff < smallestAmnt ){
			smallestAmnt	= minDiff;
			smallestIndex	= i;
			minDev			= 0;
		}
		
		
	}
	
	printf("closest is %i, diff is %f, deviation %f \n", smallestIndex, smallestAmnt, minDev);

	theCard.whichCard = smallestIndex; // get the data in...
	

	return 0;
	
}

//---------------------------
void cardManager::draw(vector <card> &cards, float x, float y){
	glPushMatrix();
	glTranslatef(x, y, 0);
	
	ofEnableAlphaBlending();
	for(int i = 0; i < cards.size(); i++){
		if( cards[i].ptsSet ){
			
			ofSetColor(0, 100, 255);
			ofNoFill();
			ofBeginShape();
			ofVertex(cards[i].c[ cards[i].pta ].x, cards[i].c[ cards[i].pta ].y);
			ofVertex(cards[i].c[ cards[i].ptb ].x, cards[i].c[ cards[i].ptb ].y);
			ofVertex(cards[i].c[ cards[i].ptc ].x, cards[i].c[ cards[i].ptc ].y);
			ofVertex(cards[i].c[ cards[i].ptd ].x, cards[i].c[ cards[i].ptd ].y);
			ofEndShape(true);
			
			ofSetColor(255,255,0,200);
			ofFill();
			ofCircle(cards[i].c[ cards[i].pta ].x, cards[i].c[ cards[i].pta ].y, 10);
			ofCircle(cards[i].c[ cards[i].ptb ].x, cards[i].c[ cards[i].ptb ].y, 10);
			ofCircle(cards[i].c[ cards[i].ptc ].x, cards[i].c[ cards[i].ptc ].y, 10);
			ofCircle(cards[i].c[ cards[i].ptd ].x, cards[i].c[ cards[i].ptd ].y, 10);
			ofSetColor(0,0,0,255);
			ofDrawBitmapString("a",cards[i].c[ cards[i].pta ].x-3, cards[i].c[ cards[i].pta ].y);
			ofDrawBitmapString("b",cards[i].c[ cards[i].ptb ].x-3, cards[i].c[ cards[i].ptb ].y);
			ofDrawBitmapString("c",cards[i].c[ cards[i].ptc ].x-3, cards[i].c[ cards[i].ptc ].y);
			ofDrawBitmapString("d",cards[i].c[ cards[i].ptd ].x-3, cards[i].c[ cards[i].ptd ].y);
			
			
			if( cards[i].whichCard != -1 ){
				ofSetColor(20, 20, 160, 190);
				ofRect(cards[i].center.x-8, cards[i].center.y-12, 56, 23);
				ofSetColor(0x00FF00);	
				ofDrawBitmapString(ofToString(cards[i].id)+ " act: " + ofToString(cards[i].activity), cards[i].center.x - 4, cards[i].center.y + 2);
			}
			
			
			ofSetColor(0xffffff);
			if( cards[i].whichCard != -1 ){
				int who = cards[i].whichCard;
				newCardBankImages[who].cardImage.draw(640 + cards[i].center.x/2, 240+cards[i].center.y/2,32,40);
				//ofCircle(cards[i].center.x, cards[i].center.y, 40);
			}	
			
			// useful to toggle this drawin.g
			//cards[i].drawAnalysisResults(cards[i].center.x/2, cards[i].center.y/2);
			
			//				
			//				
			//				if( cards[i].whichCard != -1 ){
			//					ofSetColor(20, 20, 160, 190);
			//					ofRect(cards[i].center.x-8, cards[i].center.y-12, 56, 23);
			//					ofSetColor(0x00FF00);	
			//					ofDrawBitmapString(ofToString(cards[i].whichCard)+ " = " + ofToString(cards[i].getCard()) + " " + ofToString(cards[i].diff, 3), cards[i].center.x - 4, cards[i].center.y + 2);
			//				}
			//				
			//				for (int j = 0; j < 3; j++){
			//					if( cards[i].whichCardHu[j] != -1 ){
			//						ofSetColor(20, 20, 160, 190);
			//						ofRect(cards[i].center.x-8, cards[i].center.y-12 + (j+1)*15, 56, 23);
			//						ofSetColor(0x00FF00);	
			//						ofDrawBitmapString(ofToString(cards[i].whichCardHu[j]) + " " + ofToString(cards[i].diffHu[j]*10, 3), cards[i].center.x - 4, cards[i].center.y + 2 + (1+j)*15);
			//					}
			//				}
			//				
			//				// this should be a function, yikes: 
			//				
			//				ofSetColor(20, 20, 160, 190);
			//				ofRect(cards[i].center.x-8, cards[i].center.y-12 +60, 56, 23);
			//				ofSetColor(0x00FF00);	
			//				ofDrawBitmapString("pct white " + ofToString(cards[i].pctWhitePixels, 4), cards[i].center.x - 4, cards[i].center.y + 2 + 60);
			//									
			//				ofSetColor(20, 20, 160, 190);
			//				ofRect(cards[i].center.x-8, cards[i].center.y-12 +75, 56, 23);
			//				ofSetColor(0x00FF00);	
			//				ofDrawBitmapString( ofToString((int)cards[i].avgColor.x) + " " + ofToString((int)cards[i].avgColor.y) + " " + ofToString((int)cards[i].avgColor.z), cards[i].center.x - 4, cards[i].center.y + 2 + 75);
			//				
			//				ofSetColor(20, 20, 160, 190);
			//				ofRect(cards[i].center.x-8, cards[i].center.y-12 +90, 56, 23);
			//				ofSetColor(0x00FF00);	
			//				ofDrawBitmapString( cards[i].bFaceCard == true ? "face card" : "number card" , cards[i].center.x - 4, cards[i].center.y + 2 + 90);
			//				
			//				ofSetColor(20, 20, 160, 190);
			//				ofRect(cards[i].center.x-8, cards[i].center.y-12 +105, 56, 23);
			//				ofSetColor(0x00FF00);	
			//				ofDrawBitmapString( cards[i].bRedSuit == true ? "red card" : "black card (or face card)" , cards[i].center.x - 4, cards[i].center.y + 2 + 105);
			//				
			
		}
	}
	ofDisableAlphaBlending();		
	
	glPopMatrix();
}



  
//---------------------------
double cardManager::returnShapeMatchFromOpencvMethod( CvHuMoments &a, CvHuMoments &b, int method){
  
    double ma[7], mb[7];
    int i, sma, smb;
    double eps = 1.e-5;
    double mmm;
    double result = 0;
	
    ma[0] = a.hu1;
    ma[1] = a.hu2;
    ma[2] = a.hu3;
    ma[3] = a.hu4;
    ma[4] = a.hu5;
    ma[5] = a.hu6;
    ma[6] = a.hu7;
	

    mb[0] = b.hu1;
    mb[1] = b.hu2;
    mb[2] = b.hu3;
    mb[3] = b.hu4;
    mb[4] = b.hu5;
    mb[5] = b.hu6;
    mb[6] = b.hu7;
	
    switch (method)
    {
		case 1:
        {
            for( i = 0; i < 7; i++ )
            {
                double ama = fabs( ma[i] );
                double amb = fabs( mb[i] );
				
                if( ma[i] > 0 )
                    sma = 1;
                else if( ma[i] < 0 )
                    sma = -1;
                else
                    sma = 0;
                if( mb[i] > 0 )
                    smb = 1;
                else if( mb[i] < 0 )
                    smb = -1;
                else
                    smb = 0;
				
                if( ama > eps && amb > eps )
                {
                    ama = 1. / (sma * log10( ama ));
                    amb = 1. / (smb * log10( amb ));
                    result += fabs( -ama + amb );
                }
            }
            break;
        }
			
		case 2:
        {
            for( i = 0; i < 7; i++ )
            {
                double ama = fabs( ma[i] );
                double amb = fabs( mb[i] );
				
                if( ma[i] > 0 )
                    sma = 1;
                else if( ma[i] < 0 )
                    sma = -1;
                else
                    sma = 0;
                if( mb[i] > 0 )
                    smb = 1;
                else if( mb[i] < 0 )
                    smb = -1;
                else
                    smb = 0;
				
                if( ama > eps && amb > eps )
                {
                    ama = sma * log10( ama );
                    amb = smb * log10( amb );
                    result += fabs( -ama + amb );
                }
            }
            break;
        }
			
		case 3:
        {
            for( i = 0; i < 7; i++ )
            {
                double ama = fabs( ma[i] );
                double amb = fabs( mb[i] );
				
                if( ma[i] > 0 )
                    sma = 1;
                else if( ma[i] < 0 )
                    sma = -1;
                else
                    sma = 0;
                if( mb[i] > 0 )
                    smb = 1;
                else if( mb[i] < 0 )
                    smb = -1;
                else
                    smb = 0;
				
                if( ama > eps && amb > eps )
                {
                    ama = sma * log10( ama );
                    amb = smb * log10( amb );
                    mmm = fabs( (ama - amb) / ama );
                    if( result < mmm )
                        result = mmm;
                }
            }
            break;
        }
		default:
			return 0; // bad param you suck
    }
		
    return result;
}



