#include "stdafx.h"
#include "general.h"
#include "StateAction.h"
#include "SimulationParams.h"

#include "policy.h"
#include "Simulation.h"


////////////////////////////////////////////////////////////
//class CSimulationManager implementation
CSimulationManager::CSimulationManager(CSimulationParams & SimParams,CPolicy & policy):
	m_Policy(policy),
	m_SimParams(SimParams),
	m_bLanesInitialized(false)
{
	//for debugging purposes
	for(int i = 0;i < NUM_OF_LANES;i++)
		for(int j = 0;j < SECONDS_IN_MINUTE*15/DELTA_T;j++)
		{
			m_resultsArr[i][j][0] = -2;
			m_resultsArr[i][j][1] = -2;
		}
	m_LanesArr.SetSize(NUM_OF_LANES );	
}

CSimulationManager::~CSimulationManager()
{
	for(int i = 0;i < NUM_OF_LANES ; i++)
	{
		delete m_LanesArr[i];
	}
		
}	
void CSimulationManager::Simulate(int numOfSeconds, bool bSaveResults /*=false*/)
{
	//func parameter changed to seconds
	
	//int numOfSeconds = numOfDays * SECONDS_IN_DAY;
	m_JuncConf.setConf(	C_NORTH_SOUTH_NORTH_EAST );//only to begin with
	m_JuncConf.setConf(	C_NORTH_SOUTH_NORTH_EAST );//to make prevConf equal to curConf
	CStateAction nextState;
	double immediateReward;
	int nextConfig;
	int WaitTimeArray[NUM_OF_LANES];
	int isActiveArr[NUM_OF_LANES];
	int NumOfCarsArray[NUM_OF_LANES];
	int saveInd = 0;
	//initializes junction with appropriate distribution values
	if (!m_bLanesInitialized)
		InitLanes();
	else
		UpdateLanes();
		ResetSimulation();
	for(m_SecsInDay = 0;m_SecsInDay < numOfSeconds;m_SecsInDay++)
	{
		//Cleaning the junction in end of day
		if((m_SecsInDay % SECONDS_IN_DAY)==0 )
		{
			ResetSimulation();
			m_CurrentState = GetNextSimState();
			continue;
		}
		if((m_SecsInDay % DELTA_T) == 0)  //DELTA_T is the time 
										  //in which we update 
										  //the simulation status				
		{
			//Each lane simulates incoming and outgoing traffic,
			//according to lane parameters and traffic
			//lights configuration.
			for(int i = 0;i < NUM_OF_LANES ;i++)
			{
				CLane* currLane = m_LanesArr[i];
				currLane->updateState();
				WaitTimeArray[i] = currLane->getTimeSinceLastGreen();
				NumOfCarsArray[i] = currLane->getNumOfCars();
				isActiveArr[i] = currLane->isLaneActive(m_JuncConf.getConf(),i+1 /*curr lanes */);
			}
			
			//The next state is computed (S').
			nextState = GetNextSimState();  
			//We compute R(S,A) for the previous (S,A)
			immediateReward = m_Policy.ComputeImReward(nextState,
						WaitTimeArray, NumOfCarsArray);
			
			//The epsilon-greedy policy returns A' fitting for S'.
			nextConfig = m_Policy.GetNextConfiguration(nextState ,
														WaitTimeArray);
			m_JuncConf.setConf(nextConfig);
			nextState.m_nNextConfig = nextConfig;
			//Q(S,A) is computed
			m_Policy.UpdateStateValues(m_CurrentState, nextState, immediateReward);
			m_CurrentState = nextState;
			if(m_SecsInDay > numOfSeconds - (MINUTES_TO_FILE*SECONDS_IN_MINUTE))
			if (bSaveResults)
				SaveResults(NumOfCarsArray,isActiveArr,m_CurrentState.m_nJunctionConfig, saveInd++ );
		}
		
	}
 	if (bSaveResults)
		SaveResultsToFile();
}

/*CStateAction CSimulationManager::GetNextSimState()
{
	CStateAction curState(m_JuncConf.getConf(), TimeOfDay());

	for(int i = 0;i < NUM_OF_LANES;i++)
		curState.m_NumOfCarsArray[i] = m_LanesArr[i]->getNumOfCars();
	return curState;
}*/

