#include "Agent.h"
#include "Channel.h"
#include "create_unit.h"
#include "CSVreaderModule.h"
#include "mount_nodes.h"
#include "register_in_testbench.h"
#include "Sensor.h"
#include <stdio.h>
#include "Testbench.h"

//#include "Lookuptable.h"
//#include "Clock.h"
//#include "setup_lookuptable.h"
//#include "setup_agent.h"
//#include "Cross_Confidence_Validator.h"
//#include "Continuous_Average.h"
//#include "rlutil.h"


int main(int argc, char* argv[])
{
	//create agents
	printf("Create Agents\n");
	Agent a_statorVoltage		  = create_agent("StatorVoltage");
	Agent a_statorCurrent		  = create_agent("StatorCurrent");
	Agent a_speed				  = create_agent("Speed");
	Agent a_electromagneticTorque = create_agent("ElectromagneticTorque");
	Agent a_mechanicalTorque	  = create_agent("MechanicalTorque");
	Agent a_viabilityMonitor	  = create_agent("ViabilityMonitor");

	//create sensors
	printf("\nCreate Sensors\n");
	Sensor s_statorVoltage		   = create_sensor("Stator Voltage");
	Sensor s_statorCurrent		   = create_sensor("Stator Current");
	Sensor s_speed				   = create_sensor("Speed");
	Sensor s_electromagneticTorque = create_sensor("Electromagnetic Torque");
	Sensor s_mechanicalTorque	   = create_sensor("Mechanical Torque");

	/*
	//create sensor histories
	printf("\nCreate Sensor Histories\n");
	HistoryModule hm_s_statorVoltage		 = create_historyModule("Stator Voltage", 1000, DELIMITATE_MODE_FIFO);
	HistoryModule hm_s_statorCurrent		 = create_historyModule("Stator Current", 1000, DELIMITATE_MODE_FIFO);
	HistoryModule hm_s_speed				 = create_historyModule("Speed", 1000, DELIMITATE_MODE_FIFO);
	HistoryModule hm_s_electromagneticTorque = create_historyModule("Electromagnetic Torque Sensor", 1000, DELIMITATE_MODE_FIFO);
	HistoryModule hm_s_mechanicalTorque	     = create_historyModule("Mechanical Torque Sensor", 1000, DELIMITATE_MODE_FIFO);
	*/

	//create channels for sensors
	printf("\nCreate Channels for Sensors\n");
	Channel c_sa_statorVoltage		  = create_channel("Stator Voltage (SA)", 0);
	Channel c_sa_statorCurrent		  = create_channel("Stator Current (SA)", 0);
	Channel c_sa_speed				  = create_channel("Speed Sensor (SA)", 0);
	Channel c_sa_electromagneticTorque = create_channel("Electromagnetic Torque (SA)", 0);
	Channel c_sa_mechanicalTorque      = create_channel("Mechanical Torque (SA)", 0);

	//create channels for sensors
	printf("\nCreate Channels for Agents\n");
	Channel c_aa_statorVoltage		  = create_channel("Stator Voltage (AA-UP)", MAX_BUFFER_LENGTH);
	Channel c_aa_statorCurrent		  = create_channel("Stator Current (AA-UP)", MAX_BUFFER_LENGTH);
	Channel c_aa_speed				  = create_channel("Speed Sensor (AA-UP)", MAX_BUFFER_LENGTH);
	Channel c_aa_electromagneticTorque = create_channel("Electromagnetic Torque (AA-UP)", MAX_BUFFER_LENGTH);
	Channel c_aa_mechanicalTorque      = create_channel("Mechanical Torque (AA-UP)", MAX_BUFFER_LENGTH);

	//mount sensors in agents
	printf("\nMount Sensors in Agents\n");
	mount_sensorInAgent(&a_statorVoltage, &s_statorVoltage, &c_sa_statorVoltage); //, &hm_s_statorVoltage);
	mount_sensorInAgent(&a_statorCurrent, &s_statorCurrent, &c_sa_statorCurrent); //, &hm_s_statorCurrent);
	mount_sensorInAgent(&a_speed, &s_speed, &c_sa_speed); //, &hm_s_speed);
	mount_sensorInAgent(&a_electromagneticTorque, &s_electromagneticTorque, &c_sa_electromagneticTorque); //, &hm_s_electromagneticTorque);
	mount_sensorInAgent(&a_mechanicalTorque, &s_mechanicalTorque, &c_sa_mechanicalTorque); //, &hm_s_mechanicalTorque);

	//mount agents in agent(s)
	printf("\nMount Agents in Agents\n");
	mount_agentInAgent(&a_viabilityMonitor, &a_statorVoltage,		  &c_aa_statorVoltage);
	mount_agentInAgent(&a_viabilityMonitor, &a_statorCurrent,		  &c_aa_statorCurrent);
	mount_agentInAgent(&a_viabilityMonitor, &a_speed,				  &c_aa_speed);
	mount_agentInAgent(&a_viabilityMonitor, &a_electromagneticTorque, &c_aa_electromagneticTorque);
	mount_agentInAgent(&a_viabilityMonitor, &a_mechanicalTorque,	  &c_aa_mechanicalTorque);
	
	//create testbench
	printf("\nCreate Testbench\n");
	Testbench tb = create_testbench("testbench");

	//csv-data
	//TODO: (1) simplify constructor, (2) check CSV for number of rows and columns, (3) redesign create_CSVreaderModule function
	printf("\nCreate CSV Reader Modules\n");
	CSVreaderModule csvr_statorVoltage		   = create_CSVreaderModule("Stator Voltage CSV-Reader", "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\statorVoltage.csv", 2, 2);
	CSVreaderModule csvr_statorCurrent		   = create_CSVreaderModule("Stator Current CSV-Reader", "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\statorCurrent.csv", 2, 2);
	CSVreaderModule csvr_speed				   = create_CSVreaderModule("Speed CSV-Reader", "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\speed.csv", 2, 2);
	CSVreaderModule csvr_electromagneticTorque = create_CSVreaderModule("Electromagnetic Torque CSV-Reader", "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\electromagneticTorque.csv", 2, 2);
	CSVreaderModule csvr_mechanicalTorque	   = create_CSVreaderModule("Mechanical Torque CSV-Reader", "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\mechanicalTorque.csv", 2, 2);

	//register agents
	printf("\nRegister Agents in Testbench\n");
	//TODO: "Test Bench" not "Testbench"
	register_agentInTestbench(&tb, &a_statorVoltage);
	register_agentInTestbench(&tb, &a_statorCurrent);
	register_agentInTestbench(&tb, &a_speed);
	register_agentInTestbench(&tb, &a_electromagneticTorque);
	register_agentInTestbench(&tb, &a_mechanicalTorque);
	register_agentInTestbench(&tb, &a_viabilityMonitor);

	//register sensors with their csv-readers
	printf("\nRegister Sensors in Testbench\n");
	register_sensorInTestbench(&tb, &s_statorVoltage, &csvr_statorVoltage);
	register_sensorInTestbench(&tb, &s_statorCurrent, &csvr_statorCurrent);
	register_sensorInTestbench(&tb, &s_speed, &csvr_speed);
	register_sensorInTestbench(&tb, &s_electromagneticTorque, &csvr_electromagneticTorque);
	register_sensorInTestbench(&tb, &s_mechanicalTorque, &csvr_mechanicalTorque);

	//register sensor channels
	printf("\nRegister Channels in Testbench\n");
	register_channelInTestbench(&tb, &c_sa_statorVoltage);
	register_channelInTestbench(&tb, &c_sa_statorCurrent);
	register_channelInTestbench(&tb, &c_sa_speed);
	register_channelInTestbench(&tb, &c_sa_electromagneticTorque);
	register_channelInTestbench(&tb, &c_sa_mechanicalTorque);
	register_channelInTestbench(&tb, &c_aa_statorVoltage);
	register_channelInTestbench(&tb, &c_aa_statorCurrent);
	register_channelInTestbench(&tb, &c_aa_speed);
	register_channelInTestbench(&tb, &c_aa_electromagneticTorque);
	register_channelInTestbench(&tb, &c_aa_mechanicalTorque);

	printf("\n\nPress any key to start simulation...\n");
	getchar();
	

	//Start
	//TODO: read lenght of CSV-Files and pass this number to tb.simulate
	tb.simulate(29208);
	getchar();



	/*
	//create agents
	printf("Create Agents\n");
	Agent a_body     = create_agent("Body Agent");
	Agent a_activity = create_agent("Activity Agent");
	Agent a_HR       = create_agent("HR Agent");
	Agent a_BR       = create_agent("BR Agent");
	Agent a_SpO2     = create_agent("SpO2 Agent");
	Agent a_BPSys    = create_agent("BPSys Agent");
	Agent a_bodyTemp = create_agent("BTemp Agent");

	//create sensors
	printf("\nCreate Sensors\n");
	Sensor s_activity = create_sensor("Activity Sensor");
	Sensor s_HR       = create_sensor("HR Sensor");
	Sensor s_BR       = create_sensor("BR Sensor");
	Sensor s_SpO2     = create_sensor("SpO2 Sensor");
	Sensor s_BPSys    = create_sensor("BPSys Sensor");
	Sensor s_bodyTemp = create_sensor("BTemp Sensor");
	Sensor s_battery  = create_sensor("Battery Sensor");

	//create channels for agents
	printf("\nCreate Channels for Agents\n");
	Channel c_a_activity = create_channel("Channel Activity Agent");
	Channel c_a_HR       = create_channel("Channel HR Agent");
	Channel c_a_BR       = create_channel("Channel BR Agent");
	Channel c_a_SpO2     = create_channel("Channel SpO2 Agent");
	Channel c_a_BPSys    = create_channel("Channel BPSys Agent");
	Channel c_a_bodyTemp = create_channel("Channel BTemp Agent");

	//create channels for sensors
	printf("\nCreate Channels for Sensors\n");
	Channel c_s_activity = create_channel("Channel Activity Sensor", 0);
	Channel c_s_HR       = create_channel("Channel HR Sensor", 0);
	Channel c_s_BR       = create_channel("Channel BR Sensor", 0);
	Channel c_s_SpO2     = create_channel("Channel SpO2 Sensor", 0);
	Channel c_s_BPSys    = create_channel("Channel BPSys Sensor", 0);
	Channel c_s_bodyTemp = create_channel("Channel BTemp Sensor", 0);


	//create look up tables
	printf("\nCreate Look up Tables\n");
	Lookuptable lut_HR       = create_lookuptable("HR LUT");
	Lookuptable lut_BR       = create_lookuptable("BR LUT");
	Lookuptable lut_SpO2     = create_lookuptable("SpO2 LUT");
	Lookuptable lut_BPSys    = create_lookuptable("BPSys LUT");
	Lookuptable lut_bodyTemp = create_lookuptable("BTemp LUT");

	//fill look up tables
	//TODO -> Infinity Stuff!!!!
	printf("\nFill Look up Tables\n");

	fill_lookuptable(&lut_HR, 3,   0.0, EXCLUDED,  40.0, EXCLUDED);
	fill_lookuptable(&lut_HR, 2,  40.0, INCLUDED,  51.0, EXCLUDED);
	fill_lookuptable(&lut_HR, 1,  51.0, INCLUDED,  60.0, EXCLUDED);
	fill_lookuptable(&lut_HR, 0,  60.0, INCLUDED, 100.0, INCLUDED);
	fill_lookuptable(&lut_HR, 1, 100.0, EXCLUDED, 110.0, INCLUDED);
	fill_lookuptable(&lut_HR, 2, 110.0, EXCLUDED, 129.0, INCLUDED);
	fill_lookuptable(&lut_HR, 3, 129.0, EXCLUDED, 200.0, EXCLUDED);

	fill_lookuptable(&lut_BR, 2,  0.0, EXCLUDED,  9.0, EXCLUDED);
	fill_lookuptable(&lut_BR, 0,  9.0, INCLUDED, 14.0, INCLUDED);
	fill_lookuptable(&lut_BR, 1, 14.0, EXCLUDED, 20.0, INCLUDED);
	fill_lookuptable(&lut_BR, 2, 20.0, EXCLUDED, 29.0, INCLUDED);
	fill_lookuptable(&lut_BR, 3, 29.0, EXCLUDED, 50.0, EXCLUDED);

	fill_lookuptable(&lut_SpO2, 3,  0.0, EXCLUDED,  85.0, EXCLUDED);
	fill_lookuptable(&lut_SpO2, 2, 85.0, INCLUDED,  90.0, EXCLUDED);
	fill_lookuptable(&lut_SpO2, 1, 90.0, INCLUDED,  95.0, EXCLUDED);
	fill_lookuptable(&lut_SpO2, 0, 95.0, INCLUDED, 100.0, EXCLUDED);
	
	fill_lookuptable(&lut_BPSys, 3,   0.0, EXCLUDED,  70.0, EXCLUDED);
	fill_lookuptable(&lut_BPSys, 2,  70.0, INCLUDED,  81.0, EXCLUDED);
	fill_lookuptable(&lut_BPSys, 1,  81.0, INCLUDED, 101.0, EXCLUDED);
	fill_lookuptable(&lut_BPSys, 0, 101.0, INCLUDED, 149.0, INCLUDED);
	fill_lookuptable(&lut_BPSys, 1, 149.0, EXCLUDED, 169.0, INCLUDED);
	fill_lookuptable(&lut_BPSys, 2, 169.0, EXCLUDED, 179.0, INCLUDED);
	fill_lookuptable(&lut_BPSys, 3, 179.0, EXCLUDED, 200.0, EXCLUDED);

	fill_lookuptable(&lut_bodyTemp, 3, (float)0.0, EXCLUDED,   (float)28.0, EXCLUDED);
	fill_lookuptable(&lut_bodyTemp, 2, (float)28.0, INCLUDED,  (float)32.0, EXCLUDED);
	fill_lookuptable(&lut_bodyTemp, 1, (float)32.0, INCLUDED,  (float)35.0, EXCLUDED);
	fill_lookuptable(&lut_bodyTemp, 0, (float)35.0, INCLUDED, (float)38.0, INCLUDED);
	fill_lookuptable(&lut_bodyTemp, 2, 38.0, EXCLUDED,  39.5, INCLUDED);
	fill_lookuptable(&lut_bodyTemp, 3, 39.5, EXCLUDED, 100.0, EXCLUDED);

	//check look up tables
	printf("\nCheck and activate Look up Tables\n");
	check_and_activate_lookuptable(&lut_HR);
	check_and_activate_lookuptable(&lut_BR);
	check_and_activate_lookuptable(&lut_SpO2);
	check_and_activate_lookuptable(&lut_BPSys);
	check_and_activate_lookuptable(&lut_bodyTemp);

	//create confidence validators
	printf("\nCreate Confidence Validators\n");
	Confidence_Validator cv_HR =       create_confidence_validator("ConfValid HR",     0.0, BOUND, 500.0, BOUND, 5.0,  NO_RATES_OF_CHANGE);	//TO ASK
	Confidence_Validator cv_BR =       create_confidence_validator("ConfValid BR",     0.0, BOUND, 300.0, BOUND, 5.0,  NO_RATES_OF_CHANGE);	//TO ASK
	Confidence_Validator cv_SpO2 =     create_confidence_validator("ConfValid SpO2",   0.0, BOUND, 100.0, BOUND, 5.0,  NO_RATES_OF_CHANGE);	//TO ASK
	Confidence_Validator cv_BPSys =    create_confidence_validator("ConfValid BPSys",  0.0, BOUND, 500.0, BOUND, 5.0,  NO_RATES_OF_CHANGE);	//TO ASK
	Confidence_Validator cv_bodyTemp = create_confidence_validator("ConfValid BTemp", (float)-60.0, BOUND, (float)50.0, BOUND, (float)0.003, NO_RATES_OF_CHANGE); //TO ASK

	//create abstraction modules
	printf("\nCreate Confidence Validators\n");
	Abstraction am_HR       = create_abstraction_module("AbstrMod HR",    &lut_HR, ABSTRACTION_LOOKUPTABLE);
	Abstraction am_BR       = create_abstraction_module("AbstrMod BR",    &lut_BR, ABSTRACTION_LOOKUPTABLE);
	Abstraction am_SpO2     = create_abstraction_module("AbstrMod SpO2",  &lut_SpO2, ABSTRACTION_LOOKUPTABLE);
	Abstraction am_BPSys    = create_abstraction_module("AbstrMod BPSys", &lut_BPSys, ABSTRACTION_LOOKUPTABLE);
	Abstraction am_bodyTemp = create_abstraction_module("AbstrMod BTemp", &lut_bodyTemp, ABSTRACTION_LOOKUPTABLE);

	//create bunch modules
	printf("\nCreate Bunch Modules\n");
	Bunch_Module bm_body = create_bunch_module("BunMod Body", BUNCH_SIMPLY_ADD);

	//mount bunch modules
	printf("\nMount Bunch Modules\n");
	mount_bunchmodule_in_agent(&a_body, &bm_body);

	//mount sensors in various agents
	printf("\nMount Sensors in various Agents\n");
	mount_sensor_in_agent(&a_HR,       &s_HR,       &c_s_HR,       &cv_HR,       &am_HR);
	mount_sensor_in_agent(&a_BR,       &s_BR,       &c_s_BR,       &cv_BR,       &am_BR);
	mount_sensor_in_agent(&a_SpO2,     &s_SpO2,     &c_s_SpO2,     &cv_SpO2,     &am_SpO2);
	mount_sensor_in_agent(&a_BPSys,    &s_BPSys,    &c_s_BPSys,    &cv_BPSys,    &am_BPSys);
	
	mount_sensor_in_agent(&a_bodyTemp, &s_bodyTemp, &c_s_bodyTemp, &cv_bodyTemp, &am_bodyTemp);
	//mount_sensor_in_agent(&a_bodyTemp, &s_bodyTemp, &c_s_bodyTemp, &am_bodyTemp);
	
	mount_sensor_in_agent(&a_activity, &s_activity, &c_s_activity);



	//cross confidence validator
	//TODO: schöne ausgabe in der console
	printf("\nCreate Cross Confidence Validator Modules\n");
	Cross_Confidence_Validator ccv_bodyTemp("CCV BTemp", (float)0.5);


	//mount agents
	printf("\nMount Agents\n");
	mount_slaveagent_in_agent(&a_body, &a_activity, OPEN, &c_a_activity, (unsigned int)0);
	mount_slaveagent_in_agent(&a_body, &a_HR,       OPEN, &c_a_HR);
	mount_slaveagent_in_agent(&a_body, &a_BR,       OPEN, &c_a_BR);
	mount_slaveagent_in_agent(&a_body, &a_SpO2,     OPEN, &c_a_SpO2);
	mount_slaveagent_in_agent(&a_body, &a_BPSys,    OPEN, &c_a_BPSys);
	mount_slaveagent_in_agent(&a_body, &a_bodyTemp, OPEN, &c_a_bodyTemp, &ccv_bodyTemp);

	//set abstraction methods
	printf("\nSetup Abstraction Methods\n");
	set_agents_abstraction_method(&a_activity, ABSTRACTION_LOOKUPTABLE);
	set_agents_abstraction_method(&a_HR,       ABSTRACTION_LOOKUPTABLE);
	set_agents_abstraction_method(&a_BR,       ABSTRACTION_LOOKUPTABLE);
	set_agents_abstraction_method(&a_SpO2,     ABSTRACTION_LOOKUPTABLE);
	set_agents_abstraction_method(&a_BPSys,    ABSTRACTION_LOOKUPTABLE);
	set_agents_abstraction_method(&a_bodyTemp, ABSTRACTION_LOOKUPTABLE);

	//create testbench
	printf("\nCreate Testbench\n");
	Testbench tb = create_testbench("testbench");

	//csv-data
	//TODO: schöne ausgabe (mit farbe usw) im terminal
	unsigned int fields_to_read[] = {2, 3, 4, 6, 19, 20};
	CSV_Reader csv_reader("C:\\csv-data\\EWS-Temp32.csv", 6, fields_to_read, 2);
	tb.register_csv_reader(&csv_reader);

	CSV_Writer csv_writer("CSV Writer", "C:\\csv-data\\EWS-CCVU_withoutConf.csv");
	tb.register_csv_writer(&csv_writer);

	//register agents in testbench
	printf("\nRegister Agents in Testbench:\n");
	register_in_testbench(&tb, &a_HR);
	register_in_testbench(&tb, &a_BR);
	register_in_testbench(&tb, &a_bodyTemp);
	register_in_testbench(&tb, &a_activity);
	register_in_testbench(&tb, &a_SpO2);
	register_in_testbench(&tb, &a_BPSys);
	register_in_testbench(&tb, &a_body);


	//register sensors in testbench //TODO: bei CSV - irgendwie eine zugehörigkeitstabelle.. anstatt hier beim registrieren auf die reinfolge zu achten
	printf("\nRegister Sensors in Testbench:\n");
	register_in_testbench(&tb, &s_HR);
	register_in_testbench(&tb, &s_BR);
	register_in_testbench(&tb, &s_bodyTemp);
	register_in_testbench(&tb, &s_activity);
	register_in_testbench(&tb, &s_SpO2);
	register_in_testbench(&tb, &s_BPSys);
	
	//register channels in testbench
	printf("\nRegister Channels in Testbench:\n");
	register_in_testbench(&tb, &c_a_activity);
	register_in_testbench(&tb, &c_a_HR);
	register_in_testbench(&tb, &c_a_BR);
	register_in_testbench(&tb, &c_a_SpO2);
	register_in_testbench(&tb, &c_a_BPSys);
	register_in_testbench(&tb, &c_a_bodyTemp);

	register_in_testbench(&tb, &c_s_activity);
	register_in_testbench(&tb, &c_s_HR);
	register_in_testbench(&tb, &c_s_BR);
	register_in_testbench(&tb, &c_s_SpO2);
	register_in_testbench(&tb, &c_s_BPSys);
	register_in_testbench(&tb, &c_s_bodyTemp);


	*/

}