/*
 * main.cpp
 *
 *  Created on: 25.05.2018
 *      Author: edwin willegger, edwin.willegger@tuwien.ac.at
 *      This file is used to generate output data from the
 *      flow measurements conducted in Wr. Neustadt for the project SAVE.
 *      based on the implementation of Maximilian Götzinger.
 */

#include "Agent.h"
#include "Channel.h"
#include "create_unit.h"
#include "CSVreaderModule.h"
#include "inAgentsRegistrations.h"
#include "mount_nodes.h"
#include "register_in_testbench.h"
#include "Sensor.h"
#include "setupNode.h"
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include "Testbench.h"
#include "file_util.h"

#include "LinearFunction.h"
#include "LinearFunctionBlock.h"

using namespace std;

/**********************************************************************************************************************
 ************************************************begin of global definitions of variables and constants ***************
 **********************************************************************************************************************/

#define SAMPLING	50

//global vectors for the different elements
static vector<Agent*> 				vec_of_Agents;
static vector<Sensor*> 				vec_of_Sensors;
static vector<Channel*>				vec_of_Channels_for_Sensors;
static vector<Channel*> 			vec_of_Channels_for_Agents;
static vector<LinearFunctionBlock*> vec_of_linear_Function_Blocks;
static vector<Testbench*>			vec_of_test_benches;
static vector<CSVreaderModule*>		vec_of_csv_readers;

//names of the measured data
const string FIRST_MEASURED_DATA_NAME 	= "Pump_Voltage";
const string SECOND_MEASURED_DATA_NAME 	= "Temp_1";
const string THIRD_MEASURED_DATA_NAME 	= "Temp_2";
const string FOURTH_MEASURED_DATA_NAME 	= "Sharky_S";
const string FIFTH_MEASURED_DATA_NAME 	= "Sharky_B";
const string SIXTH_MEASURED_DATA_NAME 	= "Riels";
const string SEVENTH_MEASURED_DATA_NAME = "Dyna";
//viability monitor
const string VIABILITY_MONITOR			= "ViabilityMonitor";

//name for the channels of the sensors and agents
const string APPENDIX_FOR_CHANNEL_SENSOR_NAME 		= "(SA)";
const string FIRST_MEASURED_CHANNEL_SENSOR_NAME 	= FIRST_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_SENSOR_NAME;
const string SECOND_MEASURED_CHANNEL_SENSOR_NAME 	= SECOND_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_SENSOR_NAME;
const string THIRD_MEASURED_CHANNEL_SENSOR_NAME 	= THIRD_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_SENSOR_NAME;
const string FOURTH_MEASURED_CHANNEL_SENSOR_NAME 	= FOURTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_SENSOR_NAME;
const string FIFTH_MEASURED_CHANNEL_SENSOR_NAME 	= FIFTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_SENSOR_NAME;
const string SIXTH_MEASURED_CHANNEL_SENSOR_NAME 	= SIXTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_SENSOR_NAME;
const string SEVENTH_MEASURED_CHANNEL_SENSOR_NAME 	= SEVENTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_SENSOR_NAME;
const string APPENDIX_FOR_CHANNEL_AGENT_NAME		= "(AA-UP)";
const string FIRST_MEASURED_CHANNEL_AGENT_NAME 		= FIRST_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_AGENT_NAME;
const string SECOND_MEASURED_CHANNEL_AGENT_NAME 	= SECOND_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_AGENT_NAME;
const string THIRD_MEASURED_CHANNEL_AGENT_NAME 		= THIRD_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_AGENT_NAME;
const string FOURTH_MEASURED_CHANNEL_AGENT_NAME 	= FOURTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_AGENT_NAME;
const string FIFTH_MEASURED_CHANNEL_AGENT_NAME 		= FIFTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_AGENT_NAME;
const string SIXTH_MEASURED_CHANNEL_AGENT_NAME 		= SIXTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_AGENT_NAME;
const string SEVENTH_MEASURED_CHANNEL_AGENT_NAME 	= SEVENTH_MEASURED_DATA_NAME + APPENDIX_FOR_CHANNEL_AGENT_NAME;

#define TRANSFER_RATE_CHANNEL_SENSOR	0
#define TRANSFER_RATE_CHANNEL_AGENT		MAX_BUFFER_LENGTH

//defintions for the linear function blocks
const string FUNC_BLOCK_NAME_SAME_STATE_DEV				= "funcBlock:confSim2StateDev";
const string FUNC_BLOCK_NAME_ANOTHER_STATE_DEV 			= "funcBlock:confDif2StateDev";
const string FUNC_BLOCK_NAME_SAME_TIME 					= "funcBlock:confSim2StateTime";
const string FUNC_BLOCK_NAME_ANOTHER_STATE_TIME 		= "funcBlock:confDif2StateTime";
const string FUNC_BLOCK_NAME_VAILD_STATE_DEV 			= "funcBlock:confValidStateDev";
const string FUNC_BLOCK_NAME_INVALID_STATE_DEV 			= "funcBlock:confInvalidStateDev";
const string FUNC_BLOCK_NAME_VALID_STATE_TIME			= "funcBlock:confValidStateTime";
const string FUNC_BLOCK_NAME_INVALID_STATE_TIME 		= "funcBlock:confInvalidStateTime";
const string FUNC_BLOCK_NAME_CONFIDENCE_STATE_DRIFTS 	= "confidence:confStateDrifts";
const string FUNC_BLOCK_NAME_CONFIDENCE_BROKEN 			= "confidence:broken";

#define OUTTER_BOUND_SIM_DIF 	0.14
#define INNER_BOUND_SIM_DIF 	0.01

#define OUTTER_BOUND_DRIFT 		OUTTER_BOUND_SIM_DIF * 3
#define INNER_BOUND_DRIFT		OUTTER_BOUND_SIM_DIF

#define BOUND_BROKEN			2

#define LENGTH					10


//definitions for the testbench
const string TEST_BENCH = "testbench";

//defintions for the csv-reader-modules
const string APPENDIX_CSV_MODULES = " CSV-Reader";
const string FIRST_MEASURED_DATA_CSV_NAME 	= FIRST_MEASURED_DATA_NAME + APPENDIX_CSV_MODULES;
const string SECOND_MEASURED_DATA_CSV_NAME 	= SECOND_MEASURED_DATA_NAME + APPENDIX_CSV_MODULES;
const string THIRD_MEASURED_DATA_CSV_NAME 	= THIRD_MEASURED_DATA_NAME + APPENDIX_CSV_MODULES;
const string FOURTH_MEASURED_DATA_CSV_NAME 	= FOURTH_MEASURED_DATA_NAME + APPENDIX_CSV_MODULES;
const string FIFTH_MEASURED_DATA_CSV_NAME 	= FIFTH_MEASURED_DATA_NAME + APPENDIX_CSV_MODULES;
const string SIXTH_MEASURED_DATA_CSV_NAME 	= SIXTH_MEASURED_DATA_NAME + APPENDIX_CSV_MODULES;
const string SEVENTH_MEASURED_DATA_CSV_NAME = SEVENTH_MEASURED_DATA_NAME + APPENDIX_CSV_MODULES;



