//	CmdLineParams.cpp - Class used to parse and handle command line parameters.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#include "CmdLineParams.h"
#include "AppSettings.h"
#include "ConfigFile.h"

#include <iostream>

using std::wstring;
using std::vector;
using std::wcout;
using std::endl;

//------------------------------------------------------------------------------
CmdLineParams::CmdLineParams(const vector<wstring>& argv)
{
	unsigned int i;

	for(i=0;i<argv.size();++i)
		arguments.push_back(argv[i]);

	//So we can handle '--help' args.
	registerCallback(L"help", L"--help", L"-help", false, L"", this);
}

//------------------------------------------------------------------------------
CmdLineParams::~CmdLineParams()
{

}

//------------------------------------------------------------------------------
void CmdLineParams::registerCallback(const wstring& name,
									 const wstring& longToken,
									 const wstring& shortToken,
									 bool hasValue,
									 const wstring& defaultValue,
									 CmdLineCallback *callback)
{
	ParameterCallback cb;

	cb.name = name;
	cb.longToken = longToken;
	cb.shortToken = shortToken;
	cb.hasValue = hasValue;
	if(defaultValue == L"")
		cb.defaultValue = L"0";
	else
		cb.defaultValue = defaultValue;
	cb.callback = callback;
	callbacks.push_back(cb);
}

//------------------------------------------------------------------------------
void CmdLineParams::cmdLineParameterFound(const wstring& name,
										  const wstring& value)
{
	int i;

	if(name == L"help")
	{
		wcout << endl;
		wcout << AppSettings::applicationName;
		wcout << endl << endl;
		wcout << L"Usage:" << endl;

		wcout << AppSettings::applicationName;
#ifdef WIN32
		wcout << L".exe";
#endif
		for(i=0;i<getNumRegisteredParams();++i)
		{
			wcout << L" " << callbacks[i].shortToken;
			if(callbacks[i].hasValue)
				wcout << L" [val]";
		}
		wcout << endl << endl;

		wcout << L"Flags:" << endl;
		wcout << L"--width [val] | -w [val]:\tSet the width of the window.";
		wcout << endl;
		wcout << L"--height [val] | -h [val]:\tSet the height of the window.";
		wcout << endl;
		wcout << L"--window | -win:\t\tSets whether to start the game in a window rather than fullscreen.";
		wcout << endl;
		wcout << L"--mute | -m:\t\tSwitches off the sound output.";
		wcout << endl;
		wcout << L"--drawer [name] | -d [name]:\t\tSets the renderer to use. Can be GLESDrawer (newer, more efficient) or GLImmediateDrawer (older, more compatible).";
		wcout << endl;
		wcout << L"--audio-api [name] | -a [name]:\t\tSets the audio API to use.  Can be SDL, DirectSound, ASIO, MME, ALSA, JACK, OSS, CoreAudio.";
		wcout << endl;
		wcout << L"--debug | -debug:\t\t\t\tOutput debug info to <home dir>/NiallDebugFile<some long number>.txt.";
		wcout << endl;
		wcout << L"--help | -help:\t\t\t\tDisplay this help.";
		wcout << endl;
	}
}

//------------------------------------------------------------------------------
void CmdLineParams::handleParameters()
{
	wstring tempstr;
	unsigned int i, j;
	ConfigFile configFile(*this);
	bool foundInArguments = false;

	for(j=0;j<callbacks.size();++j)
	{
		foundInArguments = false;

		for(i=0;i<arguments.size();++i)
		{
			if((arguments[i] == callbacks[j].longToken) ||
			   (arguments[i] == callbacks[j].shortToken))
			{
				wstring value;

				if(callbacks[j].hasValue && (i < (arguments.size()-1)))
				{
					++i;
					value = arguments[i];
				}
				if(callbacks[j].callback) //Just in case.
				{
					callbacks[j].callback->cmdLineParameterFound(callbacks[j].name,
																 value);
				}
				if(callbacks[j].hasValue)
					configFile.setParameterValue(callbacks[j].shortToken, value);
				else
					configFile.setParameterValue(callbacks[j].shortToken, L"1");
				foundInArguments = true;
				break;
			}
		}

		if(!foundInArguments)
		{
			//If the config file doesn't exist, write the default value to the
			//file.
			if(!configFile.exists())
			{
				configFile.setParameterValue(callbacks[j].shortToken,
											 callbacks[j].defaultValue);
			}
			//If it's a parameter with a value, try and read the value from the
			//config file.
			else if(callbacks[j].hasValue)
			{
				tempstr = configFile.getParameterValue(callbacks[j].shortToken);

				if(tempstr != L"")
				{
					callbacks[j].callback->cmdLineParameterFound(callbacks[j].name,
																 tempstr);
				}
			}
			//Otherwise, if the user didn't pass in any arguments, read the
			//hasValue=false parameter from the config file.
			else if(arguments.size() == 0)
			{
				tempstr = configFile.getParameterValue(callbacks[j].shortToken);

				if((tempstr != L"") && (tempstr != L"0"))
				{
					callbacks[j].callback->cmdLineParameterFound(callbacks[j].name,
																 L"");
				}
			}
		}
	}
}
