#ifndef AGENT_HEADERFILE
#define AGENT_HEADERFILE

#include "HistoryController.h"
#include "MasterAgentHandlerOfAgent.h"
#include "Node.h"
#include "SensorHandlerOfAgent.h"
#include "SlaveAgentHandlerOfAgent.h"
#include "StateHandler.h"
#include "StabilityController.h"

//SHORTCUT/WORKAUROUND -> TODO: make this better!
#include "AbstractionModule.h"
#include "ReliabilityModule.h"
#include "ScoreConfidenceModule.h"
#include "CrossReliabilityProfileModule.h"

#include <list>


class Agent : public Node {

	private :

		SensorHandlerOfAgent* sensorHandlerOfAgent;
		SlaveAgentHandlerOfAgent* slaveAgentHandlerOfAgent;
		MasterAgentHandlerOfAgent* masterAgentHandlerOfAgent;

		//History Controller
		HistoryController* historyController;

		//State Controller
		StateHandler* stateHandler;

		//Stability Controller
		StabilityController* stabilityController;

		//StabilityModule* stabilityModule;


		unsigned int workingCycleCounter;

		void init_agent();


		//SHORTCUT/WORKAUROUND -> TODO: make this better!
		AbstractionModule *abstractionModule;
		ReliabilityModule *reliabilityModule;
		int agentScore;
		CSV_Writer *csvWriter;
		CSV_Writer *secondCsvWriter;

		//New for Journal - SHORTCUT/WORKAUROUND -> TODO: make this better!
		ScoreConfidenceModule* scoreConfidenceModule;
		int lastEwsScore;
		float lastReliability;


		LinearFunctionBlock* confChangeRightDiff;
		LinearFunctionBlock* confChangeWrongDiff;
		LinearFunctionBlock* confChangeRightTime; 
		LinearFunctionBlock* confChangeWrongTime;


		LinearFunctionBlock* confTimeScoreHasBeen;
		unsigned int maxHistSizePossScores;


		float crossReliabilityParameter;


		PossibleScore* lastScore;
		unsigned int timeSinceChange;

		unsigned int scoreHistoryLength;
		list<PossibleScore*> scoreHistory;
		

		list<vector<PossibleScore*>*> possibleScoreHistory;

		CrossReliabilityProfileModule* crossReliabilityProfileModule;


		float crossReliabilityNEW(SlaveAgentSlotOfAgent* slaveAgent, vector<SlaveAgentSlotOfAgent*>* slaveAgents, SlaveAgentSlotOfAgent* excludeSlaveAgent, int mode, int theoreticalScore);
		float crossReliabilityNEW(SlaveAgentSlotOfAgent* slaveAgent, vector<SlaveAgentSlotOfAgent*>* slaveAgents, int mode, int theoreticalScore);

		/*
		LinearFunctionBlock* confidenceScoreChangeRight;
		LinearFunctionBlock* confidenceScoreChangeWrong;
		*/

		float getInputReliability(SensorSlotOfAgent* mountedAgent, float actualSensorValue);
		void combineConfidenceAndReliabilityOfActualPossibleScores(vector<PossibleScore*>* actualPossibleScores, float inputReliability);
		void saveActualPossibleScoresInHistory(vector<PossibleScore*>* actualPossibleScores);
		void getAllPossibleScoresBasedOnHistory(vector<PossibleScore*>* possibleScores);
		void sendPossibleScoresToMaster(vector<PossibleScore*>* possibleScores);
		void sendMostLikelyScoreToMaster(vector<PossibleScore*>* possibleScores);
		void triggerLowLevelAgent();
		void calculateAllPossibleScores(vector<PossibleScore*>* possibleEWSs);
		void removeDuplicatesOfScores(vector<PossibleScore*>* possibleEWSs);
		void justSumScoresUp(int* EWS, float* reliability);
		void triggerHighLevelAgent();


	public:
		Agent();
		Agent(string name);

		//TODO: do this in all classes where memory was allocated
		~Agent();

		bool set_sensorHandlerOfAgent();
		bool del_sensorHandlerOfAgent();
		SensorHandlerOfAgent* get_sensorHandlerOfAgent();
		
		bool set_slaveAgentHandlerOfAgent();
		bool del_slaveAgentHandlerOfAgent();
		SlaveAgentHandlerOfAgent* get_slaveAgentHandlerOfAgent();

		bool set_masterAgentHandlerOfAgent();
		bool del_masterAgentHandlerOfAgent();
		MasterAgentHandlerOfAgent* get_masterAgentHandlerOfAgent();

		bool set_stateHandler();
		bool set_stateHandler(StateHandler* stateHandler);
		bool del_stateHandler();
		StateHandler* get_stateHandler();
		
		bool setHistoryController();
		bool setHistoryController(HistoryController* historyController);
		bool delHistoryController();
		HistoryController* getHistoryController();

		bool setStabilityController();
		bool setStabilityController(StabilityController* stabilityController);
		bool delStabilityController();
		StabilityController* getStabilityController();

		/*
		bool mountStabilityModule(StabilityModule* stabilityModule);
		bool unmountStabilityModule();
		StabilityModule* getStabilityModule();
		*/

		void trigger(unsigned int cycle);




		//SHORTCUT/WORKAUROUND -> TODO: make this better!
		bool setAbstractionModule(AbstractionModule *abstractionModule);
		bool setReliabilityModule(ReliabilityModule* reliabilityModule);
		void closeCSV();

		//New for Journal - SHORTCUT/WORKAUROUND -> TODO: make this better!
		bool setScoreConfidenceModule(ScoreConfidenceModule* scoreConfidenceModule);

		void setConfidenceChange(LinearFunctionBlock* confChangeRightDiff, LinearFunctionBlock* confChangeWrongDiff, LinearFunctionBlock* confChangeRightTime, LinearFunctionBlock* confChangeWrongTime);

		void setScoreHistorLength(unsigned int scoreHistoryLength);

		void saveInScoreHistoryLength(int score, float reliability);


		/*
		void setConfidenceScoreChangeRight(LinearFunctionBlock* conf);
		void setConfidenceScoreChangeWrong(LinearFunctionBlock* conf);
		*/

		void setCSVWRiter(char* filepath);
		void setSecondCSVWRiter(char* filepath);

		void resetAgent();


		void setConfTimeScoreHasBeen(LinearFunctionBlock* confTimeScoreHasBeen);
		void setMaxHistSizePossScores(unsigned int maxHistSizePossScores);

		void setCrossReliabilityProfileModule(CrossReliabilityProfileModule* crossReliabilityProfileModule);

		void setCrossReliabiabilityParameter(float crossReliabilityParameter);

};

#endif