/**********************************************************************************************************************
 ************************************************end of global definitions of variables and constants *****************
 **********************************************************************************************************************/

/**********************************************************************************************************************
 ************************************************begin of function prototypes *****************************************
 **********************************************************************************************************************/

void create_and_register_All_Agents();
void set_working_cycle_of_All_Agents();

void create_and_register_All_Sensors();
void set_working_cycle_of_All_Sensors();

void create_and_register_channels();
void create_and_register_channels_for_sensors();
void create_and_register_channels_for_agents();

void mount_sensors_in_agents();
void mount_agents_in_agents();

void register_data_agents_in_agent_state_Handler();

void create_linear_function_blocks();
void create_same_state_deviation_function_block();
void create_another_state_deviation_function_block();
void create_state_time_function_block();
void create_another_state_time_function_block();
void create_valid_state_deviation_function_block();
void create_invalid_state_deviation_function_block();
void create_valid_state_time_function_block();
void create_invalid_state_time_function_block();
void create_confidence_state_drift_function_block();
void create_confidence_broken_function_block();
void mount_function_blocks_to_viability_monitor();

void create_all_testbenches();

void create_csvr_modules();

void register_agents_in_testbenches();

void register_sensors_in_testbenches();

void register_channels_in_testbenches();
void register_channels_of_sensors_in_testbenches();
void register_channels_of_actors_in_testbenches();

void run_simulation_of_all_testbenches();


/**********************************************************************************************************************
 ************************************************end of function prototypes *******************************************
 **********************************************************************************************************************/

int main()
{
	cout << "This program processes test data from flow measurements in Wr. Neustadt " << endl;

	create_and_register_All_Agents();
	set_working_cycle_of_All_Agents();


	create_and_register_All_Sensors();
	set_working_cycle_of_All_Sensors();

	create_and_register_channels();

	mount_sensors_in_agents();

	mount_agents_in_agents();

	register_data_agents_in_agent_state_Handler();

	create_linear_function_blocks();

	mount_function_blocks_to_viability_monitor();

	create_all_testbenches();

	create_csvr_modules();

	register_agents_in_testbenches();

	register_sensors_in_testbenches();

	register_channels_in_testbenches();

	run_simulation_of_all_testbenches();

	//TODO memory free of all objects.


	cout << "Program finished successfully" << endl;
	return 0;
}



/*
 * creates all the agents used in the measurment
 * and stores them into the global vector
 */
void create_and_register_All_Agents()
{
	cout << "Creating Agents" << endl;
	char* c_name_of_current_agent = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_agent, FIRST_MEASURED_DATA_NAME.c_str());
	Agent* a_Pump_Voltage 		= create_agent(c_name_of_current_agent);
	strcpy(c_name_of_current_agent, SECOND_MEASURED_DATA_NAME.c_str());
	Agent* a_Temp_1 				= create_agent(c_name_of_current_agent);
	strcpy(c_name_of_current_agent, THIRD_MEASURED_DATA_NAME.c_str());
	Agent* a_Temp_2 				= create_agent(c_name_of_current_agent);
	strcpy(c_name_of_current_agent, FOURTH_MEASURED_DATA_NAME.c_str());
	Agent* a_Sharky_S 			= create_agent(c_name_of_current_agent);
	strcpy(c_name_of_current_agent, FIFTH_MEASURED_DATA_NAME.c_str());
	Agent* a_Sharky_B 			= create_agent(c_name_of_current_agent);
	strcpy(c_name_of_current_agent, SIXTH_MEASURED_DATA_NAME.c_str());
	Agent* a_Riels 				= create_agent(c_name_of_current_agent);
	strcpy(c_name_of_current_agent, SEVENTH_MEASURED_DATA_NAME.c_str());
	Agent* a_Dyna 				= create_agent(c_name_of_current_agent);
	strcpy(c_name_of_current_agent, VIABILITY_MONITOR.c_str());
	Agent* a_viabilityMonitor 	= create_agent(c_name_of_current_agent);
	vec_of_Agents.push_back(a_Pump_Voltage);
	vec_of_Agents.push_back(a_Temp_1);
	vec_of_Agents.push_back(a_Temp_2);
	vec_of_Agents.push_back(a_Sharky_S);
	vec_of_Agents.push_back(a_Sharky_B);
	vec_of_Agents.push_back(a_Riels);
	vec_of_Agents.push_back(a_Dyna);
	vec_of_Agents.push_back(a_viabilityMonitor);
	cout << vec_of_Agents.size() << " agents were created" << endl;
}

/*
 * the working_cycle for all registered agents is set
 */
void set_working_cycle_of_All_Agents()
{
	unsigned int working_Cyle = SAMPLING;
	unsigned int size_of_vec_of_Agents = 0;
	unsigned int index = 0;
	Agent* current_Agent;
	size_of_vec_of_Agents = vec_of_Agents.size();
	for(index = 0; index < size_of_vec_of_Agents; index++) {
		current_Agent = vec_of_Agents[index];
		setWorkingCycleOfAgent(current_Agent, working_Cyle);
	}
}

/*
 * all necessary sensors are created and registered
 */
void create_and_register_All_Sensors()
{
	cout << "Creating Sensors" << endl;
	char* c_name_of_current_sensor = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_sensor, FIRST_MEASURED_DATA_NAME.c_str());
	Sensor* s_Pump_Voltage 	= create_sensor(c_name_of_current_sensor);
	strcpy(c_name_of_current_sensor, SECOND_MEASURED_DATA_NAME.c_str());
	Sensor* s_Temp_1 		= create_sensor(c_name_of_current_sensor);
	strcpy(c_name_of_current_sensor, THIRD_MEASURED_DATA_NAME.c_str());
	Sensor* s_Temp_2 		= create_sensor(c_name_of_current_sensor);
	strcpy(c_name_of_current_sensor, FOURTH_MEASURED_DATA_NAME.c_str());
	Sensor* s_Sharky_S 		= create_sensor(c_name_of_current_sensor);
	strcpy(c_name_of_current_sensor, FIFTH_MEASURED_DATA_NAME.c_str());
	Sensor* s_Sharky_B 		= create_sensor(c_name_of_current_sensor);
	strcpy(c_name_of_current_sensor, SIXTH_MEASURED_DATA_NAME.c_str());
	Sensor* s_Riels 		= create_sensor(c_name_of_current_sensor);
	strcpy(c_name_of_current_sensor, SEVENTH_MEASURED_DATA_NAME.c_str());
	Sensor* s_Dyna 			= create_sensor(c_name_of_current_sensor);
	vec_of_Sensors.push_back(s_Pump_Voltage);
	vec_of_Sensors.push_back(s_Temp_1);
	vec_of_Sensors.push_back(s_Temp_2);
	vec_of_Sensors.push_back(s_Sharky_S);
	vec_of_Sensors.push_back(s_Sharky_B);
	vec_of_Sensors.push_back(s_Riels);
	vec_of_Sensors.push_back(s_Dyna);
	cout << vec_of_Sensors.size() << " sensors were created." << endl;
}

