#include "StateHandler.h"

#include <algorithm>
#include "printError.h"
#include "rlutil.h"

#include "relationChecker.h"

#include "minmaxzeug.h"
#include "file_util.h"


#include <iostream>
#include <ctime>

//CHANGE ALSO BOTH FUZZY FUNCTION!!!
// is used for the history length of the number of values which will be compared
//to the current value
#define MAX_STATE_HISTORY_LENGTH 10 //10

#define STOP_WHEN_BROKEN
//#define STOP_AFTER_BROKEN
//#define STOP_WHEN_DRIFT
//#define STOP_WHEN_STATE_VALID

#define PRINT



//TODO: also change also hardcoded value in "SlaveAgentHandlerOfAgent.cpp"
#define SLIDINGWINDOWSIZE 3				//3				//10
#define STABLENUMBER 2					//2				//8
#define STABLETHRESHOLD (float)0.04		//0.4			//0.03
#define RELATEDTHRESHOLD (float)0.08	//0.08

#define INJECTIONPARTITIONING 5
#define CMPDISTANCE 3
#define THDRIFT (float)0.08				//0.8

#define MINNUMTOBEVALIDSTATE 11			//11			//8	//10

//three different status are for the system possible
#define STATUS_BROKEN	1
#define STATUS_DRIFT	2
#define STATUS_OKAY		3


using namespace rlutil;


void StateHandler::initStateHandler() {
	
	csv_writer = NULL;

	flagVariablesWereStable = false;

	slidingWindowBufferSize = SLIDINGWINDOWSIZE;
	minNumOfRelatedValuesToBeStable = STABLENUMBER;
	thresholdToBeStable = STABLETHRESHOLD;
	
	thresholdToBeRelated = RELATEDTHRESHOLD;

	discreteAveragePartitionSize = INJECTIONPARTITIONING;
	compareDistanceDiscreteAveragePartition = CMPDISTANCE;
	thresholdNotDrift = THDRIFT;

	minNumToBeValidState = MINNUMTOBEVALIDSTATE;

	activeState = NULL;

	maxStateHistoryLength = MAX_STATE_HISTORY_LENGTH;

	
	time_t rawtime;
	struct tm * timeinfo;
	char output_file_name[200];
	char datetime[80];
	const std::string output_directory_name = ""; //  "./output_data_csv/Opel/2018-08-09/";  there is no impact if we change it!
	std::string output_file_name_str;

	time(&rawtime);
	timeinfo = localtime(&rawtime);

	strftime(datetime, sizeof(datetime), "%Y-%m-%d_%I-%M-%S", timeinfo);
	output_file_name_str = output_directory_name + "output" + datetime + ".csv";
	cout << output_file_name_str << endl;
	
	//XXX - only for now:

	//Ali printf("\n csv_Writer is not NULL, but it is not initialized!!   \n");
	if (csv_writer == NULL) {
		csv_writer = new CSV_Writer("CSV Writer", (char*)output_file_name_str.c_str());
	}
	



	//DATE18
	confidenceStableInput = 0;
	confidenceStableOutput = 0;
	confidenceStable = 0;
	confStableAdjustableThreshold = 0.5;

	confidenceUnstableInput = 0;
	confidenceUnstableOutput = 0;
	confidenceUnstable = 0;
	confidenceUnstableAdjustableThreshold = 0.5;


	confidenceSameStateInput = 0;
	confSameStateInputAdjustableThreshold = 0.5;
	confidenceSameStateOutput = 0;
	confSameStateOutputAdjustableThreshold = 0.5;

	confidenceValidState = 0;
	confValidStateAdjustableThreshold = 0.5;

	brokenCounter = 0;
	confidenceBroken = 0;
	confidenceBrokenAdjustableThreshold = 0.5;

	driftCounter = 0;
	confidenceDrift = 0;
	confidenceDriftAdjustableThreshold = 0.5;


}

StateHandler::StateHandler() {
	set_name(NO_NAME);
	initStateHandler();
}

StateHandler::StateHandler(char* name) {
	set_name(name);
	initStateHandler();
}

bool StateHandler::setDiscreteAveragePartitionSize(unsigned int discreteAveragePartitionSize) {
	if (discreteAveragePartitionSize > 0) {
		this->discreteAveragePartitionSize = discreteAveragePartitionSize;
		return true;
	}
	return false;
}

unsigned int StateHandler::getDiscreteAveragePartitionSize() {
	return discreteAveragePartitionSize;
}

bool StateHandler::addVariable(vector<SlaveAgentSlotOfAgent*>* vVariables, SlaveAgentSlotOfAgent* slot) {
	if (vVariables != NULL && slot != NULL) {
		if (find((*vVariables).begin(), (*vVariables).end(), slot) == (*vVariables).end()) {
			try {
				(*vVariables).push_back(slot);
				return true;
			}
			catch (bad_alloc& error) {
				printError("bad_alloc caught: ", error.what());
			}
		}
	}
	return false;
}

bool StateHandler::addInputVariable(SlaveAgentSlotOfAgent* slot) {
	return addVariable(&vInputVariables, slot);
}

bool StateHandler::addOutputVariable(SlaveAgentSlotOfAgent* slot) {
	return addVariable(&vOutputVariables, slot);
}

bool StateHandler::delete_all_OuputVariables()
{
	SlaveAgentSlotOfAgent* cur_sl_ag_sl_ag;
	unsigned int index_v_OutVar;
	unsigned int size_v_OutVar = vOutputVariables.size();
	for(index_v_OutVar = 0; index_v_OutVar < size_v_OutVar; index_v_OutVar++) {
		cur_sl_ag_sl_ag = vOutputVariables[index_v_OutVar];
		delete cur_sl_ag_sl_ag;
	}
	vOutputVariables.clear();
	return true; //added by Ali, it is an error in VS.
}

bool StateHandler::delete_all_InputVariables()
{
	SlaveAgentSlotOfAgent* cur_sl_ag_sl_ag;
	unsigned int index_v_InpVar;
	unsigned int size_v_InpVar = vInputVariables.size();
	for(index_v_InpVar = 0; index_v_InpVar < size_v_InpVar; index_v_InpVar++) {
		cur_sl_ag_sl_ag = vInputVariables[index_v_InpVar];
		delete cur_sl_ag_sl_ag;
	}
	vInputVariables.clear();
	return true; //added by Ali, it is an error in VS.
}

bool StateHandler::delete_allStates()
{
	State* 			cur_state;
	unsigned int 	index_v_State;
	unsigned int 	size_v_State = vStates.size();
	for(index_v_State = 0; index_v_State < size_v_State; index_v_State++) {
		cur_state = vStates[index_v_State];
		delete cur_state;
	}
	vStates.clear();
	return true; //added by Ali, it is an error in VS.
}

bool StateHandler::setSlidingWindowBufferSize(unsigned int slidingWindowBufferSize) {
	if (slidingWindowBufferSize >= minNumOfRelatedValuesToBeStable) {
		this->slidingWindowBufferSize = slidingWindowBufferSize;
		return true;
	}
	return false;
}

bool StateHandler::setMinNumOfRelatedValuesToBeStable(unsigned int minNumOfRelatedValuesToBeStable) {
	if (minNumOfRelatedValuesToBeStable <= slidingWindowBufferSize) {
		this->minNumOfRelatedValuesToBeStable = minNumOfRelatedValuesToBeStable;
		return true;
	}
	return false;
}

