#include "cardTracker.h"

//-------------------------------------------
cardTracker::cardTracker(){
}

//-------------------------------------------
cardTracker::~cardTracker(){
	storedCards.clear();
}

//-------------------------------------------
void cardTracker::setup(int timeToLiveMs){
	storedCards.clear();
	
	numStoredCards	= 0;
	genID			= 0;
	lastTime		= 0;
	deathTime		= timeToLiveMs;
	
	for (int i = 0; i < MAX_TRACKED_CARDS; i++){
		pictureIdInUse[i] = false;
	}
	
}

//-------------------------------------------
void cardTracker::resetCounter(){
	genID = 0;
	storedCards.clear();
}

//-------------------------------------------
void cardTracker::begin(){
	for(int j = 0; j < storedCards.size(); j++){
		storedCards[j].assigned = false;
	}
}

//-------------------------------------------
void cardTracker::updateCardEnergyLevels(){
	for(int j = 0; j < storedCards.size(); j++){
		if (storedCards[j].assigned == true){
			storedCards[j].energy += 0.07f;
			if (storedCards[j].energy > 1) storedCards[j].energy = 1;
		} else {
			storedCards[j].energy -= 0.07;
			if (storedCards[j].energy < 0) storedCards[j].energy = 0;
		}
		storedCards[j].energySmoothed = 0.9f * storedCards[j].energySmoothed  + 0.1f * storedCards[j].energy;
	}	
}



//-------------------------------------------
void cardTracker::end(){
	if(storedCards.size() <= 0)return;

	int timeMillis = ofGetElapsedTimeMillis();
	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 = storedCards.size()-1; j >= 0; j--){
		if( storedCards[j].assigned )storedCards[j].lastAliveTime = timeMillis;
		else if( timeMillis - storedCards[j].lastAliveTime > deathTime ){
			
			// reset the pictureId = so other can get there picture taken :)
			int oldPictureId = storedCards[j].pictureId;
			if (oldPictureId != -1){
				pictureIdInUse[oldPictureId] = false;
			} else {
				printf("error in killing the card - picture ID \n");	
			}
			
			eraseList.push_back(j);
		}
	}
	
	//now kill the old stored cards
	for(int j = 0; j < eraseList.size(); j++){
		printf("deleting card %i \n", storedCards[j].id);
		storedCards.erase(storedCards.begin() + eraseList[j]);
	}
	
	numStoredCards = storedCards.size();
	if( numStoredCards == 0)resetCounter();
	
	updateCardEnergyLevels(); // do the energy thing
}

//call this when you want to update the card with the data in the cache
//-----------------------------------------
bool cardTracker::updateCardWithCache(card & cardIn){
	for(int i = 0; i < storedCards.size(); i++){
		if( cardIn.id == storedCards[i].id ){
			cardIn = storedCards[i];
			if (storedCards[i].bFirstFrameCached == true){
				storedCards[i].bFirstFrameCached = false;
			}
			return true;
		}	
	}
	return false;
}

//call this when you want to update the cache with the data in the card
//-----------------------------------------
bool cardTracker::updateCacheWithCard(card & cardIn){
	for(int i = 0; i < storedCards.size(); i++){
		if( cardIn.id == storedCards[i].id ){
			int pictureId = storedCards[i].pictureId;  // this gets lost, let's not loose it
			storedCards[i] = cardIn;
			storedCards[i].pictureId = pictureId;
			cardIn.pictureId = pictureId;
			storedCards[i].bFirstFrameCached = true;
			return true;
		}	
	}
	return false;
}


//------------------------------------------
int cardTracker::getTrackedCardPictureId(card &cardIn){
	for(int i = 0; i < storedCards.size(); i++){
		if( cardIn.id == storedCards[i].id ){
			int pictureId = storedCards[i].pictureId;  // this gets lost, let's not loose it...
			return pictureId;
		}	
	}
	return -1;
}

//------------------------------------------
int cardTracker::addCard(card & cardIn){
		
		// get a picture ID or bail 
	
		int pictureId = -1;
		for (int i = 0; i < MAX_TRACKED_CARDS; i++){
			if ( pictureIdInUse[i] == false){
				pictureIdInUse[i] = true;
				pictureId = i;
				break;
				
			}
		}
		
		if (pictureId == -1){
			// what do we do?
			printf("=================== ERROR w/ picture id ================= \n");
		}
		
		//printf("%i \n", pictureId);
	
		cardIn.pictureId		= pictureId;
		cardIn.id				= genID;
		cardIn.birthTime		= ofGetElapsedTimeMillis();
		cardIn.lastAliveTime	= cardIn.birthTime;
		cardIn.assigned			= true;	
		cardIn.activity			= 20;
		storedCards.push_back(cardIn);	 			

		genID++;
		return cardIn.id;		
}		

//------------------------------------------
bool cardTracker::matchTrackedCard(card & cardIn, int maxDist, float activityThresh, float cacheRate){
		
		float shortestDistance 	= 99999999;
		int tmpID				= -1;
		int which 				= -1;
		bool found 				= false;
		float speed 			= 0.0;
		ofxVec2f dist;
				
		for(int j = 0; j < storedCards.size(); j++){
			if( storedCards[j].assigned )continue;
				
			dist.set(cardIn.center.x - storedCards[j].center.x, cardIn.center.y - storedCards[j].center.y);
			float len = dist.length();

			if(len < maxDist && len < shortestDistance){
				shortestDistance = len;
				tmpID = storedCards[j].id;	
				found = true;
				which = j;	
				
				//this is so we don't update speed if it is a tiny amount
				if( len > activityThresh ) speed = len;
				else speed = 0.0;
			}
		}
								
		if(found){
			//if we have found our card 
			//then we fist update the cached card with the new stuff 
			//it needs then we copy the cached card to our current card
			
			//this says we found a card - so that it shouldn't be killed :)
			storedCards[which].assigned = true;		
			
			storedCards[which].activity += speed;
			if(storedCards[which].activity < 0.001){
				storedCards[which].activity = 0.0;
			}
			else{
				//this should be contrable
				//and maybe based on frame rate
				storedCards[which].activity *= cacheRate;
			}
			
			//okay because some data will need to be new if we are 
			//not a cached card - we just compute the activity and assign the id
			//so we know which previous card we belong to. 
			cardIn.activity			= storedCards[which].activity;
			cardIn.id				= storedCards[which].id;
			cardIn.assigned			= true;
			
			//we then can call updateCardWithCache
			//if the card is cached - this copies the cached data to our card
			
			//commented out - finally update our passed in card with the cached card
			//cardIn = storedCards[which];	
				
			return true;
		}
		
		return false;
}		
