#include <stdlib.h>
#include <iostream>
#include <math.h>
#include "Town.h"
#include <ctime>
#include <cstdlib>
#include "Group.h"


//Default Town Constructor
Town::Town()
{

}

/*
Precondition: The parameters are initialized within the following constraints: 
1 <=  number_bars <= 255 and 1<= population <=16348 (2^14) and user_cap is the 
array for the capacity for each bar ( whose size may exceed the population.)
Postcondition: Barnums array and people array initialized as well as STM array
which keeps track which bar has won.
Description: Town Constructor which creates the Bars and Agents using inputted 
parameters by the createBars() and createAgents() functions
*/
Town::Town(int population,int user_cap,bool isPercent,int _avgAge,int dropValue,int grpsize) 
{
		avgAge = _avgAge;
		drop = dropValue;
		numAgents = population;
		numGrps = grpsize;
		
		STM=new int[3];
		grouperPercent = user_cap;
		STM[0] = 0;
		STM[1] = 0;
		STM[2] = 0;
		agentPter = (Agent **)malloc(sizeof(Agent)*population);	//new
		groupPter = (Group **)malloc(sizeof(Group)*grpsize);       //*******************************************
		
		srand((unsigned)time(0));
		createGroups(grpsize);
		createAgents(population);								//new
		passGraph = new struct pass_graph;							//¸ÄÃû
	
}
//
//void Town::createAgents(int population)		//new
//{
//
void Town::createGroups(int numGrps)
{
	for(int i=0;i<numGrps;i++)
	{
		groupPter[i] = new Group;
	}
}