bool StateHandler::setThresholdToBeStable(float thresholdToBeStable) {
	if (thresholdToBeStable >= 0 && thresholdToBeStable <= 1) {
		this->thresholdToBeStable = thresholdToBeStable;
		return true;
	}
	return false;
}

bool StateHandler::setThresholdToBeRelated(float thresholdToBeRelated) {
	if (thresholdToBeRelated >= 0 && thresholdToBeRelated <= 1) {
		this->thresholdToBeRelated = thresholdToBeRelated;
		return true;
	}
	return false;
}




bool StateHandler::variablesAreStable(vector<SlaveAgentSlotOfAgent*>* vVariables) {
	bool flagAllVariablesAreStable = true;
	for (auto &slot : *vVariables) {
		if (slot->getHistoryLength() >= slidingWindowBufferSize - 1) {	//-1 because actual value is not in the history
			if (slot->getNumberOfRelativesToActualValue(thresholdToBeStable) < minNumOfRelatedValuesToBeStable) {	//-1 because actual value is also on of minNumOfRelatedValuesToBeStable
				flagAllVariablesAreStable = false;
			}
		}
		else {
			return false;
		}
	}

	return flagAllVariablesAreStable;
}

//Sorting with bigger Value in Front
struct descending
{
	template<class T>
	bool operator()(T const &a, T const &b) const { return a > b; }
};

//DATE18
float StateHandler::getConfVariableIsStable(SlaveAgentSlotOfAgent* variable) {
	float bestConfOf1Var = 0;
	float sample;
	if (variable->get_slaveAgentValue(&sample)) {
		
		list<float> lHistoryTemporary = variable->getHistory();
		vector<float> vDeviations;
		
		for (auto &h : lHistoryTemporary)
			vDeviations.push_back(deviationValueReferenceValue(sample, h));

		std::sort(std::begin(vDeviations), std::end(vDeviations));

		//all adaptabilities within the history of one variable
		for (unsigned int numOfHistSamplesIncluded = 1; numOfHistSamplesIncluded <= vDeviations.size(); numOfHistSamplesIncluded++) {

			float worstConfOfHistSampleSet = 1;
			unsigned int histSampleCounter = 0;

			for (auto &deviation : vDeviations) {
				if (histSampleCounter >= numOfHistSamplesIncluded)
					break;

				worstConfOfHistSampleSet = minValueOf2Values(worstConfOfHistSampleSet, StabDeviation->getY(deviation));

				histSampleCounter++;
			}

			bestConfOf1Var = maxValueOf2Values(bestConfOf1Var, minValueOf2Values(worstConfOfHistSampleSet, StabSamples->getY((float)histSampleCounter)));
		}
	}

	return bestConfOf1Var;
}

//DATE18
float StateHandler::getConfVariablesAreStable(vector<SlaveAgentSlotOfAgent*>* vVariables) {
	float worstConfOfAllVariables = 1;
	
	for (auto &slot : *vVariables)
		worstConfOfAllVariables = minValueOf2Values(worstConfOfAllVariables, getConfVariableIsStable(slot));

	return worstConfOfAllVariables;
}

//DATE18
float StateHandler::getConfVariableIsUnstable(SlaveAgentSlotOfAgent* variable) {
	float bestConfOf1Var = 0;
	float sample;
	if (variable->get_slaveAgentValue(&sample)) {

		list<float> lHistoryTemporary = variable->getHistory();
		vector<float> vDeviations;

		for (auto &h : lHistoryTemporary)
			vDeviations.push_back(deviationValueReferenceValue(sample, h));

		sort(begin(vDeviations), end(vDeviations), descending());

		//all adaptabilities within the history of one variable
		for (unsigned int numOfHistSamplesIncluded = 1; numOfHistSamplesIncluded <= vDeviations.size(); numOfHistSamplesIncluded++) {

			//float bestConfOfHistSampleSet = 1;
			float bestConfOfHistSampleSet = 0;
			unsigned int histSampleCounter = 0;

			for (auto &deviation : vDeviations) {
				if (histSampleCounter >= numOfHistSamplesIncluded)
					break;

				//bestConfOfHistSampleSet = minValueOf2Values(bestConfOfHistSampleSet, UnstabDeviation->getY(deviation));
				bestConfOfHistSampleSet = maxValueOf2Values(bestConfOfHistSampleSet, UnstabDeviation->getY(deviation));

				histSampleCounter++;
			}

			bestConfOf1Var = maxValueOf2Values(bestConfOf1Var, minValueOf2Values(bestConfOfHistSampleSet, StabSamples->getY((float)histSampleCounter)));
		}
	}

	return bestConfOf1Var;
}

//DATE18 - Is there one unstable variable?
float StateHandler::getConfVariablesAreUnstable(vector<SlaveAgentSlotOfAgent*>* vVariables) {
	float bestConfOfAllVariables = 0;

	for (auto &slot : *vVariables)
		bestConfOfAllVariables = maxValueOf2Values(bestConfOfAllVariables, getConfVariableIsUnstable(slot));

	return bestConfOfAllVariables;
}




bool StateHandler::getConfAndUnconfVariableIsMatching(State* state, LinearFunctionBlock* confDeviation, LinearFunctionBlock* confTime, float* conf, float* unconf) {
	float bestUnconfOf1Var = 0;
	float worstConfOf1Var = 1;

	if (state != NULL) {


	}

	/*
	float sample;
	if (variable->get_slaveAgentValue(&sample)) {

		list<float> lHistoryTemporary = variable->getHistory();
		vector<float> vDeviations;

		for (auto &h : lHistoryTemporary)
			vDeviations.push_back(deviationValueReferenceValue(sample, h));

		sort(begin(vDeviations), end(vDeviations), descending());

		//all adaptabilities within the history of one variable
		for (unsigned int numOfHistSamplesIncluded = 1; numOfHistSamplesIncluded <= vDeviations.size(); numOfHistSamplesIncluded++) {

			//float bestConfOfHistSampleSet = 1;
			float bestConfOfHistSampleSet = 0;
			unsigned int histSampleCounter = 0;

			for (auto &deviation : vDeviations) {
				if (histSampleCounter >= numOfHistSamplesIncluded)
					break;

				//bestConfOfHistSampleSet = minValueOf2Values(bestConfOfHistSampleSet, UnstabDeviation->getY(deviation));
				bestConfOfHistSampleSet = maxValueOf2Values(bestConfOfHistSampleSet, UnstabDeviation->getY(deviation));

				histSampleCounter++;
			}

			bestConfOf1Var = maxValueOf2Values(bestConfOf1Var, minValueOf2Values(bestConfOfHistSampleSet, StabSamples->getY((float)histSampleCounter)));
		}
	}

	return bestConfOf1Var;
	*/

	return 0;
}

