/**
 * program that will convert temperatures from Celsius to Fahrenheit
 * or from Fahrenheit to Celsius
 */
#include "command_line_argument_parser.h"
#include <fstream>
#include <cmath>

// --------------------------------------------------------
// variables that the programmer must define
// --------------------------------------------------------
// name of program
string program_name = "temperature.exe";
// short description of what the program does
string program_desc = "convert temperatures between celsius and fahrenheit";

// --------------------------------------------------------
// variables related to command line arguments
// --------------------------------------------------------
// verbose level
u32    verbose = 1;

float  initial_temperature = 0;
float  final_temperature = 100.0;
float  incr_temperature = 5.0;

// unit of initial to final temperatures
u32	   unit_id = 0;
vector<string> unit_options = {
	"celsius",
	"fahrenheit"
};

/**
 * trigger function for command line argument used to
 * check that temperatures are set correctly
 */
void trigger_temperature() {
	if (initial_temperature >= final_temperature) {
		ostringstream oss;
		oss << "initial temperature (=" << initial_temperature << ") ";
		oss << "should be inferior to final temperature (=" << final_temperature << ")";
		throw std::logic_error(oss.str());
	}
}

/**
 * convert from celsius to fahrenheit
 */		
void c2f() {
	float temperature = initial_temperature;
	while (temperature <= final_temperature) {
		float f = 32.0 + (temperature * 5.0) / 9.0;	
		if (verbose > 0) {	
			cout << temperature << "°C = " << f << "°F" << endl;
		}
		temperature += incr_temperature;
	}
}

/**
 * convert from fahrenheit to celsius 
 */
void f2c() {
	float temperature = initial_temperature;
	while (temperature <= final_temperature) {
		float c = (temperature -32.0) * 5.0 / 9.0;
		if (verbose > 0) {	
			cout << temperature << "°F = " << c << "°C" << endl;
		}	
		temperature += incr_temperature;
	}
}

/**
 * main function
 */
int main(int argc, char *argv[]) {
	// declare command line parser
	clap::CommandLineParser cl(program_name, program_desc, 
		argc, const_cast<char **>( argv ));
		
	try {
		
		// --------------------------------------------------------------
		// add options	
		// --------------------------------------------------------------
		
		// verbose level (0 = silent)
		cl.add_natural("verbose", 'v', &verbose,
				"verbose level, chose between 0 (silent) or 1, default is 1");
				
		// unit of initial and final temperatures		
		cl.add_options("unit", 'u', &unit_id,
				&unit_options, "unit of initial and final temperature");
		
		// option with trigger, increment
		cl.add_float("incr-temperature", 'c', &incr_temperature, 
				"temperature incrementation", &trigger_temperature);				

		// options that need to be set and use trigger
		
		// set initial temperature						
		cl.add_float("initial-temperature", 'i', &initial_temperature, 
				"initial temperature", &trigger_temperature)->set_needed();
				
		// set final temperature		
		cl.add_float("final-temperature", 'f', &final_temperature, 
				"final temperature", &trigger_temperature)->set_needed();
								
		// --------------------------------------------------------------
		// parse command line arguments
		// --------------------------------------------------------------
		cl.parse();
			
		// --------------------------------------------------------------
		// your code here
		// --------------------------------------------------------------
		if (unit_id == 0) {
			c2f();
		} else {
			f2c();
		}		
		
	} catch(exception& e) {
		cl.report_error(e);
	}

	return 0;
}
