#include "stdafx.h"
#include "general.h"
#include "SimulationParams.h"
#include "Simulation.h"
#include <math.h>
#include <stdlib.h>
#include <time.h>

int Product(int i) //Atzeret
{
	int ans = 1;
	for (int j = 2; j <= i; j++)
	{
		ans = ans*j;
	}
	return ans;
}

///////////////////////////////////////////////////////////
//class CLane implementation

CLane::CLane(double lambda, CJuncConfiguration* juncConf, double depRate, int lane):
m_CarDistribution(lambda),
m_JuncConfiguration(juncConf), 
m_DepartureRate(depRate),
m_Lane(lane),
m_NumOfCars(0),
m_NumOfCarsSoFar(0),
m_TimeSinceLastGreen(0),
m_TimeActive(0)
{}

bool CLane::isLaneActive(int conf,int lane)
{
	bool ans = false;

	switch(lane)
	{
	case L_NORTH_SOUTH :
		ans = ((conf == C_NORTH_SOUTH_NORTH_EAST) || 
		      (conf == C_NORTH_SOUTH_SOUTH_NORTH));
		break;
	case L_NORTH_EAST :
		ans = ((conf == C_NORTH_SOUTH_NORTH_EAST) || 
		      (conf == C_NORTH_EAST_SOUTH_WEST));
		break;
	case L_EAST_WEST :
		ans = ((conf == C_EAST_WEST_WEST_EAST) || 
		      (conf == C_EAST_WEST_EAST_SOUTH));
		break;
	case L_EAST_SOUTH:
		ans = ((conf == C_EAST_WEST_EAST_SOUTH) || 
		      (conf == C_EAST_SOUTH_WEST_NORTH));
		break;
	case L_SOUTH_NORTH:
		ans = ((conf == C_NORTH_SOUTH_SOUTH_NORTH) || 
		      (conf == C_SOUTH_NORTH_SOUTH_WEST));
		break;
	case L_SOUTH_WEST :
		ans = ((conf == C_NORTH_EAST_SOUTH_WEST) || 
		      (conf == C_SOUTH_NORTH_SOUTH_WEST));
		break;
	case L_WEST_EAST :
		ans = ((conf == C_EAST_WEST_WEST_EAST) || 
		      (conf == C_WEST_EAST_WEST_NORTH));
		break;
	case L_WEST_NORTH :
		ans = ((conf == C_EAST_SOUTH_WEST_NORTH) || 
		      (conf == C_WEST_EAST_WEST_NORTH));
		break;

	}
	return ans;
	
}

void CLane::updateState()
{

	m_NumOfCars += m_CarDistribution.numOfCarsAdded();
	m_TimeSinceLastGreen += DELTA_T;
	if (isLaneActive(m_JuncConfiguration->getConf(),m_Lane))
	{	
		m_TimeSinceLastGreen = 0;  //green right now
		int delta_t = DELTA_T;
		if(!isLaneActive(m_JuncConfiguration->getPrevConf(),m_Lane))
			delta_t = delta_t-3;//"dead" period in junction
		int carsLeft = (UINT)(m_DepartureRate * delta_t);
		if( carsLeft > m_NumOfCars ) carsLeft = m_NumOfCars;
		m_NumOfCars -= carsLeft;
		m_NumOfCarsSoFar += carsLeft;
		m_TimeActive += delta_t;
		
	}
}

///////////////////////////////////////////////////////////
//class CCarDistribution implementation

CCarDistribution::CCarDistribution(double lambda)
{
	setLambda(lambda);
}

int  CCarDistribution::numOfCarsAdded()
{
	//adopted from  Principles of Discrete Event Simulation, Fishman 1978 
	double Lambda = m_Lambda*DELTA_T;
	double eps = 0.000000001;
	double w = exp(-Lambda);
	int X = 0;
	double A = w;
	double B = w;
	
	

	double U = (double)rand()/(double)RAND_MAX;

	while (1)
	{
		if (U <= A || A > 1-eps|| B < eps)
			return X;
		else
		{
			X++;
			B = (B*Lambda)/X;
			A += B;
		}
	}
}

///////////////////////////////////////////////////////////////
//class CJuncConfiguration
void CJuncConfiguration::setConf(int conf)
{
	m_PrevConf = m_CurrConf ;
    m_CurrConf = conf;
	++m_confArr[m_CurrConf - 1];
}
CJuncConfiguration::CJuncConfiguration(): m_CurrConf(0), m_PrevConf(0)
{
	Reset();
}
void CJuncConfiguration::Reset()
{
	for(int i = 0;i < NUM_OF_CONFIGURATIONS;i++)
		m_confArr[i] = 0;
}

/*void CJuncConfiguration::UpdateConf()
{
	m_CurrConf = m_Policy.GetNextConfiguration();
}*/