/*
bool StateHandler::getConfAndUnconfVariablesAreMatching(vector<SlaveAgentSlotOfAgent*>* vVariables, LinearFunctionBlock* confDeviation, LinearFunctionBlock* confTime, float* conf, float* unconf) {
	
	float bestUnconfOfAllVariables = 0;
	float worstConfOfAllVariables = 1;

	for (auto &variable :* vVariables) {
		bestUnconfOfAllVariables = maxValueOf2Values(bestUnconfOfAllVariables, getConfAndUnconfVariableIsMatching(variable, confDeviation, confTime, conf, unconf));
		worstConfOfAllVariables = minValueOf2Values(worstConfOfAllVariables, getConfAndUnconfVariableIsMatching(variable, confDeviation, confTime, conf, unconf));
	}

	*conf = worstConfOfAllVariables;
	*unconf = bestUnconfOfAllVariables;

	return true;
}
*/





State* StateHandler::makeNewState() {
	State* state = new (nothrow) State();
	if (state != NULL) {
		bool flagLoadVariablesWorked = true;
		for (auto &slot : vInputVariables) {
			if (!state->addInputSubState(slot))
				flagLoadVariablesWorked = false;
		}
		for (auto &slot : vOutputVariables) {
			if (!state->addOutputSubState(slot))
				flagLoadVariablesWorked = false;
		}
		if (!flagLoadVariablesWorked) {
			delete state;
			return NULL;
		}
	}
	else {
		return NULL;
	}

	return state;
}

bool StateHandler::addActiveStateToStateVector() {
#ifdef PRINT
	printf(" >> Save Active State\n");
#endif //PRINT
	if (activeState != NULL) {
		for (auto &state : vStates) {
			if (state == activeState)
				return true;
		}

#ifdef STOP_WHEN_STATE_VALID
		getchar();
#endif // STOP_WHEN_STATE_VALID
		
		try {
			vStates.push_back(activeState);
			return true;
		}
		catch (bad_alloc& error) {
			printError("bad_alloc caught: ", error.what());
			delete activeState;
		}
	}
	return false;
}

/*
bool StateHandler::addStateAndMakeItActive() {
	State* state = addState();
	if (state != NULL) {
		activeState = state;
		return true;
	}
	return false;
}
*/

bool StateHandler::makeNewActiveState() {
	State* state = makeNewState();
	if (state != NULL) {
		activeState = state;
		return true;
	}
	return false;
}


State* StateHandler::findRelatedState() {
	for (auto &state : vStates) {
		if (state->inputVariablesAreRelated(thresholdToBeRelated) && state->outputVariablesAreRelated(thresholdToBeRelated)) {
			return state;
		}
	}
	return NULL;
}

bool StateHandler::findRelatedStateAndMakeItActive() {
	State* state = findRelatedState();
	if (state != NULL) {
		activeState = state;
		return true;
	}
	return false;
}

void StateHandler::eraseStatesWithLessInjections() {
	if (activeState != NULL) {
		if (activeState->getNumOfInjections() < minNumToBeValidState) {
			activeState = NULL;
		}
	}

	for (vector<State*>::iterator state = vStates.begin(); state < vStates.end(); state++) {
		if ((*state)->getNumOfInjections() < minNumToBeValidState) {
			//TODO: also delete all subStates (etc.) of the State? Because: Memory Leakage.
			vStates.erase(state);
			state--;
		}
	}








	/*
	for (auto &state : vStates) {
	//TODO: also delete all subStates (etc.) of the State? Because: Memory Leakage.
	if (state->getNumOfInjections() < minNumToBeValidState) {
	vStates.erase(state);
	}
	}
	*/

}

void StateHandler :: reset_States()
{
	this->delete_allStates();
	this->activeState = NULL;
}

void StateHandler :: reset_States_and_Slave_Agents()
{
	reset_States();
	this->delete_all_InputVariables();
	this->delete_all_OuputVariables();
}


StateHandler :: ~StateHandler()
{
	delete_all_OuputVariables();
	delete_all_InputVariables();
	delete_allStates();

	//delete csv_writer;
}


//XXX - only for now
bool test = true;
unsigned int brokenCounter = 0, driftCounter = 0;

void printDrift() {
	driftCounter++;
	setColor(TXTCOLOR_YELLOW);
	printf(" >> DRIFT\n");
	setColor(TXTCOLOR_GREY);
	test = true;
}

void printBroken() {
	brokenCounter++;
	setColor(TXTCOLOR_LIGHTRED);
	printf(" >> BROKEN\n");
	setColor(TXTCOLOR_GREY);
	test = true;
}

//XXX - only for now
unsigned int old_cycle = 1;

int brokentest = 0;

/*
 * makes a new state and reports if there is a anomaly = hearth piece of CAM :-)
 */