/*
 * working cycle of all registered sensors is set
 */
void set_working_cycle_of_All_Sensors()
{
	unsigned int working_Cyle = SAMPLING;
	unsigned int size_of_vec_of_Sensors = 0;
	unsigned int index = 0;
	Sensor* current_Sensor;

	size_of_vec_of_Sensors = vec_of_Sensors.size();
	for(index = 0; index < size_of_vec_of_Sensors; index++) {
		current_Sensor = vec_of_Sensors[index];
		setWorkingCycleOfSensor(current_Sensor, working_Cyle);
	}
}

/*
 * creating and registering all channels
 */
void create_and_register_channels()
{
	create_and_register_channels_for_sensors();
	create_and_register_channels_for_agents();
}

/*
 * creating and registering the channels for the sensors.
 */
void create_and_register_channels_for_sensors()
{
	cout << "Creating and registering channels for sensors" << endl;
	char* c_name_of_current_channel = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_channel, FIRST_MEASURED_CHANNEL_SENSOR_NAME.c_str());
	Channel* c_sa_Pump_Voltage 	= create_channel(c_name_of_current_channel, 0);
	strcpy(c_name_of_current_channel, SECOND_MEASURED_CHANNEL_SENSOR_NAME.c_str());
	Channel* c_sa_Temp_1 		= create_channel(c_name_of_current_channel, 0);
	strcpy(c_name_of_current_channel, THIRD_MEASURED_CHANNEL_SENSOR_NAME.c_str());
	Channel* c_sa_Temp_2 		= create_channel(c_name_of_current_channel, 0);
	strcpy(c_name_of_current_channel, FOURTH_MEASURED_CHANNEL_SENSOR_NAME.c_str());
	Channel* c_sa_Sharky_S 		= create_channel(c_name_of_current_channel, 0);
	strcpy(c_name_of_current_channel, FIFTH_MEASURED_CHANNEL_SENSOR_NAME.c_str());
	Channel* c_sa_Sharky_B	 	= create_channel(c_name_of_current_channel, 0);
	strcpy(c_name_of_current_channel, SIXTH_MEASURED_CHANNEL_SENSOR_NAME.c_str());
	Channel* c_sa_Riels 		= create_channel(c_name_of_current_channel, 0);
	strcpy(c_name_of_current_channel, SEVENTH_MEASURED_CHANNEL_SENSOR_NAME.c_str());
	Channel* c_sa_Dyna 			= create_channel(c_name_of_current_channel, 0);

	vec_of_Channels_for_Sensors.push_back(c_sa_Pump_Voltage);
	vec_of_Channels_for_Sensors.push_back(c_sa_Temp_1);
	vec_of_Channels_for_Sensors.push_back(c_sa_Temp_2);
	vec_of_Channels_for_Sensors.push_back(c_sa_Sharky_S);
	vec_of_Channels_for_Sensors.push_back(c_sa_Sharky_B);
	vec_of_Channels_for_Sensors.push_back(c_sa_Riels);
	vec_of_Channels_for_Sensors.push_back(c_sa_Dyna);
	cout << vec_of_Channels_for_Sensors.size() << " channels for sensors were created" << endl;
}

/*
 * creating and registering the channels for the agents
 */
void create_and_register_channels_for_agents()
{
	cout << "Creating and registering channels for agents" << endl;
		char* c_name_of_current_channel = new char[MAX_LENGTH_NAME];
		strcpy(c_name_of_current_channel, FIRST_MEASURED_CHANNEL_AGENT_NAME.c_str());
		Channel* c_aa_Pump_Voltage 	= create_channel(c_name_of_current_channel, 0);
		strcpy(c_name_of_current_channel, SECOND_MEASURED_CHANNEL_AGENT_NAME.c_str());
		Channel* c_aa_Temp_1 		= create_channel(c_name_of_current_channel, 0);
		strcpy(c_name_of_current_channel, THIRD_MEASURED_CHANNEL_AGENT_NAME.c_str());
		Channel* c_aa_Temp_2 		= create_channel(c_name_of_current_channel, 0);
		strcpy(c_name_of_current_channel, FOURTH_MEASURED_CHANNEL_AGENT_NAME.c_str());
		Channel* c_aa_Sharky_S 		= create_channel(c_name_of_current_channel, 0);
		strcpy(c_name_of_current_channel, FIFTH_MEASURED_CHANNEL_AGENT_NAME.c_str());
		Channel* c_aa_Sharky_B 		= create_channel(c_name_of_current_channel, 0);
		strcpy(c_name_of_current_channel, SIXTH_MEASURED_CHANNEL_AGENT_NAME.c_str());
		Channel* c_aa_Riels 		= create_channel(c_name_of_current_channel, 0);
		strcpy(c_name_of_current_channel, SEVENTH_MEASURED_CHANNEL_AGENT_NAME.c_str());
		Channel* c_aa_Dyna 			= create_channel(c_name_of_current_channel, 0);

		vec_of_Channels_for_Agents.push_back(c_aa_Pump_Voltage);
		vec_of_Channels_for_Agents.push_back(c_aa_Temp_1);
		vec_of_Channels_for_Agents.push_back(c_aa_Temp_2);
		vec_of_Channels_for_Agents.push_back(c_aa_Sharky_S);
		vec_of_Channels_for_Agents.push_back(c_aa_Sharky_B);
		vec_of_Channels_for_Agents.push_back(c_aa_Riels);
		vec_of_Channels_for_Agents.push_back(c_aa_Dyna);

		cout << vec_of_Channels_for_Agents.size() << " channels for agents were created" << endl;
}

