#ifndef TESTBENCH_HEADERFILE
#define TESTBENCH_HEADERFILE

#include <vector>
#include "AgentSlotOfTestbench.h"
#include "ChannelSlotOfTestbench.h"
#include "CSVreaderModule.h"
#include "SensorSlotOfTestbench.h"
#include "Unit.h"
#include "Agent.h"
#include "Testbench_Config.h"


/*
#include "Agent.h"
#include "Channel.h"
#include "CSVreader.h"
#include "CSV_Writer.h"

#define MAX_NUM_OF_AGENTS 20
#define MAX_NUM_OF_CHANNELS 80
#define MAX_NUM_OF_SENSORS 20
*/
using namespace std;

//definitions for the linear function blocks, with their associated linear function names
//first name of the linear function block and then the names of the linear functions registered
//within this function block, is later used to identify the right linear function
//to parameterize it correctly.
const string FUNC_BLOCK_NAME_SAME_STATE_DEV				= "funcBlock:confSim2StateDev";
const string CONF_SIM2_STATE_DEV_1						= "ConfSim2StateDev1";
const string CONF_SIM2_STATE_DEV_2						= "ConfSim2StateDev2";
const string CONF_SIM2_STATE_DEV_3						= "ConfSim2StateDev3";
const string CONF_SIM2_STATE_DEV_4						= "ConfSim2StateDev4";
const string CONF_SIM2_STATE_DEV_5						= "ConfSim2StateDev5";
const string FUNC_BLOCK_NAME_ANOTHER_STATE_DEV 			= "funcBlock:confDif2StateDev";
const string CONF_DIF2_STATE_DEV_1						= "ConfDif2StateDev1";
const string CONF_DIF2_STATE_DEV_2						= "ConfDif2StateDev2";
const string CONF_DIF2_STATE_DEV_3						= "ConfDif2StateDev3";
const string CONF_DIF2_STATE_DEV_4						= "ConfDif2StateDev4";
const string CONF_DIF2_STATE_DEV_5						= "ConfDif2StateDev5";
const string FUNC_BLOCK_NAME_SAME_TIME 					= "funcBlock:confSim2StateTime";
const string CONF_SIM2_STATE_TIME_1						= "ConfSim2StateTime1";
const string CONF_SIM2_STATE_TIME_2						= "ConfSim2StateTime2";
const string CONF_SIM2_STATE_TIME_3						= "ConfSim2StateTime3";
const string FUNC_BLOCK_NAME_ANOTHER_STATE_TIME 		= "funcBlock:confDif2StateTime";
const string CONF_DIF2_STATE_TIME_1						= "ConfDif2StateTime1";
const string CONF_DIF2_STATE_TIME_2						= "ConfDif2StateTime2";
const string CONF_DIF2_STATE_TIME_3						= "ConfDif2StateTime3";
const string FUNC_BLOCK_NAME_VAILD_STATE_DEV 			= "funcBlock:confValidStateDev";
const string CONF_VALID_STATE_DEV_1						= "ConfValidStateDev1";
const string CONF_VALID_STATE_DEV_2						= "ConfValidStateDev2";
const string CONF_VALID_STATE_DEV_3						= "ConfValidStateDev3";
const string CONF_VALID_STATE_DEV_4						= "ConfValidStateDev4";
const string CONF_VALID_STATE_DEV_5						= "ConfValidStateDev5";
const string FUNC_BLOCK_NAME_INVALID_STATE_DEV 			= "funcBlock:confInvalidStateDev";
const string CONF_INVALID_STATE_DEV_1					= "ConfInvalidStateDev1";
const string CONF_INVALID_STATE_DEV_2					= "ConfInvalidStateDev2";
const string CONF_INVALID_STATE_DEV_3					= "ConfInvalidStateDev3";
const string CONF_INVALID_STATE_DEV_4					= "ConfInvalidStateDev4";
const string CONF_INVALID_STATE_DEV_5					= "ConfInvalidStateDev5";
const string FUNC_BLOCK_NAME_VALID_STATE_TIME			= "funcBlock:confValidStateTime";
const string VALID_STATE_TIME_1							= "ValidStateTime1";
const string VALID_STATE_TIME_2							= "ValidStateTime2";
const string VALID_STATE_TIME_3							= "ValidStateTime3";
const string FUNC_BLOCK_NAME_INVALID_STATE_TIME 		= "funcBlock:confInvalidStateTime";
const string INVALID_STATE_TIME_1						= "InvalidStateTime1";
const string INVALID_STATE_TIME_2						= "InvalidStateTime2";
const string INVALID_STATE_TIME_3						= "InvalidStateTime3";
const string FUNC_BLOCK_NAME_CONFIDENCE_STATE_DRIFTS 	= "confidence:confStateDrifts";
const string CONFIDENCE_DRIFT_DEVIATION_1				= "ConfidenceDriftDeviation1";
const string CONFIDENCE_DRIFT_DEVIATION_2				= "ConfidenceDriftDeviation2";
const string CONFIDENCE_DRIFT_DEVIATION_3				= "ConfidenceDriftDeviation3";
const string CONFIDENCE_DRIFT_DEVIATION_4				= "ConfidenceDriftDeviation4";
const string CONFIDENCE_DRIFT_DEVIATION_5				= "ConfidenceDriftDeviation5";
const string FUNC_BLOCK_NAME_CONFIDENCE_BROKEN 			= "confidence:broken";
const string CONFIDENCE_BROKEN_1						= "ConfidenceBroken1";
const string CONFIDENCE_BROKEN_2						= "ConfidenceBroken2";
const string CONFIDENCE_BROKEN_3						= "ConfidenceBroken3";