void StateHandler::trigger(unsigned int cycle) {

#ifdef PRINT
	printf("cycle: %u\n", cycle);
#endif // PRINT


	bool flagGotValues = true;
#ifdef PRINT
	printf("Input Sample Values:\n");
#endif // PRINT
	for (auto &slot : vInputVariables) {
		float sampleValue;
		if (!(slot->get_slaveAgentValue(&sampleValue)))
			flagGotValues = false;	//program never executes this line of code
#ifdef PRINT
		printf("In, %s: %f\n", slot->get_comPort()->get_name(), sampleValue);
#endif // PRINT
		
		if (cycle == 1)
			csv_writer->write_field(slot->get_comPort()->get_name());
		else
			csv_writer->write_field(sampleValue);
		csv_writer->make_new_field();
	}
#ifdef PRINT
	printf("Output Sample Values:\n");
#endif // PRINT
	for (auto &slot : vOutputVariables) {
		float sampleValue;
		if (!(slot->get_slaveAgentValue(&sampleValue)))
			flagGotValues = false;	//program never executes this line of code
#ifdef PRINT
		printf("Out, %s: %f\n", slot->get_comPort()->get_name(), sampleValue);
#endif // PRINT
			
		if (cycle == 1)
			csv_writer->write_field(slot->get_comPort()->get_name());
		else
			csv_writer->write_field(sampleValue);
		csv_writer->make_new_field();
	}

	if (cycle == 1){
			csv_writer->write_field("State Nr");
			csv_writer->make_new_field();

			csv_writer->write_field("Conf State Valid");
			csv_writer->make_new_field();

			csv_writer->write_field("Conf State Invalid");
			csv_writer->make_new_field();

			csv_writer->write_field("Conf Input unchanged");
			csv_writer->make_new_field();

			csv_writer->write_field("Conf Input changed");
			csv_writer->make_new_field();

			csv_writer->write_field("Conf Output unchanged");
			csv_writer->make_new_field();

			csv_writer->write_field("Conf Output changed");
			csv_writer->make_new_field();

			csv_writer->write_field("Status");
			csv_writer->make_new_field();

			csv_writer->write_field("Conf Status");
			csv_writer->make_new_field();
	}
	else {
		//in the beginning, a active state has to be created
		if (activeState == NULL && vStates.empty()) {
			brokenCounter = 0;
#ifdef PRINT
			printf(" > new active state\n");
#endif // PRINT
			makeNewActiveState();
			if (activeState->insertValueInState(FuncBlockConfValStateDev, FuncBlockConfInvStateDev, FuncBlockConfValStateTime, FuncBlockConfInvStateTime, maxStateHistoryLength, discreteAveragePartitionSize))
				addActiveStateToStateVector();
			//NEW - Adjust FuncBlockConfSim2StateTime and FuncBlockConfDif2StateTime
			float newBoundary = (float)activeState->getLengthOfHistory();
			FuncBlockConfSim2StateTime->changeFunctionBlockIncr(newBoundary);
			FuncBlockConfDif2StateTime->changeFunctionBlockDecr(newBoundary);

			csv_writer->write_field((int)vStates.size() + 1);
			csv_writer->make_new_field();

			csv_writer->write_field(activeState->getConfStateValid());
			csv_writer->make_new_field();

			csv_writer->write_field(activeState->getConfStateInvalid());
			csv_writer->make_new_field();

			csv_writer->write_field(0);	//confInputVarAreSim2ActiveState
			csv_writer->make_new_field();

			csv_writer->write_field(0);	//confInputVarAreDif2ActiveState
			csv_writer->make_new_field();

			csv_writer->write_field(0);	//confOutputVarAreSim2ActiveState
			csv_writer->make_new_field();

			csv_writer->write_field(0);	//confOutputVarAreDif2ActiveState
			csv_writer->make_new_field();


			csv_writer->write_field(STATUS_OKAY);
			csv_writer->make_new_field();

			csv_writer->write_field(0);	//Status Conf
			csv_writer->make_new_field();


		}
		//there is an active state and/or other states
		else {
			float confInputVarAreSim2ActiveState = activeState->getConfInputVarAreSim2State(FuncBlockConfSim2StateDev, FuncBlockConfSim2StateTime);
			float confInputVarAreDif2ActiveState = activeState->getConfInputVarAreDif2State(FuncBlockConfDif2StateDev, FuncBlockConfDif2StateTime);
			float confOutputVarAreSim2ActiveState = activeState->getConfOutputVarAreSim2State(FuncBlockConfSim2StateDev, FuncBlockConfSim2StateTime);
			float confOutputVarAreDif2ActiveState = activeState->getConfOutputVarAreDif2State(FuncBlockConfDif2StateDev, FuncBlockConfDif2StateTime);

			float confInputIsSteady = confInputVarAreSim2ActiveState - confInputVarAreDif2ActiveState;
			float confOutputIsSteady = confOutputVarAreSim2ActiveState - confOutputVarAreDif2ActiveState;

			printf("input (sim/dif) %f/%f\noutput (sim/dif) %f/%f\n", confInputVarAreSim2ActiveState, confInputVarAreDif2ActiveState, confOutputVarAreSim2ActiveState, confOutputVarAreDif2ActiveState);


			//same state
			if ((confInputVarAreSim2ActiveState > confInputVarAreDif2ActiveState) && (confOutputVarAreSim2ActiveState > confOutputVarAreDif2ActiveState)) {
				brokenCounter = 0;
#ifdef PRINT
				printf(" > same state\n");

				//printf("\nPROOF:\nconfInputVarAreSim2ActiveState = %f\nconfInputVarAreDif2ActiveState = %f\nconfOutputVarAreSim2ActiveState = %f\nconfOutputVarAreDif2ActiveState = %f\n", confInputVarAreSim2ActiveState, confInputVarAreDif2ActiveState, confOutputVarAreSim2ActiveState, confOutputVarAreDif2ActiveState);
#endif // PRINT
				if (activeState->insertValueInState(FuncBlockConfValStateDev, FuncBlockConfInvStateDev, FuncBlockConfValStateTime, FuncBlockConfInvStateTime, maxStateHistoryLength, discreteAveragePartitionSize))
					addActiveStateToStateVector();
				//NEW - Adjust FuncBlockConfSim2StateTime and FuncBlockConfDif2StateTime
				float newBoundary = (float)activeState->getLengthOfHistory();
				FuncBlockConfSim2StateTime->changeFunctionBlockIncr(newBoundary);
				FuncBlockConfDif2StateTime->changeFunctionBlockDecr(newBoundary);

				//print state number
				if(activeState->isStateValid())
					csv_writer->write_field((int)vStates.size());
				else
					csv_writer->write_field((int)vStates.size()+1);
				csv_writer->make_new_field();

				//print conf valid
				csv_writer->write_field(activeState->getConfStateValid());
				csv_writer->make_new_field();
				csv_writer->write_field(activeState->getConfStateInvalid());
				csv_writer->make_new_field();

				//print conf statechange
				csv_writer->write_field(confInputVarAreSim2ActiveState);
				csv_writer->make_new_field();
				csv_writer->write_field(confInputVarAreDif2ActiveState);
				csv_writer->make_new_field();
				csv_writer->write_field(confOutputVarAreSim2ActiveState);
				csv_writer->make_new_field();
				csv_writer->write_field(confOutputVarAreDif2ActiveState);
				csv_writer->make_new_field();


				confidenceDrift = activeState->checkAllVariablesForDriftingFuzzy(discreteAveragePartitionSize, DriftDeviation);
				float confidenceNoDrift = 1 - confidenceDrift;

				/*
				//print conf drift
				csv_writer->write_field(confidenceNoDrift);
				csv_writer->make_new_field();
				csv_writer->write_field(confidenceDrift);
				csv_writer->make_new_field();
				*/

				if (confidenceDrift > 0.5) {
#ifdef PRINT
					setColor(TXTCOLOR_YELLOW);
					printf("DRIFT\n");
					setColor(TXTCOLOR_GREY);
#endif // PRINT
#ifdef STOP_WHEN_DRIFT
					getchar();
#endif // STOP_WHEN_DRIFT
					setColor(TXTCOLOR_GREY);

					//print drift
					csv_writer->write_field(STATUS_DRIFT);
					csv_writer->make_new_field();

					//calc and print conf
					float conf = fuzzyAND(fuzzyAND(confidenceDrift, activeState->getConfStateValid()), fuzzyAND(confInputVarAreSim2ActiveState, confOutputVarAreSim2ActiveState));
					csv_writer->write_field(conf);

				}
				else {
#ifdef PRINT
					setColor(TXTCOLOR_LIGHTGREEN);
					printf("OK\n");
					setColor(TXTCOLOR_GREY);
#endif // PRINT

					//print ok
					csv_writer->write_field(STATUS_OKAY);
					csv_writer->make_new_field();

					//calc and print conf
					float conf = fuzzyAND(fuzzyAND(confInputVarAreSim2ActiveState, confOutputVarAreSim2ActiveState), fuzzyAND(activeState->getConfStateValid(), confidenceNoDrift));
					csv_writer->write_field(conf);
				}
				csv_writer->make_new_field();

				

			}
			//state change
			else {
				//was Valid
				if (activeState->isStateValid()) {

					//only one sub set changed
					if (((confInputVarAreSim2ActiveState > confInputVarAreDif2ActiveState) && (confOutputVarAreSim2ActiveState <= confOutputVarAreDif2ActiveState)) || ((confInputVarAreSim2ActiveState <= confInputVarAreDif2ActiveState) && (confOutputVarAreSim2ActiveState > confOutputVarAreDif2ActiveState))) {
						

						//print state number
						if (activeState->isStateValid())
							csv_writer->write_field((int)vStates.size());
						else
							csv_writer->write_field((int)vStates.size() + 1);
						csv_writer->make_new_field();

						//print conf valid
						csv_writer->write_field(activeState->getConfStateValid());
						csv_writer->make_new_field();
						csv_writer->write_field(activeState->getConfStateInvalid());
						csv_writer->make_new_field();

						//print conf statechange
						csv_writer->write_field(confInputVarAreSim2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confInputVarAreDif2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confOutputVarAreSim2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confOutputVarAreDif2ActiveState);
						csv_writer->make_new_field();







						brokenCounter++;
						printf("brokenCounter: %u\n", brokenCounter);
						
						confidenceBroken = FuncBlockConfBrokenSamples->getY((float) brokenCounter);
						float confidenceOK = 1 - confidenceBroken;

						if (confidenceBroken > 0.5) {
#ifdef PRINT
							setColor(TXTCOLOR_LIGHTRED);
							printf("BROKEN\n");
							setColor(TXTCOLOR_GREY);
#endif // PRINT
#ifdef STOP_AFTER_BROKEN
							brokentest = 1;
#endif // STOP_AFTER_BROKEN			
#ifdef STOP_WHEN_BROKEN
							getchar();
#endif // STOP_WHEN_BROKEN

							//print broken
							csv_writer->write_field(STATUS_BROKEN);
							csv_writer->make_new_field();

							//calculate and print conf
							float conf = fuzzyAND(fuzzyOR(confInputVarAreDif2ActiveState, confOutputVarAreDif2ActiveState), fuzzyAND(confidenceBroken, activeState->getConfStateValid()));
							csv_writer->write_field(conf);
							//csv_writer->make_new_field();
						}
						else {
							//print ok
							csv_writer->write_field(STATUS_OKAY);
							csv_writer->make_new_field();

							//calculate and print conf
							float conf = fuzzyAND(fuzzyOR(fuzzyAND(confInputVarAreSim2ActiveState, confOutputVarAreSim2ActiveState), fuzzyAND(confInputVarAreDif2ActiveState, confOutputVarAreDif2ActiveState)), fuzzyAND(confidenceOK, activeState->getConfStateValid()));
							csv_writer->write_field(conf);
						}






					}
					//In- and output changed
					else {
						brokenCounter = 0;

						printf(" > delete active state\n");
						activeState = NULL;
						printf(" > new active state\n");
						
						// search in vector for matching state //TODO in future: look for the best matching, Not for the first matching
						bool flagFoundMatchingState = false;
						float confInputVarAreSim2ActiveState;
						float confInputVarAreDif2ActiveState;
						float confOutputVarAreSim2ActiveState;
						float confOutputVarAreDif2ActiveState;
						for (auto &state : vStates) {
							confInputVarAreSim2ActiveState = state->getConfInputVarAreSim2State(FuncBlockConfSim2StateDev, FuncBlockConfSim2StateTime);
							confInputVarAreDif2ActiveState = state->getConfInputVarAreDif2State(FuncBlockConfDif2StateDev, FuncBlockConfDif2StateTime);
							confOutputVarAreSim2ActiveState = state->getConfOutputVarAreSim2State(FuncBlockConfSim2StateDev, FuncBlockConfSim2StateTime);
							confOutputVarAreDif2ActiveState = state->getConfOutputVarAreDif2State(FuncBlockConfDif2StateDev, FuncBlockConfDif2StateTime);

							if ((confInputVarAreSim2ActiveState > confInputVarAreDif2ActiveState) && (confOutputVarAreSim2ActiveState > confOutputVarAreDif2ActiveState)) {
								activeState = state;
								flagFoundMatchingState = true;
							}
						}

						if (flagFoundMatchingState == false) {
							makeNewActiveState();
							confInputVarAreSim2ActiveState = 0;
							confInputVarAreDif2ActiveState = 0;
							confOutputVarAreSim2ActiveState = 0;
							confOutputVarAreDif2ActiveState = 0;
						}
						
						//insert in activeState
						if (activeState->insertValueInState(FuncBlockConfValStateDev, FuncBlockConfInvStateDev, FuncBlockConfValStateTime, FuncBlockConfInvStateTime, maxStateHistoryLength, discreteAveragePartitionSize))
							addActiveStateToStateVector();
						//NEW - Adjust FuncBlockConfSim2StateTime and FuncBlockConfDif2StateTime
						float newBoundary = (float)activeState->getLengthOfHistory();
						FuncBlockConfSim2StateTime->changeFunctionBlockIncr(newBoundary);
						FuncBlockConfDif2StateTime->changeFunctionBlockDecr(newBoundary);


						//print state number
						if (activeState->isStateValid())
							csv_writer->write_field((int)vStates.size());
						else
							csv_writer->write_field((int)vStates.size() + 1);
						csv_writer->make_new_field();

						//print conf valid
						csv_writer->write_field(activeState->getConfStateValid());
						csv_writer->make_new_field();
						csv_writer->write_field(activeState->getConfStateInvalid());
						csv_writer->make_new_field();

						//print conf statechange
						csv_writer->write_field(confInputVarAreSim2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confInputVarAreDif2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confOutputVarAreSim2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confOutputVarAreDif2ActiveState);
						csv_writer->make_new_field();




						confidenceDrift = activeState->checkAllVariablesForDriftingFuzzy(discreteAveragePartitionSize, DriftDeviation);
						float confidenceNoDrift = 1 - confidenceDrift;

						if (confidenceDrift > 0.5) {
							setColor(TXTCOLOR_YELLOW);
							printf("DRIFT\n");
#ifdef STOP_WHEN_DRIFT
							getchar();
#endif // STOP_WHEN_DRIFT
							setColor(TXTCOLOR_GREY);

							//print drift
							csv_writer->write_field(STATUS_DRIFT);
							csv_writer->make_new_field();

							//calc and print conf
							float conf = fuzzyAND(confidenceDrift, activeState->getConfStateValid());
							csv_writer->write_field(conf);

						}
						else {
							setColor(TXTCOLOR_LIGHTGREEN);
							printf("OK\n");
							setColor(TXTCOLOR_GREY);

							//print ok
							csv_writer->write_field(STATUS_OKAY);
							csv_writer->make_new_field();

							//calc and print conf
							float conf = fuzzyAND(fuzzyAND(confInputVarAreDif2ActiveState, confOutputVarAreDif2ActiveState), fuzzyAND(activeState->getConfStateValid(), confidenceNoDrift));
							csv_writer->write_field(conf);
						}
						csv_writer->make_new_field();
					}

					
				}
				//was NOT Valid
				else {

					brokenCounter = 0;

					printf(" > delete active state\n");
					delete activeState;
					activeState = NULL;
					printf(" > new active state\n");


					// search in vector for matching state //TODO in future: look for the best matching, Not for the first matching
					bool flagFoundMatchingState = false;
					float confInputVarAreSim2ActiveState;
					float confInputVarAreDif2ActiveState;
					float confOutputVarAreSim2ActiveState;
					float confOutputVarAreDif2ActiveState;
					for (auto &state : vStates) {
						confInputVarAreSim2ActiveState = state->getConfInputVarAreSim2State(FuncBlockConfSim2StateDev, FuncBlockConfSim2StateTime);
						confInputVarAreDif2ActiveState = state->getConfInputVarAreDif2State(FuncBlockConfDif2StateDev, FuncBlockConfDif2StateTime);
						confOutputVarAreSim2ActiveState = state->getConfOutputVarAreSim2State(FuncBlockConfSim2StateDev, FuncBlockConfSim2StateTime);
						confOutputVarAreDif2ActiveState = state->getConfOutputVarAreDif2State(FuncBlockConfDif2StateDev, FuncBlockConfDif2StateTime);

						if ((confInputVarAreSim2ActiveState > confInputVarAreDif2ActiveState) && (confOutputVarAreSim2ActiveState > confOutputVarAreDif2ActiveState)) {
							activeState = state;
							flagFoundMatchingState = true;
						}
					}

					if (flagFoundMatchingState == false) {
						makeNewActiveState();
						confInputVarAreSim2ActiveState = 0;
						confInputVarAreDif2ActiveState = 0;
						confOutputVarAreSim2ActiveState = 0;
						confOutputVarAreDif2ActiveState = 0;
					}

					//insert in active state
					if (activeState->insertValueInState(FuncBlockConfValStateDev, FuncBlockConfInvStateDev, FuncBlockConfValStateTime, FuncBlockConfInvStateTime, maxStateHistoryLength, discreteAveragePartitionSize))
						addActiveStateToStateVector();
					//NEW - Adjust FuncBlockConfSim2StateTime and FuncBlockConfDif2StateTime
					float newBoundary = (float)activeState->getLengthOfHistory();
					FuncBlockConfSim2StateTime->changeFunctionBlockIncr(newBoundary);
					FuncBlockConfDif2StateTime->changeFunctionBlockDecr(newBoundary);


					//print state number
						if (activeState->isStateValid())
							csv_writer->write_field((int)vStates.size());
						else
							csv_writer->write_field((int)vStates.size() + 1);
						csv_writer->make_new_field();

						//print conf valid
						csv_writer->write_field(activeState->getConfStateValid());
						csv_writer->make_new_field();
						csv_writer->write_field(activeState->getConfStateInvalid());
						csv_writer->make_new_field();

						//print conf statechange
						csv_writer->write_field(confInputVarAreSim2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confInputVarAreDif2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confOutputVarAreSim2ActiveState);
						csv_writer->make_new_field();
						csv_writer->write_field(confOutputVarAreDif2ActiveState);
						csv_writer->make_new_field();




						confidenceDrift = activeState->checkAllVariablesForDriftingFuzzy(discreteAveragePartitionSize, DriftDeviation);
						float confidenceNoDrift = 1 - confidenceDrift;

						if (confidenceDrift > 0.5) {
							setColor(TXTCOLOR_YELLOW);
							printf("DRIFT\n");
#ifdef STOP_WHEN_DRIFT
							getchar();
#endif // STOP_WHEN_DRIFT
							setColor(TXTCOLOR_GREY);

							//print drift
							csv_writer->write_field(2);
							csv_writer->make_new_field();

							//calc and print conf
							float conf = fuzzyAND(confidenceDrift, activeState->getConfStateValid());
							csv_writer->write_field(conf);

						}
						else {
							setColor(TXTCOLOR_LIGHTGREEN);
							printf("OK\n");
							setColor(TXTCOLOR_GREY);

							//print ok
							csv_writer->write_field(STATUS_OKAY);
							csv_writer->make_new_field();

							//calc and print conf
							float conf = fuzzyAND(fuzzyAND(confInputVarAreDif2ActiveState, confOutputVarAreDif2ActiveState), fuzzyAND(activeState->getConfStateValid(), confidenceNoDrift));
							csv_writer->write_field(conf);
						}
						csv_writer->make_new_field();



				}

			}

#ifdef PRINT
			printf("STATES: %u\n", vStates.size());
#endif // PRINT
		}
	}

	csv_writer->make_new_line();

	if (brokentest)
		getchar();




















	/*
	//XXX - only for now
	for (unsigned int i = 1; i < (cycle - old_cycle); i++) {
		csv_writer->make_new_field();
		csv_writer->make_new_field();
		csv_writer->make_new_field();
		csv_writer->make_new_line();
		//printf("%u\n", i);
	}
	old_cycle = cycle;
	
	confidenceStableInput = getConfVariablesAreStable(&vInputVariables);
	confidenceStableOutput = getConfVariablesAreStable(&vOutputVariables);
	confidenceStable = minValueOf2Values(confidenceStableInput, confidenceStableOutput);
	printf("confidence stable: %f\n", confidenceStable);

	
	confidenceUnstableInput = getConfVariablesAreUnstable(&vInputVariables);
	confidenceUnstableOutput = getConfVariablesAreUnstable(&vOutputVariables);
	printf("unstable In: %f, Out: %f\n", confidenceUnstableInput, confidenceUnstableOutput);
	confidenceUnstable = maxValueOf2Values(confidenceUnstableInput, confidenceUnstableOutput);
	printf("confidence unstable: %f\n", confidenceUnstable);

	if (confidenceUnstableInput > 0) {
		printf("jetzt\n");
		getchar();
	}


	//TEST
	if (confidenceStable > confidenceUnstable) {
		setColor(TXTCOLOR_LIGHTBLUE);
		printf("jetzt\n");
		setColor(TXTCOLOR_GREY);

		getchar();
	}
	
	//getchar();

		
	if (confidenceStable > confidenceUnstable) {
	//if (false) {
		printf(" > stable\n");

		//for the beginning (there is no state available/created) -> create state
		if (activeState == NULL && vStates.empty()) {
			printf("   > new state\n");
			makeNewActiveState();
			activeState->injectValues(discreteAveragePartitionSize);
			confidenceValidState = ValidState->getY((float)activeState->getNumOfInjections());
		}
		//there is an active state
		else if (activeState != NULL) {

			//caclulate confidences of deciding for same state
			float confidenceSameStateInput = activeState->inputVariablesAreRelatedFuzzy(SameState);
			float confidenceSameStateOutput = activeState->outputVariablesAreRelatedFuzzy(SameState);
			printf("ConfSameState\nIn: %f\nout: %f\n", confidenceSameStateInput, confidenceSameStateOutput);


			//In- and Outputs are unchanged
			if ((confidenceSameStateInput > confSameStateInputAdjustableThreshold) && (confidenceSameStateOutput > confSameStateOutputAdjustableThreshold)) {

				printf("   > same state\n");

				//inject values
				activeState->injectValues(discreteAveragePartitionSize);
				//calculate the confidence to have a validState
				confidenceValidState = ValidState->getY((float)activeState->getNumOfInjections());

				//TODO DATE
				//check for drifting!!!
				//printDrift();

				
			}
			//In- and Outputs have changed
			else if ((confidenceSameStateInput <= confSameStateInputAdjustableThreshold) && (confidenceSameStateOutput <= confSameStateOutputAdjustableThreshold)) {

				printf("   > change state\n");
				getchar();
				//active state is/was valid
				if (confidenceValidState > confValidStateAdjustableThreshold) {

					printf("speicher\n");
					getchar();


					addActiveStateToStateVector();

					//TODO DATE
					//search for matching state
					//or
					printf("   > new state\n");
					//create an new active state
					makeNewActiveState();

					//inject values
					activeState->injectValues(discreteAveragePartitionSize);
					//calculate the confidence to have a validState
					confidenceValidState = ValidState->getY((float)activeState->getNumOfInjections());

					//TODO DATE
					//check for drifting!!!
					//printDrift();

				}
			}
			//Only in- or outputs have changed
			else {
				//active state is/was valid
				if (confidenceValidState > confValidStateAdjustableThreshold) {
					
					addActiveStateToStateVector();

					printf("   > broken\n");
					brokenCounter++;
					confidenceBroken = BrokenCounterSamples->getY(brokenCounter);

					//getchar();

					//TODO DATE??
					//Save State
				}
			}
		}
		//there is no active state, but there is/are state(s)
		else {

			printf("   > old or new state\n");

			//getchar();
			//TODO DATE
			//search for matching state
			//or
			printf("   > new state\n");
			makeNewActiveState();
			activeState->injectValues(discreteAveragePartitionSize);
			confidenceValidState = ValidState->getY((float)activeState->getNumOfInjections());

			//TODO DATE
			//check for drifting!!!
			//printDrift();
		}


		if (activeState != NULL) {
			confidenceDrift = activeState->checkAllVariablesForDriftingFuzzy(discreteAveragePartitionSize, DriftDeviation);
		}

		//getchar();
	}
	//unstable
	else {

		printf("   > unstable\n");

		//there is/was an active state
		if (activeState != NULL) {
			//delete activeState;

			if (confidenceValidState > confValidStateAdjustableThreshold)
				addActiveStateToStateVector();
			
			activeState = NULL;
		}
	}
	
	//DATE TODO
	//STABLE CONFIDENCE MITEINBEZIEHEN
	if ((confidenceBroken >= confidenceBroken) && (confidenceBroken > confidenceBrokenAdjustableThreshold)) {
		setColor(TXTCOLOR_LIGHTRED);
		printf(" >> BROKEN - confidence %f\n", confidenceBroken);
		setColor(TXTCOLOR_GREY);

		getchar();
	}
	else if (confidenceDrift > confidenceDriftAdjustableThreshold) {
		setColor(TXTCOLOR_YELLOW);
		printf(" >> DRIFT - confidence %f\n", confidenceDrift);
		setColor(TXTCOLOR_GREY);

		//XXXXXXXXXX ????????????????????????????????????
		if (brokenCounter > 0)
			brokenCounter--;

		getchar();
	}
	else {
		setColor(TXTCOLOR_LIGHTGREEN);
		
		float confidenceOK;
		if (confidenceDrift > confidenceBroken)
			confidenceOK = 1 - confidenceDrift;
		else
			confidenceOK = 1 - confidenceBroken;

		printf(" >> SYSTEM OK - confidence %f\n", confidenceOK);
		setColor(TXTCOLOR_GREY);
	}



	printf("brokenCounter %u\n", brokenCounter);
	printf("number of states: %i\n", vStates.size());
	*/
	







	/*
	if (variablesAreStable(&vInputVariables) && variablesAreStable(&vOutputVariables)) {
		printf(" > stable\n");

		//XXX - only for now
		csv_writer->write_field(2); //stable
		csv_writer->make_new_field();

		//getchar();

		if (activeState == NULL && vStates.empty()) {
			makeNewActiveState();
			activeState->injectValues(discreteAveragePartitionSize);

			//XXX - only for now 
			csv_writer->write_field(1); //new active state
			csv_writer->make_new_field();
			csv_writer->make_new_field();
		}
		else {
			if (activeState != NULL) {

				printf("\nbeginning here:\n");

				bool flagInputUnchanged = activeState->inputVariablesAreRelated(thresholdToBeRelated);
				bool flagOutputUnchanged = activeState->outputVariablesAreRelated(thresholdToBeRelated);
				
				//input and/or output unchanged?
				if (flagInputUnchanged && flagOutputUnchanged) {
					activeState->injectValues(discreteAveragePartitionSize);
					if (!activeState->checkAllVariablesForNotDrifting(discreteAveragePartitionSize, compareDistanceDiscreteAveragePartition, thresholdNotDrift)) {
						printDrift();

						//XXX - only for now
						csv_writer->make_new_field();
						csv_writer->write_field(1); //drift
						csv_writer->make_new_field();
					}
					//XXX - only for now
					else {
						csv_writer->make_new_field();
						csv_writer->make_new_field();
					}
				}
				else {
					if (activeState->getNumOfInjections() >= minNumToBeValidState) {
						if ((!flagInputUnchanged && flagOutputUnchanged) || (flagInputUnchanged && !flagOutputUnchanged)) {
							printBroken();
							getchar();

							//XXX - only for now
							csv_writer->make_new_field();
							csv_writer->write_field(2); //broken
							csv_writer->make_new_field();
						}
						else {
							addActiveStateToStateVector();
							if (!findRelatedStateAndMakeItActive()) {
								makeNewActiveState();
								activeState->injectValues(discreteAveragePartitionSize);

								//XXX - only for now
								csv_writer->write_field(1); //new active state
								csv_writer->make_new_field();
								csv_writer->make_new_field();
							}
							else {
								//next line is new
								activeState->resetDiscreteAveragePartitionCounter();

								//XXX - only for now
								csv_writer->write_field(2); //change to existing state
								csv_writer->make_new_field();


								activeState->injectValues(discreteAveragePartitionSize);
								if (!activeState->checkAllVariablesForNotDrifting(discreteAveragePartitionSize, compareDistanceDiscreteAveragePartition, thresholdNotDrift)) {
									printDrift();

									//XXX - only for now
									csv_writer->write_field(1); //drift
									csv_writer->make_new_field();
								}
								//XXX - only for now
								else {
									csv_writer->make_new_field();
								}
							}
						}
					}
					else {
						delete activeState;
						if (!findRelatedStateAndMakeItActive()) {
							makeNewActiveState();
							activeState->injectValues(discreteAveragePartitionSize);

							//XXX - only for now
							csv_writer->write_field(1); //new active state
							csv_writer->make_new_field();
							csv_writer->make_new_field();
						}
						else {
							//next line is new
							activeState->resetDiscreteAveragePartitionCounter();

							//XXX - only for now
							csv_writer->write_field(2); //change to existing state
							csv_writer->make_new_field();

							activeState->injectValues(discreteAveragePartitionSize);
							if (!activeState->checkAllVariablesForNotDrifting(discreteAveragePartitionSize, compareDistanceDiscreteAveragePartition, thresholdNotDrift)) {
								printDrift();

								//XXX - only for now
								csv_writer->write_field(1); //drift
								csv_writer->make_new_field();
							}
							//XXX - only for now
							else {
								csv_writer->make_new_field();
							}
						}
					}
				}
			}
			else {
				if (!findRelatedStateAndMakeItActive()) {
					makeNewActiveState();
					activeState->injectValues(discreteAveragePartitionSize);

					//XXX - only for now
					csv_writer->write_field(1); //new active state
					csv_writer->make_new_field();
					csv_writer->make_new_field();
				}
				else {
					//next line is new
					activeState->resetDiscreteAveragePartitionCounter();

					//XXX - only for now
					csv_writer->write_field(2); //change to existing state
					csv_writer->make_new_field();

					activeState->injectValues(discreteAveragePartitionSize);
					if (!activeState->checkAllVariablesForNotDrifting(discreteAveragePartitionSize, compareDistanceDiscreteAveragePartition, thresholdNotDrift)) {
						printDrift();

						//XXX - only for now
						csv_writer->write_field(1); //drift
						csv_writer->make_new_field();
					}
					//XXX - only for now
					else {
						csv_writer->make_new_field();
					}
				}
			}
		}





		if (activeState != NULL) {
			printf(" -- an activeState exist: \n");
			printf(" --- injections: %u\n", activeState->getNumOfInjections());

			//XXX - only for now
			csv_writer->write_field((int)activeState->getNumOfInjections()); //number of injections
			csv_writer->make_new_line();
		}
		//XXX - only for now
		else {
			csv_writer->make_new_field();
		}


		printf(" -- Number of States (excl. activeState): %u\n", vStates.size());
		for (auto &s : vStates) {
			printf(" --- injections: %u\n", s->getNumOfInjections());
		}
		printf(" ... BrokenCounter: %u\n", brokenCounter);
		printf(" ... driftCounter: %u\n", driftCounter);
		printf("cycle: %u\n", cycle);


		if (test) {
			test = false;
			//getchar();
		}

		flagVariablesWereStable = true;
	}

	else {

		printf(" > unstable\n");
		//XXX - only for now
		csv_writer->write_field(1); //unstable
		csv_writer->make_new_field();
		csv_writer->make_new_field();
		csv_writer->make_new_field();
		csv_writer->make_new_line();


		if (flagVariablesWereStable)
			test = true;

		//search for states with less injections in all states
		if (flagVariablesWereStable) {
			if (activeState != NULL) {
				
				if (activeState->getNumOfInjections() >= minNumToBeValidState) {
					addActiveStateToStateVector();
					
				}
				else {
					delete activeState;
				}
				activeState = NULL;


				//getchar();

			}
		}

		flagVariablesWereStable = false;
	}



	//xxx - only for now
	//csv_writer->make_new_line();
	*/
}