void mount_sensors_in_agents()
{
	Agent* 			current_agent;
	Sensor* 		current_sensor;
	Channel* 		current_sensor_channel;
	unsigned int 	size_of_vec_sensor = 0;
	unsigned int	index 	= 0;

	size_of_vec_sensor = vec_of_Sensors.size();
	cout << "mounting sensors in agents." << endl;
	//it is assumed that the corresponding sensors and agents and channels are always at the same
	//position in the different vectors, if not then you have to add an search algorithm for it.
	for(index = 0; index < size_of_vec_sensor; index++)
	{
		current_agent 			= vec_of_Agents[index];
		current_sensor 			= vec_of_Sensors[index];
		current_sensor_channel 	= vec_of_Channels_for_Sensors[index];
		mount_sensorInAgent(current_agent, current_sensor, current_sensor_channel);
	}
	cout << size_of_vec_sensor << " sensors in agents were mounted" << endl;
}

void mount_agents_in_agents()
{
	Agent* 			current_agent;
	Agent* 			viability_Monitor;
	Channel*	 	current_agent_channel;
	unsigned int 	size_of_vec_agents = 0;
	unsigned int 	index 				= 0;

	size_of_vec_agents = vec_of_Agents.size();
	//it is assumed that the viability agent is at the last postition in the vector
	viability_Monitor = vec_of_Agents[size_of_vec_agents-1];
	//all agents and channels are registered to the viabilityMonitor agent
	//so you have to subtract the viabilityMonitor from the number of elements to register
	//it is assumed that all the corresponding channels and agents are placed at the same index
	for(index = 0; index < size_of_vec_agents -1; index++)
	{
		current_agent 			= vec_of_Agents[index];
		current_agent_channel 	= vec_of_Channels_for_Agents[index];
		//only register if the agent is not the viability_monitor, otherwise you would register the viability monitor to itself.
		if(current_agent != viability_Monitor) {
			mount_agentInAgent(viability_Monitor, current_agent, current_agent_channel);
		}
	}
	cout << size_of_vec_agents -1 << "agents were registered to the viability monitor" << endl;
}

/*
 * registers the channels for the data agents to the viability monitor
 */
void register_data_agents_in_agent_state_Handler()

{
	Agent* 			viability_Monitor;
	Channel* 		current_agent_channel;
	unsigned int 	size_of_vec_channel_agents 	= 0;
	unsigned int 	index 						= 0;

	size_of_vec_channel_agents = vec_of_Channels_for_Agents.size();
	//get the agent for the viabilityMonitor, it is assumed that it is at the last position
	viability_Monitor = vec_of_Agents[vec_of_Agents.size()-1];
	//register all the channels to the viability monitor
	for(index = 0; index < size_of_vec_channel_agents; index++) {
		current_agent_channel = vec_of_Channels_for_Agents[index];
		registerSlaveAgentAsInputVariableInStateHandler(viability_Monitor, current_agent_channel);
	}
}

/*
 * creates and register all the different linear function blocks
 */
void create_linear_function_blocks()
{
	//don't change the sequence, because later it is assumed that the functions are
	//registered int the vector in this sequence
	//if you change it you have also to change the sequence in the function mount_function_blocks_to_viability_monitor
	create_same_state_deviation_function_block();
	create_another_state_deviation_function_block();
	create_state_time_function_block();
	create_another_state_time_function_block();
	create_valid_state_deviation_function_block();
	create_invalid_state_deviation_function_block();
	create_valid_state_time_function_block();
	create_invalid_state_time_function_block();
	create_confidence_state_drift_function_block();
	create_confidence_broken_function_block();
}

/*
 * creates and register the linear function block for same state deviation
 */
void create_same_state_deviation_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_SAME_STATE_DEV.c_str());
	LinearFunctionBlock* confSim2StateDev = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* funcConfSim2StateDev1 = new LinearFunction();
	funcConfSim2StateDev1->setDomain(false, true, (float)-OUTTER_BOUND_SIM_DIF);
	funcConfSim2StateDev1->setKandD((float)0, (float)0);
	confSim2StateDev->addLinearFunction(funcConfSim2StateDev1);
	LinearFunction* funcConfSim2StateDev2 = new LinearFunction();
	funcConfSim2StateDev2->setDomain(true, (float)-OUTTER_BOUND_SIM_DIF, true, (float)-INNER_BOUND_SIM_DIF);
	funcConfSim2StateDev2->setKandD((float)-OUTTER_BOUND_SIM_DIF, (float)0, (float)-INNER_BOUND_SIM_DIF, (float)1);
	confSim2StateDev->addLinearFunction(funcConfSim2StateDev2);
	LinearFunction* funcConfSim2StateDev3 = new LinearFunction();
	funcConfSim2StateDev3->setDomain(true, (float)-INNER_BOUND_SIM_DIF, true, (float)INNER_BOUND_SIM_DIF);
	funcConfSim2StateDev3->setKandD((float)0, (float)1);
	confSim2StateDev->addLinearFunction(funcConfSim2StateDev3);
	LinearFunction* funcConfSim2StateDev4 = new LinearFunction();
	funcConfSim2StateDev4->setDomain(true, (float)INNER_BOUND_SIM_DIF, true, (float)OUTTER_BOUND_SIM_DIF);
	funcConfSim2StateDev4->setKandD((float)INNER_BOUND_SIM_DIF, (float)1, (float)OUTTER_BOUND_SIM_DIF, (float)0);
	confSim2StateDev->addLinearFunction(funcConfSim2StateDev4);
	LinearFunction* funcConfSim2StateDev5 = new LinearFunction();
	funcConfSim2StateDev5->setDomain(true, (float)OUTTER_BOUND_SIM_DIF, false);
	funcConfSim2StateDev5->setKandD((float)0, (float)0);
	confSim2StateDev->addLinearFunction(funcConfSim2StateDev5);

	vec_of_linear_Function_Blocks.push_back(confSim2StateDev);
}

/*
 * creates and register another state deviation function block
 */
