#ifndef __SIMULATION_H
#define __SIMULATION_H

enum eLanes
{
	L_NORTH_SOUTH = 1,
	L_NORTH_EAST, //2
	L_EAST_WEST,  //3	
	L_EAST_SOUTH, //4 
	L_SOUTH_NORTH,//5
	L_SOUTH_WEST, //6
	L_WEST_EAST,  //7
	L_WEST_NORTH  //8
};

enum eConfiguration
{
	
	C_NORTH_SOUTH_NORTH_EAST = 1,//lanes 1,2
	C_NORTH_SOUTH_SOUTH_NORTH,	 //lanes 1,5
	C_NORTH_EAST_SOUTH_WEST,	 //lanes 2,6
	C_EAST_WEST_WEST_EAST,		 //lanes 3,7
	C_EAST_WEST_EAST_SOUTH,		 //lanes 3,4
	C_EAST_SOUTH_WEST_NORTH,	 //lanes 4,8
	C_SOUTH_NORTH_SOUTH_WEST,	 //lanes 5,6
	C_WEST_EAST_WEST_NORTH,		 //lanes 7,8
	NUM_OF_CONFIGURATIONS

};
enum eTimeOfDay
{
	MIDNIGHT_TO_DUSK,
	MORNING,
	DAY_TIME,
	AFTERNOON,
	NIGHT
};


class CJuncConfiguration;
class CCarDistribution;
class CPolicy;
/////////////////////////////////////////////////////////////////
//class CCarDistribution
class CCarDistribution
{
private:
	double m_Lambda;
	UINT m_ProbabilitiesArray[MAX_NUM_OF_CARS_PER_DELTA_T+1];
public:
	CCarDistribution(){}  //should never be used
	CCarDistribution(double lambda);
	int  numOfCarsAdded();
	void setLambda(double l) {m_Lambda = l; }
};

//////////////////////////////////////////////////////////////////
//class CLane

class CLane
{
private:
	
	int m_Lane;          //direction of arrival and departure fron junction 
	int    m_NumOfCars;     //in lane
	int	   m_NumOfCarsSoFar;	//num of cars that left the junction
	double m_DepartureRate; //num of cars leaving per second when light is green
	CJuncConfiguration* m_JuncConfiguration;
	CCarDistribution    m_CarDistribution;
	int  m_TimeSinceLastGreen;
	int  m_TimeActive;
public:
	CLane(){}  //should never be used
	CLane(double lambda, CJuncConfiguration* juncConf, double depRate, int lane);
	void updateState();
	void UpdateLaneParams(double l, double depRate){m_CarDistribution.setLambda(l); m_DepartureRate = depRate;}
	void setLambda (double l){m_CarDistribution.setLambda(l);}
	int  getNumOfCars () {return m_NumOfCars;}
	int  getNumOfCarsSoFar () {return m_NumOfCarsSoFar;}
	int  getTimeSinceLastGreen() {return m_TimeSinceLastGreen;}
	void Reset(){m_NumOfCars = 0; m_TimeSinceLastGreen = 0; m_TimeActive = 0;}
	//static as it is used by the CSarsaPolicy class.
	static bool isLaneActive(int conf,int lane);
	int GetTimeActive(){return m_TimeActive;}

};

//////////////////////////////////////////////////////////////
//class CJuncConfiguration

class CJuncConfiguration
{
private:
	int m_CurrConf;
	int m_PrevConf;
	int m_confArr[NUM_OF_CONFIGURATIONS - 1];
	//NUM_OF_CONFIGURATIONS is actualy (num of configurations + 1)
	//CPolicy & m_Policy;
public:
	CJuncConfiguration();
	void setConf(int conf);
	int getConf(){return m_CurrConf;}
	int getPrevConf(){return m_PrevConf;}
	int *getConfArr(){return m_confArr;}
	void Reset();
	bool   HasConfChanged() {return (!(m_PrevConf == m_CurrConf));} 
	//void UpdateConf();

};

//////////////////////////////////////////////////////////////
//class CSimulationManager

class CSimulationManager
{
private:
	CJuncConfiguration m_JuncConf;
	CArray<CLane*,CLane*> m_LanesArr;
	CSimulationParams & m_SimParams;
	CPolicy&  m_Policy;
	CStateAction  m_CurrentState;
	int m_SecsInDay;	//seconds so far in the day
	eTimeOfDay TimeOfDay();
	void InitLanes();
	void UpdateLanes();
	bool m_bLanesInitialized;
	int m_resultsArr[NUM_OF_LANES+1][SECONDS_IN_MINUTE*MINUTES_TO_FILE/DELTA_T ][2];
	void SaveResults(int* NumOfCarsArray, int *isActiveArr, int conf, int ind);
	void SaveResultsToFile();
public:
	CSimulationManager(CSimulationParams& SimParams, CPolicy&  policy);
	~CSimulationManager();
	void Simulate(int numOfSeconds, bool bSaveResults =false);
	int getSeconds(){return m_SecsInDay;}
	CStateAction GetNextSimState(); 
	void ResetSimulation();
	//	int getHour();

};


#endif