class Testbench : public Module {

	private:
		//TODO: set- and get function for maxNumOf_registeredAgents;
		vector<AgentSlotOfTestbench*> 	vector_registeredAgents;


		//TODO: set- and get function for maxNumOf_registeredChannels;
		vector<ChannelSlotOfTestbench*> vector_registeredChannels;


		//TODO: set- and get function for maxNumOf_registeredSensors;
		vector<SensorSlotOfTestbench*> 	vector_registeredSensors;

		vector<Testbench_Config*>		vector_registered_Configs;
		void remove_all_Testbench_Configs();
		void remove_all_Agents();
		void remove_all_Channels();
		void remove_all_Sensors();

		void set_parameters_FuncBlockConfSim2StateDev(LinearFunctionBlock* FuncBlockConfSim2StateDev);
		void set_parameters_FuncBlockConfDif2StateDev(LinearFunctionBlock* FuncBlockConfDif2StateDev);
		void set_parameters_FuncBlockConfSim2StateTime(LinearFunctionBlock* FuncBlockConfSim2StateTime);
		void set_parameters_FuncBlockConfDif2StateTime(LinearFunctionBlock* FuncBlockConfDif2StateTime);
		void set_parameters_FuncBlockConfValStateDev(LinearFunctionBlock* FuncBlockConfValStateDev);
		void set_parameters_FuncBlockConfInvStateDev(LinearFunctionBlock* FuncBlockConfInvStateDev);
		void set_parameters_FuncBlockConfValStateTime(LinearFunctionBlock* FuncBlockConfValStateTime);
		void set_parameters_FuncBlockConfInvStateTime(LinearFunctionBlock* FuncBlockConfInvStateTime);
		void set_parameters_DriftDeviation(LinearFunctionBlock* DriftDeviation);
		void set_parameters_FuncBlockConfBrokenSamples(LinearFunctionBlock* FuncBlockConfBrokenSamples);


	public:
		static const unsigned int MAXNUM_OF_REGISTERED_AGENTS = 1000;

		static const unsigned int MAXNUM_OF_REGISTERED_CHANNELS = 1000;

		static const unsigned int MAXNUM_OF_REGISTERED_SENSORS = 1000;

		Testbench();
		Testbench(char* name);

		void init_testbench();

		bool register_agent(Agent* agent);

		bool register_sensor(Sensor* sensor);
		SensorSlotOfTestbench* get_sensorSlotAddressOfTestbench(Sensor* sensor);

		bool register_channel(Channel* channel);

		bool register_testbench_config(Testbench_Config* tb_config);
		vector<Testbench_Config*>& get_all_registered_testbench_configs();
		void set_current_tb_config_index(const int index);
		Testbench_Config* get_current_Testbench_config();

		void set_config_values_in_linear_functions();

		bool free_resources();

		void set_CSV_Writer_parameter();

		void set_CSV_Reader_row(const int start_row);
		void set_CSV_Reader_to_beginning();

		void reset_States();
		void reset_States_and_Slave_Agents();

		void simulate(unsigned int rounds);

		vector<AgentSlotOfTestbench*>& get_all_registeredAgents();

		~Testbench();



	
	/*
	private:

		unsigned int num_of_registered_agents;
		Agent* registered_agents[MAX_NUM_OF_AGENTS];

		unsigned int num_of_registered_channels;
		Channel* registered_channels[MAX_NUM_OF_CHANNELS];

		unsigned int num_of_registered_sensors;
		Sensor* registered_sensors[MAX_NUM_OF_SENSORS];
		CSV_Reader* registered_sensors_csvr[MAX_NUM_OF_SENSORS];
		bool flag_sensor_has_csvr[MAX_NUM_OF_SENSORS];

		//csv
		CSV_Reader* csv_reader;
		bool flag_csv_reader_exist;

		CSV_Writer* csv_writer;
		bool flag_csv_writer_exist;

	public:
		Testbench();
		Testbench(char* name);

		void simulate();

		//for agents:
		unsigned int get_num_of_registered_agents();
		bool register_agent(Agent* agent);
		bool deregister_agent(Agent* agent);
		bool deregister_agent(unsigned int agent_ix);
		bool get_ix_of_agent(Agent* agent, unsigned int *agent_ix);

		//for sensors:
		unsigned int get_num_of_registered_sensors();
		bool register_sensor(Sensor* sensor);
		bool register_sensor(Sensor* sensor, CSV_Reader *csvr);
		bool deregister_sensor(Sensor* sensor);
		bool deregister_sensor(unsigned int sensor_ix);
		bool get_ix_of_sensor(Sensor* sensor, unsigned int *sensor_ix);
		bool get_flag_sensor_has_csvr(unsigned int sensor_ix);
		CSV_Reader* get_registered_sensors_csvr(unsigned int sensor_ix);
		CSV_Reader* get_registered_sensors_csvr(Sensor* sensor);



		//for channels:
		unsigned int get_num_of_registered_channels();
		bool register_channel(Channel* channel);
		bool deregister_channel(Channel* channel);
		bool deregister_channel(unsigned int channel_ix);
		bool get_ix_of_channel(Channel* channel, unsigned int *channel_ix);

		//csv
		bool register_csv_reader(CSV_Reader* csv_reader);
		bool register_csv_writer(CSV_Writer* csv_writer);
		*/
};


#endif