CStateAction CSimulationManager::GetNextSimState()
{
	int NumCarsNorth = m_LanesArr[0]->getNumOfCars() +
					   m_LanesArr[1]->getNumOfCars(); 	
	
	int NumCarsEast  = m_LanesArr[2]->getNumOfCars() +
					   m_LanesArr[3]->getNumOfCars();
	
	int NumCarsSouth = m_LanesArr[4]->getNumOfCars() +
					   m_LanesArr[5]->getNumOfCars(); 	

	int NumCarsWest  = m_LanesArr[6]->getNumOfCars() +
					   m_LanesArr[7]->getNumOfCars(); 	

	
	
	
	CStateAction curState(m_JuncConf.getConf(), NumCarsNorth,
						  NumCarsEast, NumCarsSouth, NumCarsWest
						  ,TimeOfDay());
						  
	curState.NormalizeTrafficValues();
	return curState;
		
		
}


eTimeOfDay CSimulationManager::TimeOfDay()
{
/*	if (m_SecsInDay < 25200) return MIDNIGHT_TO_DUSK;
	if (m_SecsInDay < 36000) return MORNING;
	if (m_SecsInDay < 57600) return DAY_TIME;
	if (m_SecsInDay < 72000) return AFTERNOON;
	if (m_SecsInDay < 86400) return NIGHT;
*/
	return MORNING;
}


void CSimulationManager::InitLanes()
{
	
	for(int i = 0;i < NUM_OF_LANES ; i++)
	{
		double lambda = m_SimParams.m_LaneArrivalArr[i];
		double depRate = m_SimParams.m_LaneDepartureArr[i];
		m_LanesArr[i] = new CLane(lambda, &m_JuncConf, depRate, i+1/*enum value of lane*/);
	}
	m_bLanesInitialized = true;
}
void CSimulationManager::UpdateLanes()
{
	
	for(int i = 0;i < NUM_OF_LANES ; i++)
	{
		
		
		double lambda = m_SimParams.m_LaneArrivalArr[i];
		double depRate = m_SimParams.m_LaneDepartureArr[i];
		m_LanesArr[i]->UpdateLaneParams(lambda, depRate);
		//m_LanesArr[i] = new CLane(lambda, &m_JuncConf, depRate, i+1/*enum value of lane*/);
	}

}

void CSimulationManager::SaveResults(int* NumOfCarsArray, int *isActiveArr, int conf, int ind)
{
	
	for(int i = 0;i < NUM_OF_LANES;i++)
	{
		if(isActiveArr[i] == 1)
		{
			m_resultsArr[i][ind][1] = NumOfCarsArray[i];
			m_resultsArr[i][ind][0] = -1;
		}
		else
		{
			m_resultsArr[i][ind][0] = NumOfCarsArray[i];
			m_resultsArr[i][ind][1] = -1;

		}
		m_resultsArr[NUM_OF_LANES][ind][0] = conf;
		m_resultsArr[NUM_OF_LANES][ind][1] = -1;

	}
}

void CSimulationManager::SaveResultsToFile()
{
	int *confArr = m_JuncConf.getConfArr();
#ifdef SARSA	
	FILE *f = fopen("d:\\C-s\\learning\\ramzor3\\traffic.txt" ,"w");
#endif
#ifdef DEFAULT
	FILE *f = fopen("d:\\C-s\\learning\\ramzor3\\default.txt","w");
#endif
#ifdef PROPORTION
	FILE *f = fopen("d:\\C-s\\learning\\ramzor3\\Prop.txt","w");
#endif
	
	for(int j = 0;j < SECONDS_IN_MINUTE*MINUTES_TO_FILE/DELTA_T;j++)
	{
		for(int i = 0;i < NUM_OF_LANES;i++)
		{
			if(m_resultsArr[i][j][0] == -1)//active
				fprintf(f,"%08d	", m_resultsArr[i][j][1]);
			else
				fprintf(f,"%d	", m_resultsArr[i][j][0]);
		}
		fprintf(f,"%d	", m_resultsArr[NUM_OF_LANES][j][0]);//print config.
		fprintf(f, "\n");
	}
	for(int i = 0;i < NUM_OF_LANES;i++)
	{
		fprintf(f,"%d	", m_LanesArr[i]->GetTimeActive());
	}
	fprintf(f, "\n");

	for(i = 0;i < (NUM_OF_CONFIGURATIONS - 1);i++)
	{
		fprintf(f,"%d	", confArr[i]);
	}

	fclose(f);
}
void CSimulationManager::ResetSimulation()
{
	for(int i = 0;i < NUM_OF_LANES;i++)
		m_LanesArr[i]->Reset();	
	m_JuncConf.Reset();
}