void create_another_state_deviation_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_ANOTHER_STATE_DEV.c_str());
	LinearFunctionBlock*  confDif2StateDev = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* funcConfDif2StateDev1 = new LinearFunction();
	funcConfDif2StateDev1->setDomain(false, true, (float)-OUTTER_BOUND_SIM_DIF);
	funcConfDif2StateDev1->setKandD((float)0, (float)1);
	confDif2StateDev->addLinearFunction(funcConfDif2StateDev1);
	LinearFunction* funcConfDif2StateDev2 = new LinearFunction();
	funcConfDif2StateDev2->setDomain(true, (float)-OUTTER_BOUND_SIM_DIF, true, (float)-INNER_BOUND_SIM_DIF);
	funcConfDif2StateDev2->setKandD((float)-OUTTER_BOUND_SIM_DIF, (float)1, (float)-INNER_BOUND_SIM_DIF, (float)0);
	confDif2StateDev->addLinearFunction(funcConfDif2StateDev2);
	LinearFunction* funcConfDif2StateDev3 = new LinearFunction();
	funcConfDif2StateDev3->setDomain(true, (float)-INNER_BOUND_SIM_DIF, true, (float)INNER_BOUND_SIM_DIF);
	funcConfDif2StateDev3->setKandD((float)0, (float)0);
	confDif2StateDev->addLinearFunction(funcConfDif2StateDev3);
	LinearFunction* funcConfDif2StateDev4 = new LinearFunction();
	funcConfDif2StateDev4->setDomain(true, (float)INNER_BOUND_SIM_DIF, true, (float)OUTTER_BOUND_SIM_DIF);
	funcConfDif2StateDev4->setKandD((float)INNER_BOUND_SIM_DIF, (float)0, (float)OUTTER_BOUND_SIM_DIF, (float)1);
	confDif2StateDev->addLinearFunction(funcConfDif2StateDev4);
	LinearFunction* funcConfDif2StateDev5 = new LinearFunction();
	funcConfDif2StateDev5->setDomain(true, (float)OUTTER_BOUND_SIM_DIF, false);
	funcConfDif2StateDev5->setKandD((float)0, (float)1);
	confDif2StateDev->addLinearFunction(funcConfDif2StateDev5);

	vec_of_linear_Function_Blocks.push_back(confDif2StateDev);
}

void create_state_time_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_SAME_TIME.c_str());
	LinearFunctionBlock* confSim2StateTime = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* funcConfSim2StateTime1 = new LinearFunction();
	funcConfSim2StateTime1->setDomain(false, true, (float)0);
	funcConfSim2StateTime1->setKandD((float)0, (float)0);
	confSim2StateTime->addLinearFunction(funcConfSim2StateTime1);
	LinearFunction* funcConfSim2StateTime2 = new LinearFunction();
	funcConfSim2StateTime2->setDomain(true, (float)0, true, (float)LENGTH);
	funcConfSim2StateTime2->setKandD((float)0, (float)0, (float)LENGTH, (float)1);
	confSim2StateTime->addLinearFunction(funcConfSim2StateTime2);
	LinearFunction* funcConfSim2StateTime3 = new LinearFunction();
	funcConfSim2StateTime3->setDomain(true, (float)LENGTH, false);
	funcConfSim2StateTime3->setKandD((float)0, (float)1);
	confSim2StateTime->addLinearFunction(funcConfSim2StateTime3);

	vec_of_linear_Function_Blocks.push_back(confSim2StateTime);
}

void create_another_state_time_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_ANOTHER_STATE_TIME.c_str());
	LinearFunctionBlock* confDif2StateTime = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* funcConfDif2StateTime1 = new LinearFunction();
	funcConfDif2StateTime1->setDomain(false, true, (float)0);
	funcConfDif2StateTime1->setKandD((float)0, (float)1);
	confDif2StateTime->addLinearFunction(funcConfDif2StateTime1);
	LinearFunction* funcConfDif2StateTime2 = new LinearFunction();
	funcConfDif2StateTime2->setDomain(true, (float)0, true, (float)LENGTH);
	funcConfDif2StateTime2->setKandD((float)0, (float)1, (float)LENGTH, (float)0);
	confDif2StateTime->addLinearFunction(funcConfDif2StateTime2);
	LinearFunction* funcConfDif2StateTime3 = new LinearFunction();
	funcConfDif2StateTime3->setDomain(true, (float)LENGTH, false);
	funcConfDif2StateTime3->setKandD((float)0, (float)0);
	confDif2StateTime->addLinearFunction(funcConfDif2StateTime3);

	vec_of_linear_Function_Blocks.push_back(confDif2StateTime);
}

void create_valid_state_deviation_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_VAILD_STATE_DEV.c_str());
	LinearFunctionBlock* confValidStateDev = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* funcConfValidStateDev1 = new LinearFunction();
	funcConfValidStateDev1->setDomain(false, true, (float)-OUTTER_BOUND_SIM_DIF);
	funcConfValidStateDev1->setKandD((float)0, (float)0);
	confValidStateDev->addLinearFunction(funcConfValidStateDev1);
	LinearFunction* funcConfValidStateDev2 = new LinearFunction();
	funcConfValidStateDev2->setDomain(true, (float)-OUTTER_BOUND_SIM_DIF, true, (float)-INNER_BOUND_SIM_DIF);
	funcConfValidStateDev2->setKandD((float)-OUTTER_BOUND_SIM_DIF, (float)0, (float)-INNER_BOUND_SIM_DIF, (float)1);
	confValidStateDev->addLinearFunction(funcConfValidStateDev2);
	LinearFunction* funcConfValidStateDev3 = new LinearFunction();
	funcConfValidStateDev3->setDomain(true, (float)-INNER_BOUND_SIM_DIF, true, (float)INNER_BOUND_SIM_DIF);
	funcConfValidStateDev3->setKandD((float)0, (float)1);
	confValidStateDev->addLinearFunction(funcConfValidStateDev3);
	LinearFunction* funcConfValidStateDev4 = new LinearFunction();
	funcConfValidStateDev4->setDomain(true, (float)INNER_BOUND_SIM_DIF, true, (float)OUTTER_BOUND_SIM_DIF);
	funcConfValidStateDev4->setKandD((float)INNER_BOUND_SIM_DIF, (float)1, (float)OUTTER_BOUND_SIM_DIF, (float)0);
	confValidStateDev->addLinearFunction(funcConfValidStateDev4);
	LinearFunction* funcConfValidStateDev5 = new LinearFunction();
	funcConfValidStateDev5->setDomain(true, (float)OUTTER_BOUND_SIM_DIF, false);
	funcConfValidStateDev5->setKandD((float)0, (float)0);
	confValidStateDev->addLinearFunction(funcConfValidStateDev5);

	vec_of_linear_Function_Blocks.push_back(confValidStateDev);
}

