#include "Testbench.h"

#include "printError.h"
#include <stdio.h>

#define MAXNUMOF_REGISTEREDCAGENTS 1000
#define MAXNUMOF_REGISTEREDCHANNELS 1000
#define MAXNUMOF_REGISTEREDSENSORS 1000

//#define PRINT
//#define STOP_EVERY_CYCLE
//#define STOP_EVERY_CYCLE_AFTER_SAMPLE 738


using namespace std;

void Testbench :: init_testbench() {
	maxNumOf_registeredAgents = MAXNUMOF_REGISTEREDCAGENTS;
	maxNumOf_registeredChannels = MAXNUMOF_REGISTEREDCHANNELS;
	maxNumOf_registeredSensors = MAXNUMOF_REGISTEREDSENSORS;
}

Testbench :: Testbench() {
	setName(NO_NAME);
	init_testbench();
}

Testbench :: Testbench(char* name) {
	setName(name);
	init_testbench();
}

bool Testbench :: register_agent(Agent* agent) {
	AgentSlotOfTestbench* agentSlot = new AgentSlotOfTestbench();
	if(agentSlot != NULL) {
		if(agentSlot->set_agent(agent)) {
			try {
				if(vector_registeredAgents.size() < maxNumOf_registeredAgents) {
					vector_registeredAgents.push_back(agentSlot);
				}
				else {
					printError("Max number of registered agents is already reached!");
					return false;
				}
			}
			catch(bad_alloc& error) {
				printError("bad_alloc caught: ", error.what());
				return false;
			}
			return true;
		}
		else {
			printError("Agent is not set!");
			vector_registeredAgents.pop_back(); //TODO: check if it is right?!?!
			return false;
		}
	}
	else {
		printError("Couldn't create AgentSlot!");
		return false;
	}
}

bool Testbench :: register_sensor(Sensor* sensor) {
	SensorSlotOfTestbench* sensorSlot = new SensorSlotOfTestbench();
	if(sensorSlot != NULL) {
		if(sensorSlot->set_sensor(sensor)) {
			try {
				if(vector_registeredSensors.size() < maxNumOf_registeredSensors) {
					vector_registeredSensors.push_back(sensorSlot);
				}
				else {
					printError("Max number of registered sensors is already reached!");
					return false;
				}
			}
			catch(bad_alloc& error) {
				printError("bad_alloc caught: ", error.what());
				return false;
			}
			return true;
		}
		else {
			printError("Input port is no set!");
			vector_registeredSensors.pop_back(); //TODO: check if it is right?!?!
			return false;
		}
	}
	else {
		printError("Couldn't create SensorSlot!");
		return false;
	}
}

SensorSlotOfTestbench* Testbench :: get_sensorSlotAddressOfTestbench(Sensor* sensor) {
	for(auto &sensorSlot : vector_registeredSensors) {
		if(sensorSlot->get_sensor() == sensor) {
			return sensorSlot;
		}
	}
	return NULL;
}


bool Testbench :: register_channel(Channel* channel) {
	ChannelSlotOfTestbench* channelSlot = new ChannelSlotOfTestbench();
	if(channelSlot != NULL) {
		if(channelSlot->set_channel(channel)) {
			try {
				if(vector_registeredChannels.size() < maxNumOf_registeredChannels) {
					vector_registeredChannels.push_back(channelSlot);
				}
				else {
					printError("Max number of registered channels is already reached!");
					return false;
				}
			}
			catch(bad_alloc& error) {
				printError("bad_alloc caught: ", error.what());
				return false;
			}
			return true;
		}
		else {
			printError("Channel is not set!");
			vector_registeredChannels.pop_back(); //TODO: check if it is right?!?!
			return false;
		}
	}
	else {
		printError("Couldn't create ChannelSlot!");
		return false;
	}
}


bool flagStop = true;


void Testbench :: simulate(unsigned int rounds) {
	
	for(unsigned int cycle =1; cycle <=rounds; cycle++) {

#ifdef PRINT
		printf("\n------------------- round %u -------------------\n", cycle);
#endif // PRINT

		//change the signals
		for(auto &sensorSlot : vector_registeredSensors) {
			Sensor *sensor = sensorSlot->get_sensor();
			if(sensor != NULL) {
				CSVreaderModule *csvReader = sensorSlot->get_csvReaderModule();
				if(csvReader != NULL) {
					float inputValue;
					if(csvReader->get_next_value(&inputValue)) {
						//printf("%s neuer wert\n", csvReader->getName().c_str());

						sensor->set_sensorValue(inputValue);
						sensor->set_flag_sensor_value_is_valid(true);

						//printf("%s red: %f\n", csvReader->getName().c_str(), inputValue);
					}
					else {
						//printf("%s NIX\n", csvReader->getName().c_str());
						sensor->set_flag_sensor_value_is_valid(false);
					}
				}
			}
		}

		//trigger sensors -> they send information to agents
		for(auto &sensorSlot : vector_registeredSensors) {
			Sensor *sensor = sensorSlot->get_sensor();
			if(sensor != NULL) {
				sensor->trigger();
			}
		}
		
		//trigger channels -> they transport the information
		for(auto &channelSlot : vector_registeredChannels) {
			Channel *channel = channelSlot->get_channel();
			if(channel != NULL) {
				channel->trigger();
			}
		}
		
		//trigger agents -> agents do their job
		for(auto &agentSlot : vector_registeredAgents) {
			Agent *agent = agentSlot->get_agent();
			if(agent != NULL) {
				agent->trigger(cycle);
			}
		}

#ifdef STOP_EVERY_CYCLE_AFTER_SAMPLE
#ifndef STOP_EVERY_CYCLE
		if (cycle >= STOP_EVERY_CYCLE_AFTER_SAMPLE)
			getchar();
#endif // !STOP_EVERY_CYCLE
#endif // STOP_EVERY_CYCLE_AFTER_SAMPLE
#ifdef STOP_EVERY_CYCLE
		if (flagStop == true) {
			char c = getchar();
			if (c == 'c')
				flagStop = false;
		}
#endif // STOP_EVERY_CYCLE


	}


	/*
	//XXX - only for now (close CSV-Files
	for (auto &agentSlot : vector_registeredAgents) {
		Agent *agent = agentSlot->get_agent();
		if (agent != NULL) {
			StateHandler *stateHandler = agent->get_stateHandler();
			if (stateHandler != NULL) {
				stateHandler->closeCsvFile();
			}
		}
	}
	*/

	//printf("close csv writer\n");
	for (auto &agentSlot : vector_registeredAgents) {
		agentSlot->get_agent()->closeCSV();
	}

}


void Testbench::clearTestbench() {

	for (auto &agentSlot : vector_registeredAgents) {
		Agent *agent = agentSlot->get_agent();
		if (agent != NULL) {
			agent->resetAgent();
		}
	}

	for (auto &sensorSlot : vector_registeredSensors) {

		Sensor* sensor = sensorSlot->get_sensor();
		if (sensor != NULL) {
			sensor->resetSensor();
		}
	}

	for (auto &channelSlot : vector_registeredChannels) {

		Channel* channel = channelSlot->get_channel();
		if (channel != NULL) {
			channel->resetChannel();
		}
	}

	vector_registeredAgents.clear();
	vector_registeredChannels.clear();
	vector_registeredSensors.clear();

}

