// implementation file: main.cpp in project Coding. Console application.
// description:         Root for testing coding abstractions and concretions.
//                      IO part: input from command line arguments, output to console.
// companion documents: http://informatik.karlheinz-hug.de/Lehrmaterial/Informatik_3/Praktikum/Projekte/
//                      PUe32-Projektuebungsblatt-Codierung.pdf
//                      PUe32-Beispielentwurf-Codierung.pdf
// variant:             1 simple
// author:              Karlheinz Hug
// creation date:       2012-07-04
// last update:         2012-10-03

#include <cstdlib>
#include <iostream>
#include <string>

#include "FileCoder.hpp"

	std::string command_name;

	void show_usage_exit (std::string bad_message)
	{
		std::cout << bad_message << std::endl <<
			"Please call " << command_name << " with these nonempty arguments:" << std::endl <<
			command_name << " source_filename target_filename direction function" << std::endl <<
			"direction: 'encode' | 'decode' " << std::endl <<
			"function:  'copy' | 'compress' |" << std::endl <<
			"           ( 'crypt' | 'compress+crypt' ) method" << std::endl <<
			"method:    'caesar' caesarkey | 'vernam' vernamkey" << std::endl <<
			"caesarkey: integer" << std::endl <<
			"vernamkey: string" << std::endl;
		exit(1);
	}

	int main (int argc, char * argv[])
	{
		// Input from command line:
		command_name = argv[0];
		if (argc < 5)
		{
			show_usage_exit("Missing arguments!");
		}
		std::string source_filename = argv[1];
		std::string target_filename = argv[2];
		std::string direction       = argv[3];
		std::string function        = argv[4];
		if (source_filename.size() == 0 || target_filename.size() == 0 || direction.size() == 0 || function.size() == 0)
		{
			show_usage_exit("Wrong arguments 1, 2, 3 or 4: arguments must be nonempty!");
		}
		if (source_filename.compare(target_filename) == 0)
		{
			show_usage_exit("Wrong arguments 1, 2: filenames must be different!");
		}
		if (direction.compare("encode") != 0 && direction.compare("decode") != 0)
		{
			show_usage_exit("Wrong argument 3: direction must be 'encode' or 'decode'!");
		}
		if (function.compare("copy") != 0 && function.compare("compress") != 0 &&
			function.compare("crypt") != 0 && function.compare("compress+crypt") != 0)
		{
			show_usage_exit("Wrong argument 4: function unknown!");
		}
		char coder_type;
		std::string method,
		            key;
		if (function.compare("copy") == 0)
		{
			coder_type = '@';
		}
		else if (function.compare("compress") == 0)
		{
			coder_type = 'e';
		}
		else // crypt
		{
			if (argc < 7)
			{
				show_usage_exit("Missing arguments for encryption!");
			}
			method = argv[5];
			key    = argv[6];
			if (method.size() == 0 || key.size() == 0)
			{
				show_usage_exit("Wrong arguments 5 or 6: method and key must be nonempty!");
			}
			if (method.compare("caesar") == 0)
			{
				coder_type = 'c';
			}
			else if (method.compare("vernam") == 0)
			{
				coder_type = 'v';
			}
			else
			{
				show_usage_exit("Wrong argument 5: method unknown!");
			}
			if (function.find("compress") != std::string::npos)
			{
				coder_type = std::toupper(coder_type);
			}
		}

		// Calls to functional part:
		FileCoder file_coder(coder_type, key);
		if (direction.compare("encode") == 0)
		{
			file_coder.encode(source_filename, target_filename);
		}
		else
		{
			file_coder.decode(source_filename, target_filename);
		}

		// Output to console:
		std::cout << file_coder.coder_name() << " ";
		switch (file_coder.result())
		{
			case FileCoder::done :
				std::cout << "done";
				break;
			case FileCoder::failed_open :
				std::cout << "failed open";
				break;
			case FileCoder::failed_write :
				std::cout << "failed write";
				break;
			case FileCoder::failed_decode :
				std::cout << "failed decode";
				break;
			default :
				std::cout << "fatal error!";
				break;
		}
		std::cout << std::endl;
		return 0;
	}