void create_invalid_state_deviation_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_INVALID_STATE_DEV.c_str());
	LinearFunctionBlock* confInvalidStateDev = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* funcConfInvalidStateDev1 = new LinearFunction();
	funcConfInvalidStateDev1->setDomain(false, true, (float)-OUTTER_BOUND_SIM_DIF);
	funcConfInvalidStateDev1->setKandD((float)0, (float)1);
	confInvalidStateDev->addLinearFunction(funcConfInvalidStateDev1);
	LinearFunction* funcConfInvalidStateDev2 = new LinearFunction();
	funcConfInvalidStateDev2->setDomain(true, (float)-OUTTER_BOUND_SIM_DIF, true, (float)-INNER_BOUND_SIM_DIF);
	funcConfInvalidStateDev2->setKandD((float)-OUTTER_BOUND_SIM_DIF, (float)1, (float)-INNER_BOUND_SIM_DIF, (float)0);
	confInvalidStateDev->addLinearFunction(funcConfInvalidStateDev2);
	LinearFunction* funcConfInvalidStateDev3 = new LinearFunction();
	funcConfInvalidStateDev3->setDomain(true, (float)-INNER_BOUND_SIM_DIF, true, (float)INNER_BOUND_SIM_DIF);
	funcConfInvalidStateDev3->setKandD((float)0, (float)0);
	confInvalidStateDev->addLinearFunction(funcConfInvalidStateDev3);
	LinearFunction* funcConfInvalidStateDev4 = new LinearFunction();
	funcConfInvalidStateDev4->setDomain(true, (float)INNER_BOUND_SIM_DIF, true, (float)OUTTER_BOUND_SIM_DIF);
	funcConfInvalidStateDev4->setKandD((float)INNER_BOUND_SIM_DIF, (float)0, (float)OUTTER_BOUND_SIM_DIF, (float)1);
	confInvalidStateDev->addLinearFunction(funcConfInvalidStateDev4);
	LinearFunction* funcConfInvalidStateDev5 = new LinearFunction();
	funcConfInvalidStateDev5->setDomain(true, (float)OUTTER_BOUND_SIM_DIF, false);
	funcConfInvalidStateDev5->setKandD((float)0, (float)1);
	confInvalidStateDev->addLinearFunction(funcConfInvalidStateDev5);

	vec_of_linear_Function_Blocks.push_back(confInvalidStateDev);
}

void create_valid_state_time_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_VALID_STATE_TIME.c_str());
	LinearFunctionBlock* confValidStateTime = new LinearFunctionBlock("funcBlock:confValidStateTime");
	LinearFunction* funcConfValidStateTime1 = new LinearFunction();
	funcConfValidStateTime1->setDomain(false, true, (float)0);
	funcConfValidStateTime1->setKandD((float)0, (float)0);
	confValidStateTime->addLinearFunction(funcConfValidStateTime1);
	LinearFunction* funcConfValidStateTime2 = new LinearFunction();
	funcConfValidStateTime2->setDomain(true, (float)0, true, (float)LENGTH);				//10
	funcConfValidStateTime2->setKandD((float)0, (float)0, (float)LENGTH, (float)1);
	confValidStateTime->addLinearFunction(funcConfValidStateTime2);
	LinearFunction* funcConfValidStateTime3 = new LinearFunction();
	funcConfValidStateTime3->setDomain(true, (float)LENGTH, false);
	funcConfValidStateTime3->setKandD((float)0, (float)1);
	confValidStateTime->addLinearFunction(funcConfValidStateTime3);

	vec_of_linear_Function_Blocks.push_back(confValidStateTime);
}
void create_invalid_state_time_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_INVALID_STATE_TIME.c_str());
	LinearFunctionBlock* confInvalidStateTime = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* funcConfInvalidStateTime1 = new LinearFunction();
	funcConfInvalidStateTime1->setDomain(false, true, (float)0);
	funcConfInvalidStateTime1->setKandD((float)0, (float)1);
	confInvalidStateTime->addLinearFunction(funcConfInvalidStateTime1);
	LinearFunction* funcConfInvalidStateTime2 = new LinearFunction();
	funcConfInvalidStateTime2->setDomain(true, (float)0, true, (float)LENGTH);
	funcConfInvalidStateTime2->setKandD((float)0, (float)1, (float)LENGTH, (float)0);
	confInvalidStateTime->addLinearFunction(funcConfInvalidStateTime2);
	LinearFunction* funcConfInvalidStateTime3 = new LinearFunction();
	funcConfInvalidStateTime3->setDomain(true, (float)LENGTH, false);
	funcConfInvalidStateTime3->setKandD((float)0, (float)0);
	confInvalidStateTime->addLinearFunction(funcConfInvalidStateTime3);

	vec_of_linear_Function_Blocks.push_back(confInvalidStateTime);
}

void create_confidence_state_drift_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_CONFIDENCE_STATE_DRIFTS.c_str());
	LinearFunctionBlock* confStateDrifts = new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* functionConfidenceDriftDeviation1 = new LinearFunction();
	functionConfidenceDriftDeviation1->setDomain(false, true, (float)-OUTTER_BOUND_DRIFT);
	functionConfidenceDriftDeviation1->setKandD((float)0, (float)1);
	confStateDrifts->addLinearFunction(functionConfidenceDriftDeviation1);
	LinearFunction* functionConfidenceDriftDeviation2 = new LinearFunction();
	functionConfidenceDriftDeviation2->setDomain(true, (float)-OUTTER_BOUND_DRIFT, true, (float)-INNER_BOUND_DRIFT);
	functionConfidenceDriftDeviation2->setKandD((float)-INNER_BOUND_DRIFT, (float)1, (float)-INNER_BOUND_DRIFT, (float)0);
	confStateDrifts->addLinearFunction(functionConfidenceDriftDeviation2);
	LinearFunction* functionConfidenceDriftDeviation3 = new LinearFunction();
	functionConfidenceDriftDeviation3->setDomain(true, (float)-INNER_BOUND_DRIFT, true, (float)INNER_BOUND_DRIFT);
	functionConfidenceDriftDeviation3->setKandD((float)0, (float)0);
	confStateDrifts->addLinearFunction(functionConfidenceDriftDeviation3);
	LinearFunction* functionConfidenceDriftDeviation4 = new LinearFunction();
	functionConfidenceDriftDeviation4->setDomain(true, (float)INNER_BOUND_DRIFT, true, (float)OUTTER_BOUND_DRIFT);
	functionConfidenceDriftDeviation4->setKandD((float)INNER_BOUND_DRIFT, (float)0, (float)OUTTER_BOUND_DRIFT, (float)1);
	confStateDrifts->addLinearFunction(functionConfidenceDriftDeviation4);
	LinearFunction* functionConfidenceDriftDeviation5 = new LinearFunction();
	functionConfidenceDriftDeviation5->setDomain(true, (float)OUTTER_BOUND_DRIFT, false);
	functionConfidenceDriftDeviation5->setKandD((float)0, (float)1);
	confStateDrifts->addLinearFunction(functionConfidenceDriftDeviation5);

	vec_of_linear_Function_Blocks.push_back(confStateDrifts);
}

