#include "ofApp.h"


//--------------------------------------------------------------
void ofApp::setup() {

	// General graphic parameters
	ofEnableSmoothing();
	ofEnableAntiAliasing();
	ofEnableAlphaBlending();
	ofSetVerticalSync(false);

	scenes.push_back(new PfdScene);
	scenes.push_back(new MapScene);
	scenes.push_back(new DataScene);

	//default graphical settings
	circleRes = 100;
	frameRate = 60;

	loadIni();

	// Setup all scenes
	for (auto& scene : scenes) {
		scene->setup();
	}

	if (preloadMapTiles == true) {
		for (int zoom = mapZoom::getInstance().getValueMin(); zoom <= mapZoom::getInstance().getValueMax(); zoom++)
		{
			ofLogNotice() << zoom;
			map.loadExistingMapTiles(zoom);
		}
		ofLogNotice() << "OFFLINE MAP LOADING COMPLETE";
	};
	
	fontSmall.load(ofToDataPath("fonts/Nord-Regular.ttf"), 12, true, true);
	fontMedium.load(ofToDataPath("fonts/Nord-Regular.ttf"), 16, true, true);
	fontLarge.load(ofToDataPath("fonts/Nord-Regular.ttf"), 20, true, true);


	// Black Background
	ofBackground(0);

	// initiate graphical settings based on .ini file
	ofSetCircleResolution(circleRes);
	ofSetFrameRate(60);

	//FakeNoise parameters (duration and time) - for testing only. elapsedTime is updated in the update() function
	duration = 50.0f;
	startTime = ofGetElapsedTimef();
	elapsedTime = 0;

	// parameters to control the writing frequency for AOA and AOS values in the output file
	lastWriteTime = ofGetElapsedTimeMillis();
	writeInterval = 1000 / outputFrequency;

	// Create new file named based on the current system date and time
	std::string filename = generateFilename();
	outputFile.open(ofToDataPath("output/" + filename));

	if (outputFile.is_open()) {
		// Write the headers (variable names) to the file

		outputFile << std::left << "TIME" << "\t" << std::setw(10) << "AoA_ASSE" << "\t" << std::setw(10) << "AoA_VANE" << "\t" << std::setw(10) << "DELTA AoA" << "\t" << std::setw(10) << "AoS_ASSE" << "\t" << std::setw(10) << "AoS_VANE" << "\t" << std::setw(10) << "DELTA AoS" << "\t" << std::setw(10) << "FLAG" << std::endl;

		// logic to update the scenes with touches
	}

	else {
		ofLog() << "Unable to open file for writing";
	}

	// setup the PFD, MAP and DATA buttons to swap scenes

	pfdButton.setSize(SCREEN_HEIGHT * 0.08, SCREEN_HEIGHT * 0.036);
	mapButton.setSize(SCREEN_HEIGHT * 0.08, SCREEN_HEIGHT * 0.036);
	dataButton.setSize(SCREEN_HEIGHT * 0.08, SCREEN_HEIGHT * 0.036);

	pfdButton.setPosition(SCREEN_WIDTH * 0.5 - pfdButton.getWidth()*0.5, SCREEN_HEIGHT*0.002);
	mapButton.setPosition(SCREEN_WIDTH * 0.25 - mapButton.getWidth() * 0.5, SCREEN_HEIGHT * 0.002);
	dataButton.setPosition(SCREEN_WIDTH * 0.75 - dataButton.getWidth() * 0.5, SCREEN_HEIGHT * 0.002);

}
//--------------------------------------------------------------
void ofApp::update(){
	
	elapsedTime+=0.01;	//elapsed time update for FakeNoise - for testing only
	INPUT_DATA.update(elapsedTime, duration); //Iterates through each struct members (input data) calling their update function (fakenoise for testing)

	uint64_t currentTime = ofGetElapsedTimeMillis();

	if (currentTime - lastWriteTime >= writeInterval)
	{
		float errorAOA = abs((INPUT_DATA.ADC_OUT_AOA.value - INPUT_DATA.ADC_OUT_AOA_VANE.value) / INPUT_DATA.ADC_OUT_AOA_VANE.value) * 100;
		float errorAOS = abs((INPUT_DATA.ADC_OUT_AOS.value - INPUT_DATA.ADC_OUT_AOS_VANE.value) / INPUT_DATA.ADC_OUT_AOS_VANE.value) * 100;

		if (outputFile.is_open()) {
			outputFile << std::fixed << std::setprecision(5) << std::left << currentTime << "\t" << std::setw(10) << INPUT_DATA.ADC_OUT_AOA.value << "\t"
				<< std::setw(10) << INPUT_DATA.ADC_OUT_AOA_VANE.value << "\t" << std::setw(10) << errorAOA << "%" << "\t"
				<< std::setw(10) << INPUT_DATA.ADC_OUT_AOS.value << "\t" << std::setw(10) << INPUT_DATA.ADC_OUT_AOS_VANE.value << "\t" << std::setw(10) << errorAOS << "%" <<  "\t" << std::setw(10)<< ASSE_VS_VANE_FLAG << std::endl; // Write with formatting
		}
		else {
			ofLog() << "Unable to write to file";
		}

		lastWriteTime = currentTime;
	}

	for (auto& scene : scenes) {
		scene->update(INPUT_DATA);
	}
}

