#include <iostream>
#include <exception>
#include <string>

#include "config.h"
#include "Simulator.h"
#include "Logger.h"
#include "conf/ConfigurationParser.h"

/** Main function of the program, parses command line arguments and initiates the simulator */
int main(int argc, char **argv) {
	int result = 0;
	Simulator* simulator = Simulator::getInstance();
	try {
		int loglevel = LOG_INFO;
		bool visualize = true;
		std::string logfile("log.txt");
		std::string simfile("./ini/setup.ini");
		std::string carsfile("./ini/cars.ini");
		std::string worldfile("./ini/world.ini");
		
		std::string arg;
		for (int i = 0; i < argc; i++) {
			arg = std::string(argv[i]);
			if (arg == "-h") {
				simulator->printHelp();
				return 0;
			} else if (arg.substr(0,2) == "-l") {
				logfile = arg.substr(2, arg.length());
			} else if (arg.substr(0,2) == "-s") {
				simfile = arg.substr(2, arg.length());
			} else if (arg.substr(0,2) == "-c") {
				carsfile = arg.substr(2, arg.length());
			} else if (arg.substr(0,2) == "-w") {
				worldfile = arg.substr(2, arg.length());
			} else if (arg.substr(0,2) == "-v") {
				std::string level = arg.substr(2, arg.length());
				if (level == "DEBUG") loglevel = LOG_DEBUG;
				else if (level == "INFO") loglevel = LOG_INFO;
				else if (level == "WARN") loglevel = LOG_WARN;
				else if (level == "ERROR") loglevel = LOG_ERROR;
				else if (level == "FATAL") loglevel = LOG_FATAL;
				else if (level == "NONE") loglevel = LOG_NONE;
			} else if (arg.substr(0,2) == "-n") {
				visualize = false;
			}
		}
		
		Logger::setLevel(loglevel);
		Logger::setFilename(logfile);
		_INFO("Application start");
		simulator->init(simfile, carsfile, worldfile, visualize);
		simulator->run();
		_INFO("Application end");
	} catch (ConfigurationException &e) {
		_FATAL("Configuration error:" << e.what());
		result = 1;
	} catch (AssertionException &e) {
		_DEBUG(simulator->getInfo());
		result = 1;
	} catch (SimulatorException &e) {
		_FATAL("Uncaught simulator exception:" << e.what());
		_DEBUG(simulator->getInfo());
		result = 1;
	} catch (std::exception &e) {
		_FATAL("Uncaught std::exception:" << e.what());
		_DEBUG(simulator->getInfo());
		result = 1;
	}
	return result;
}