void create_confidence_broken_function_block()
{
	char* c_name_of_current_func_block = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_func_block, FUNC_BLOCK_NAME_CONFIDENCE_BROKEN.c_str());
	LinearFunctionBlock* confBroken	= new LinearFunctionBlock(c_name_of_current_func_block);
	LinearFunction* functionConfidenceBroken1 = new LinearFunction();
	functionConfidenceBroken1->setDomain(false, true, (float)0);
	functionConfidenceBroken1->setKandD((float)0, (float)0);
	confBroken->addLinearFunction(functionConfidenceBroken1);
	LinearFunction* functionConfidenceBroken2 = new LinearFunction();
	functionConfidenceBroken2->setDomain(true, (float)0, true, (float)BOUND_BROKEN);
	functionConfidenceBroken2->setKandD((float)0, (float)0, (float)BOUND_BROKEN, (float)1);
	confBroken->addLinearFunction(functionConfidenceBroken2);
	LinearFunction* functionConfidenceBroken3 = new LinearFunction();
	functionConfidenceBroken3->setDomain(true, (float)BOUND_BROKEN, false);
	functionConfidenceBroken3->setKandD((float)0, (float)1);
	confBroken->addLinearFunction(functionConfidenceBroken3);

	vec_of_linear_Function_Blocks.push_back(confBroken);
}

/*
 * mount the different function blocks to the viability monitior agent
 */
void mount_function_blocks_to_viability_monitor()
{
	Agent* 					viability_Monitor;
	LinearFunctionBlock*	current_Linear_Function_Bock;
	unsigned int 			size_of_vec_lin_func_block 	= vec_of_linear_Function_Blocks.size();
	unsigned int 			index 						= 0;

	//it is assumed that the viability monitor is at the last position of the vector of agents
	viability_Monitor = vec_of_Agents[vec_of_Agents.size()-1];
	for(index = 0; index < size_of_vec_lin_func_block; index++) {
		current_Linear_Function_Bock = vec_of_linear_Function_Blocks[index];
		//it is assumed that the function blocks are added into the vector in the following sequence
		switch(index) {
			case 0:
				viability_Monitor->get_stateHandler()->FuncBlockConfSim2StateDev = current_Linear_Function_Bock;
				break;
			case 1:
				viability_Monitor->get_stateHandler()->FuncBlockConfDif2StateDev = current_Linear_Function_Bock;
				break;
			case 2:
				viability_Monitor->get_stateHandler()->FuncBlockConfSim2StateTime = current_Linear_Function_Bock;
				break;
			case 3:
				viability_Monitor->get_stateHandler()->FuncBlockConfDif2StateTime = current_Linear_Function_Bock;
				break;
			case 4:
				viability_Monitor->get_stateHandler()->FuncBlockConfValStateDev = current_Linear_Function_Bock;
				break;
			case 5:
				viability_Monitor->get_stateHandler()->FuncBlockConfInvStateDev = current_Linear_Function_Bock;
				break;
			case 6:
				viability_Monitor->get_stateHandler()->FuncBlockConfValStateTime = current_Linear_Function_Bock;
				break;
			case 7:
				viability_Monitor->get_stateHandler()->FuncBlockConfInvStateTime = current_Linear_Function_Bock;
				break;
			case 8:
				viability_Monitor->get_stateHandler()->DriftDeviation = current_Linear_Function_Bock;
				break;
			case 9:
				viability_Monitor->get_stateHandler()->FuncBlockConfBrokenSamples = current_Linear_Function_Bock;
				break;
		}
	}
}


void create_all_testbenches() {
	char* c_name_of_current_testbench = new char[MAX_LENGTH_NAME];
	strcpy(c_name_of_current_testbench, TEST_BENCH.c_str());
	cout << "Creating testbench" << endl;
	Testbench* tb = create_testbench(c_name_of_current_testbench);
	vec_of_test_benches.push_back(tb);
}

void create_csvr_modules()
{
	//sets the row in which the data is available
	unsigned int row = 2;
	char* c_name_of_current_csv_module = new char[MAX_LENGTH_NAME];
	string current_reader_path_and_file_name;
	cout << "Creating CSV Reader Modules" << endl;

	current_reader_path_and_file_name 	= PATH_TO_CSV_DATA_FILES + PATH_TO_DATE_OF_MEASUREMENT + PATH_TO_AN_MEASURMENT + FILE_NAME_VOLTAGE;
	strcpy(c_name_of_current_csv_module, FIRST_MEASURED_DATA_CSV_NAME.c_str());
	CSVreaderModule* csvr_Pump_Voltage 	= create_CSVreaderModule(c_name_of_current_csv_module,current_reader_path_and_file_name.c_str(),2,row);

	current_reader_path_and_file_name 	= PATH_TO_CSV_DATA_FILES + PATH_TO_DATE_OF_MEASUREMENT + PATH_TO_AN_MEASURMENT + FILE_NAME_TEMP_1;
	strcpy(c_name_of_current_csv_module, SECOND_MEASURED_DATA_CSV_NAME.c_str());
	CSVreaderModule* csvr_Temp_1		 	= create_CSVreaderModule(c_name_of_current_csv_module,current_reader_path_and_file_name.c_str(),2,row);

	current_reader_path_and_file_name 	= PATH_TO_CSV_DATA_FILES + PATH_TO_DATE_OF_MEASUREMENT + PATH_TO_AN_MEASURMENT + FILE_NAME_TEMP_2;
	strcpy(c_name_of_current_csv_module, THIRD_MEASURED_DATA_CSV_NAME.c_str());
	CSVreaderModule* csvr_Temp_2		 	= create_CSVreaderModule(c_name_of_current_csv_module,current_reader_path_and_file_name.c_str(),2,row);

	current_reader_path_and_file_name 	= PATH_TO_CSV_DATA_FILES + PATH_TO_DATE_OF_MEASUREMENT + PATH_TO_AN_MEASURMENT + FILE_NAME_SHARKY_S;
	strcpy(c_name_of_current_csv_module, FOURTH_MEASURED_DATA_CSV_NAME.c_str());
	CSVreaderModule* csvr_Sharky_S	 	= create_CSVreaderModule(c_name_of_current_csv_module,current_reader_path_and_file_name.c_str(),2,row);

	current_reader_path_and_file_name 	= PATH_TO_CSV_DATA_FILES + PATH_TO_DATE_OF_MEASUREMENT + PATH_TO_AN_MEASURMENT + FILE_NAME_SHARKY_B;
	strcpy(c_name_of_current_csv_module, FIFTH_MEASURED_DATA_CSV_NAME.c_str());
	CSVreaderModule* csvr_Sharky_B	 	= create_CSVreaderModule(c_name_of_current_csv_module,current_reader_path_and_file_name.c_str(),2,row);

	current_reader_path_and_file_name 	= PATH_TO_CSV_DATA_FILES + PATH_TO_DATE_OF_MEASUREMENT + PATH_TO_AN_MEASURMENT + FILE_NAME_RIELS;
	strcpy(c_name_of_current_csv_module, SIXTH_MEASURED_DATA_CSV_NAME.c_str());
	CSVreaderModule* csvr_RIELS	 		= create_CSVreaderModule(c_name_of_current_csv_module,current_reader_path_and_file_name.c_str(),2,row);

	current_reader_path_and_file_name 	= PATH_TO_CSV_DATA_FILES + PATH_TO_DATE_OF_MEASUREMENT + PATH_TO_AN_MEASURMENT + FILE_NAME_DYNA;
	strcpy(c_name_of_current_csv_module, SEVENTH_MEASURED_DATA_CSV_NAME.c_str());
	CSVreaderModule* csvr_Dyna	 		= create_CSVreaderModule(c_name_of_current_csv_module,current_reader_path_and_file_name.c_str(),2,row);

	vec_of_csv_readers.push_back(csvr_Pump_Voltage);
	vec_of_csv_readers.push_back(csvr_Temp_1);
	vec_of_csv_readers.push_back(csvr_Temp_2);
	vec_of_csv_readers.push_back(csvr_Sharky_S);
	vec_of_csv_readers.push_back(csvr_Sharky_B);
	vec_of_csv_readers.push_back(csvr_RIELS);
	vec_of_csv_readers.push_back(csvr_Dyna);
}