void StateHandler::closeCsvFile() {
	if(csv_writer != NULL)
		csv_writer->close_file();
}

string StateHandler::create_Output_File_Name(string cfg_parameter)
{
	time_t rawtime;
	struct tm * timeinfo;
	char output_file_name[200];
	char datetime[80];
	std::string output_file_name_str;

	time(&rawtime);
	timeinfo = localtime(&rawtime);

	strftime(datetime, sizeof(datetime), "%Y-%m-%d_%I-%M-%S", timeinfo);
	output_file_name_str = output_directory_name + "output" + datetime + cfg_parameter + ".csv";
	//cout << output_file_name_str << endl;

	return output_file_name_str;
}

void StateHandler::set_CSV_Writer_parameter(string cfg_parameter)
{
	string cur_Output_File_Name = this->create_Output_File_Name(cfg_parameter);
	csv_writer->reset_fpointer(cur_Output_File_Name);
}



/*
void StateHandler :: initStateHandler() {
	//activeState = NULL;
	thresholdToAverage = THRESHOLDTOAVG;
	minNumOfChangedForValidStateChange = MINNUMCHANGEDFORVALIDSTATECHANGE;

	minimumInjectionsForBeingState = MININJFORBEINGSTATE;
}

StateHandler :: StateHandler() {
	set_name(NO_NAME);
	initStateHandler();
}

StateHandler :: StateHandler(char* name) {
	set_name(name);
	initStateHandler();
}

bool StateHandler :: setMinimumInjectionsForBeingState(unsigned int minimumInjectionsForBeingState) {
	if (minimumInjectionsForBeingState > 0) {
		this->minimumInjectionsForBeingState = minimumInjectionsForBeingState;
		return true;
	}
	return false;
}

unsigned int StateHandler :: getMinimumInjectionsForBeingState() {
	return minimumInjectionsForBeingState;
}

bool StateHandler :: add_slot(SlaveAgentSlotOfAgent* slot) {
	if(slot != NULL) {
		try {
			vSlots.push_back(slot);
			return true;
		}	
		catch(bad_alloc& error) {
			printError("bad_alloc caught: ", error.what());
			delete slot;
		}
	}
	return false;
}

void StateHandler :: setThresholdToAverage(float thresholdToAverage) {
	this->thresholdToAverage = thresholdToAverage;
}

float StateHandler :: getThresholdToAverage() {
	return thresholdToAverage;
}

void StateHandler::set_minNumOfChangedForValidStateChange(unsigned int minNumOfChangedForValidStateChange) {
	this->minNumOfChangedForValidStateChange = minNumOfChangedForValidStateChange;
}

unsigned int StateHandler::get_minNumOfChangedForValidStateChange() {
	return minNumOfChangedForValidStateChange;
}


bool StateHandler :: trigger() {
	
	bool flagWorked = true;

	printf("NumOfStates: ");
	for (auto &slot : vSlots) {
		printf("%u, ", slot->getNumberOfStates());
	}
	printf("\n");


	//Check all input values if they have changed more than threshold ...and count how many changed
	unsigned int numberOfChanges = 0;
	for (auto &slot : vSlots) {
		float value;
		if (slot->get_slaveAgentValue(&value)) {

			State* activeState = slot->getActiveState();
			if (activeState != NULL) {
				printf("act - ");
				if (activeState->isNew()) {
					printf("new - ");
					//numberOfChanges++;
				}
				else if (activeState->valueIsRelated(value, thresholdToAverage)) {
					printf("rel - ");
				}
				else {
					printf("nrel - ");
					numberOfChanges++;
				}
			}

			else {
				printf("nact - ");
			}
		}
	}
	printf("\n");









	printf(" >> Number of Changes: %u\n", numberOfChanges);
	//nothing has changes more than threshold
		
	if (numberOfChanges == 0) {
		printf("\n\n >>> inject in active state\n");
		for (auto &slot : vSlots) {
			slot->injectValueInActiveState();
		}
	}
	else if(numberOfChanges >= minNumOfChangedForValidStateChange) {
		printf("\n\n >>> new (or another) state\n");

		for (auto &slot : vSlots) {
			State* activeState = slot->getActiveState();
			if (activeState != NULL) {
				if (activeState->getNumberOfInjections() < minimumInjectionsForBeingState) {
					slot->deleteActiveState();
					printf(" >> delete State\n");
				}
			}
		}
			
		//search for existing state
		bool flagRelated = false;
		if (vSlots.empty() == false) {
			int ix = vSlots.front()->getIndexOfRelatedState(0, thresholdToAverage);
			while (ix > -2) {
				if (ix >= 0) {
					//TODO: maybe another state fits a bit better.. approach -> euklidean distance?
					flagRelated = true;
					for (vector<SlaveAgentSlotOfAgent*>::iterator slot = vSlots.begin() + 1; slot < vSlots.end(); slot++) {
						if ((*slot)->valueIsRelated(ix, thresholdToAverage) == false) {
							flagRelated = false;
						}
					}
					if (flagRelated == true) {
						for (auto &slot : vSlots) {
							slot->setActiveState(ix);
						}
						break;
					}
					ix = vSlots.front()->getIndexOfRelatedState(ix+1, thresholdToAverage);
				}
			}
		}

		if (flagRelated == false) {
			printf(" >> No related state found\n");

			printf("\n\n >>> inject in active state\n");
			for (auto &slot : vSlots) {
				slot->injectValueInActiveState();
			}
		}


	}

	
	printf("ende\n");

	return false;
}
*/