//--------------------------------------------------------------
void ofApp::draw() {

	// The DATA scene is always drawn in the background to keep updating the VANE vs ASSE graphs.
	if (currentScene != DATA)
	{
		scenes[DATA]->draw();
	}

	scenes[currentScene]->draw();

	ofSetColor(ofColor::black);
	ofDrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT * 0.04);


	//draws the tab buttons, with colors depending on the currently active one.
	switch (currentScene) {

	case PFD:
		ofSetColor(ofColor::slateGrey);
		ofDrawRectRounded(mapButton, 5);
		ofDrawRectRounded(dataButton, 5);

		ofSetColor(ofColor::forestGreen);
		ofDrawRectRounded(pfdButton, 5);
		
		break;

	case MAP:
		ofSetColor(ofColor::slateGrey);
		ofDrawRectRounded(pfdButton, 5);
		ofDrawRectRounded(dataButton, 5);

		ofSetColor(ofColor::forestGreen);
		ofDrawRectRounded(mapButton, 5);
		break;

	case DATA:
		ofSetColor(ofColor::slateGrey);
		ofDrawRectRounded(pfdButton, 5);
		ofDrawRectRounded(mapButton, 5);

		ofSetColor(ofColor::forestGreen);
		ofDrawRectRounded(dataButton, 5);
		break;


	}

	ofSetColor(ofColor::white);

	fontMedium.drawString("PFD", pfdButton.getCenter().x - fontMedium.stringWidth("PFD") * 0.5, pfdButton.getCenter().y + fontMedium.stringHeight("PFD") * 0.5);
	fontMedium.drawString("MAP", mapButton.getCenter().x - fontMedium.stringWidth("MAP") * 0.5, mapButton.getCenter().y + fontMedium.stringHeight("MAP") * 0.5);
	fontMedium.drawString("DATA", dataButton.getCenter().x - fontMedium.stringWidth("DATA") * 0.5, dataButton.getCenter().y + fontMedium.stringHeight("DATA") * 0.5);
	
}	

void ofApp::exit()

{
	if (outputFile.is_open()) {
		outputFile.close();
	}
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key) {

	scenes[currentScene]->keyPressed(key);


	if (key == 'p') {
		currentScene = PFD;
	}
	
	if (key == 'm') {
		currentScene = MAP;
	}

	if (key == 'd') {
		currentScene = DATA;
	}
}


//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){


}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

	scenes[currentScene]->mousePressed(x, y, button);

	if (pfdButton.inside(x, y))
	{
		currentScene = PFD;
	}

	if (mapButton.inside(x, y))
	{
		currentScene = MAP;
	}

	if (dataButton.inside(x, y))
	{
		currentScene = DATA;
	}

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){ 

}