/*
 * all agents would be registered to all testbenches
 */
void register_agents_in_testbenches()
{
	Testbench* 		current_tb;
	unsigned int 	size_of_vec_test_benches 	= vec_of_test_benches.size();
	unsigned int 	index_tb 					= 0;
	Agent* 			current_ag;
	unsigned int 	size_of_vec_agents 	= vec_of_Agents.size();
	unsigned int 	index_agents 		= 0;

	cout << "registering agents in testbenches" << endl;
	for(index_tb = 0; index_tb < size_of_vec_test_benches; index_tb++) {
		current_tb = vec_of_test_benches[index_tb];
		for(index_agents = 0; index_agents < size_of_vec_agents; index_agents++) {
			current_ag = vec_of_Agents[index_agents];
			register_agentInTestbench(current_tb, current_ag);
		}
	}
	cout << size_of_vec_agents << " agents were registered in every of the " << size_of_vec_test_benches << " testbenches" << endl;
}

/*
 * registering the sensors and the corresponding csv-readers in the testbenches
 * it is assumed that the csv readers and the sensors are at the same index position
 * in the vectors.
 */
void register_sensors_in_testbenches()
{
	Testbench* 			current_tb;
	unsigned int 		size_of_vec_test_benches 	= vec_of_test_benches.size();
	unsigned int 		index_tb 					= 0;
	Sensor* 			current_se;
	unsigned int 		size_of_vec_sensors 		= vec_of_Sensors.size();
	unsigned int 		index_sensors 				= 0;
	CSVreaderModule*	current_csv_reader;
	unsigned int 		size_of_vec_csv_reader 		= vec_of_csv_readers.size();

	if(size_of_vec_csv_reader != size_of_vec_sensors) {
		cout << "Error, in sequence of data processing";
		cout << "Number of csv-readers should be equal to number of sensors" << endl;
	}
	else {
		cout << "Registering sensors and their csv-readers in testbenches " << endl;
		for(index_tb = 0; index_tb < size_of_vec_test_benches; index_tb++) {
			current_tb = vec_of_test_benches[index_tb];
			for(index_sensors = 0; index_sensors < size_of_vec_sensors; index_sensors++) {
				current_se 			= vec_of_Sensors[index_sensors];
				//it is assumed that the sensor and the corresponding csv-reader is stored
				//at the same position in the two different vectors
				current_csv_reader 	= vec_of_csv_readers[index_sensors];
				register_sensorInTestbench(current_tb, current_se, current_csv_reader);
			}
		}
		cout << size_of_vec_sensors << " Sensors and their csv-readers were registered to ";
		cout << "every of the " << size_of_vec_test_benches << " testbenches" << endl;
	}
}

void register_channels_in_testbenches()
{
	register_channels_of_sensors_in_testbenches();

	register_channels_of_actors_in_testbenches();
}

void register_channels_of_sensors_in_testbenches()
{
	Testbench* 		current_tb;
	unsigned int 	size_of_vec_test_benches 	= vec_of_test_benches.size();
	unsigned int 	index_tb 					= 0;
	Channel*	 	current_se_ch;
	unsigned int 	size_of_vec_se_channel 		= vec_of_Channels_for_Sensors.size();
	unsigned int 	index_se_ch 				= 0;

	cout << "Registering channels of sensors in testbench" << endl;
	for(index_tb = 0; index_tb < size_of_vec_test_benches; index_tb++) {
		current_tb = vec_of_test_benches[index_tb];
		for(index_se_ch = 0; index_se_ch < size_of_vec_se_channel; index_se_ch++) {
			current_se_ch = vec_of_Channels_for_Sensors[index_se_ch];
			register_channelInTestbench(current_tb, current_se_ch);
		}
	}
	cout << size_of_vec_se_channel << " channels of sensors were registered in ";
	cout << size_of_vec_test_benches << " testbenches." << endl;

}

void register_channels_of_actors_in_testbenches()
{
	Testbench* 		current_tb;
	unsigned int 	size_of_vec_test_benches 	= vec_of_test_benches.size();
	unsigned int 	index_tb 					= 0;
	Channel* 		current_se_ch;
	unsigned int 	size_of_vec_ag_channel 		= vec_of_Channels_for_Agents.size();
	unsigned int 	index_se_ch 				= 0;

	cout << "Registering channels of agents in testbench" << endl;
	for(index_tb = 0; index_tb < size_of_vec_test_benches; index_tb++) {
		current_tb = vec_of_test_benches[index_tb];
		for(index_se_ch = 0; index_se_ch < size_of_vec_ag_channel; index_se_ch++) {
			current_se_ch = vec_of_Channels_for_Agents[index_se_ch];
			register_channelInTestbench(current_tb, current_se_ch);
		}
	}
	cout << size_of_vec_ag_channel << " channels of agents were registered in ";
	cout << size_of_vec_test_benches << " testbenches." << endl;
}

void run_simulation_of_all_testbenches()
{

	string 			pressed_key;
	Testbench* 		current_tb;
	unsigned int 	size_of_vec_test_benches = vec_of_test_benches.size();
	unsigned int 	index_tb = 0;
	unsigned int 	sim_rounds = 1000;

	cout << "Press any key to start the simulation of all testbenches." << endl;
	getline(cin, pressed_key);
	for(index_tb = 0; index_tb < size_of_vec_test_benches; index_tb++){
		current_tb = vec_of_test_benches[index_tb];
		current_tb->simulate(sim_rounds);
	}
	cout << "Simulation of " << size_of_vec_test_benches << " testbenches successfully finished" << endl;
}