void Town::createAgents(int numAgents)
{
	int tmpRandValue;
	int cntGrouper = 0;
	if(avgAge == -1)	//without mortality
	{
		for(int i=0;i<numAgents;i++)
		{
			agentPter[i] = new Agent;
			
			//tmpRandValue = rand()%2;
			//if (tmpRandValue == 1)
			//if (rand()%2 == 1)
			//if (rand()%(int)(100/grouperPercent) == 1)
			if(rand()%100 < grouperPercent && (cntGrouper < numAgents*grouperPercent/100))
			{
				agentPter[i]->allocateGroup(numGrps);
				groupPter[agentPter[i]->getGroupIndex()]->addAgent(i);
				cntGrouper++;
			}
			else
				agentPter[i]->setGroupIndex(-1);
			//if(1);
		}
	}
	else				//with mortality
	{
		for(int i=0;i<numAgents;i++)
		{
			agentPter[i] = new Agent(avgAge,drop);
			//if (rand()%2 == 1)
			if(rand()%100 < grouperPercent && (cntGrouper < numAgents*grouperPercent/100))
			{
				agentPter[i]->allocateGroup(numGrps);
				groupPter[agentPter[i]->getGroupIndex()]->addAgent(i);
				cntGrouper++;
			}
			else
				agentPter[i]->setGroupIndex(-1);
			//if(1);
		}
	}
	
}


	
/* Precondition: Input parameters have been passed from the GUI and have initialized all appropriate instances.
Postcondition: One turn has passed, all parameters have been updated and recorded.
Description: One turn is simulated when turn() is run.
*/
graphPtr Town::turn() 
{
		STI = STM[0] + STM[1]*2 + STM[2]*4;	
		
		//
		int cntGrouper = 1;
		int tmpGrouperCapSum = 0;
		int tmpNonGrouperCapSum = 0;
		//int* a;
		int i;
		int tmpCountWinner = 0;
		int numGo = 0;	//number of agents going to bar
		int result;
		int tmpStratScoreSum = 0;
		int tmpBestStratScore = 0;
		//
		for(i=0;i<101;i++)
		{
			passGraph->age[i]=0;	
		}
		//
		for(int i=0;i<numAgents;i++)
		{
			agentPter[i]->makeOwnDecision(STI);
			
		}
		//
		if (grouperPercent != 0)
		{
		int max;
		int demaciya;
		int fake_broadcasting;
		max = agentPter[0]->getCapital();
		for (int i=0;i<numAgents;i++)
		{
			if(agentPter[i]->getCapital() > max)
			{
				max=agentPter[i]->getCapital();
				demaciya = i;
			}
		}
		
		if (rand()%10<2)//broadcasting*************************************
		{
			if (rand()%10 < 5)
		{
			if (agentPter[demaciya]->getDecision() == 1)
				fake_broadcasting = 0;
			else 
				fake_broadcasting = 1;

		}
		else
			fake_broadcasting = agentPter[demaciya]->getDecision();
		for (int i=0;i<numAgents;i++)
			if (agentPter[i]->getDecision() != fake_broadcasting)
			{
				if (rand()%10 < 6)
					agentPter[i]->setDecision(fake_broadcasting);
			}
		}
		else
		/****************group decision***********************************************/
		{
			for(int i=0;i<numGrps;i++)
			{
				groupPter[i]->makeDecision(agentPter);     //******************************************definiton
			}
		
			for(int i=0;i<numAgents;i++)
			{	
				if (agentPter[i]->getGroupIndex() != -1)
				{
					if (rand()%10 < 1) //cheatingggggggggggggggggggggggg
					{
					if (agentPter[i]->getDecision() != groupPter[agentPter[i]->getGroupIndex()]->cheat_choice)
						{
							if (agentPter[i]->getCapital() < groupPter[agentPter[i]->getGroupIndex()]->avg_capital)
							agentPter[i]->setDecision(groupPter[agentPter[i]->getGroupIndex()]->cheat_choice);		
						}
					}
					else if (agentPter[i]->getDecision() != groupPter[agentPter[i]->getGroupIndex()]->group_choice)
					{
						if (agentPter[i]->getCapital() < groupPter[agentPter[i]->getGroupIndex()]->avg_capital)
						agentPter[i]->setDecision(groupPter[agentPter[i]->getGroupIndex()]->group_choice);
					}
				}
			}
		}
}
		/*****************************************************************************/
		//count number of agents going to bar
		for(int i=0;i<numAgents;i++)
		{
			numGo += agentPter[i]->getDecision();
		}
		//if(numGo > (int)(((float)winPercent/100.0)*numAgents))
		if(numGo > (numAgents/2))
		{
			result = 0;	//not go win
			passGraph->numWinners = numAgents - numGo;
		} 
		else
		{
			result = 1;	//go win
			passGraph->numWinners = numGo;
		}
		//give the result to agents. Agents update their capital and strategy scores
		for(int i=0;i<numAgents;i++)
		{
			agentPter[i]->tellResult(result,STI);
			tmpStratScoreSum += agentPter[i]->getAvgStratScore();
			if(agentPter[i]->getBestStratScore() > tmpBestStratScore)
			{
				tmpBestStratScore = agentPter[i]->getBestStratScore();
			}
			//test
			if(agentPter[i]->getGroupIndex() != -1)
			{
				cntGrouper++;
				tmpGrouperCapSum += agentPter[i]->getCapital();
			}
			else
				tmpNonGrouperCapSum += agentPter[i]->getCapital();
			//test
		}
		//calculate avgCapital of groupers and nongroupers
		tmpGrouperCapSum = tmpGrouperCapSum/cntGrouper;
		tmpNonGrouperCapSum = tmpNonGrouperCapSum / (numAgents - cntGrouper);

		passGraph->grouperAdvantage = tmpGrouperCapSum - tmpNonGrouperCapSum;
		if(numGrps == 1)
			passGraph->grouperAdvantage =0;
		//update and shift STM
		STM[2] = STM[1];
		STM[1] = STM[0];
		STM[0] = result;
				
		if(avgAge != -1)
			popControl();
		else
			passGraph->deaths = 0;
			
		passGraph->avgStratScore = (double)tmpStratScoreSum/numAgents;
		passGraph->bestStratScore = (double)tmpBestStratScore;
		return passGraph;
	}


void Town::popControl()
{
	int tmpCount = 0;	
	for(int i=0;i<numAgents;i++)
		{
			if(!agentPter[i]->aging())	//if return value ==0, the agent is replaced
			{
				agentPter[i] = new Agent(avgAge,drop);
				tmpCount++;
			}
			passGraph->age[agentPter[i]->getAge()]++;
			passGraph->deaths = tmpCount;
		}
}

/*
Town::~Town()
{
	int i;
	for(i=0;i<numbars;i++)
	{
		delete barnums[i];
	}
	free(barnums);
	free(topStrats);
	//new
	free(agentPter);
}*/

Town::~Town()
{
	free(agentPter);
	free(groupPter);	//´ýÌí¼Ó
}

