// =============================================================================
// Zboard Config Utility
// Copyright (C) 2007  Matt Razza

// 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 2
// 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
// -------------------------------------------------------------------------------
// This file has the entry point for the app and has some generic functions.
// ===============================================================================

// Load Standard Stuff
#include "zboard-inc.h"
#include "zboard-info.cpp"
#include "zboard-xmodmap.cpp"
#include "zboard-settings.cpp"
#include "zboard-scan.cpp"

// Function defines
void showHelp(); //Shows the --help dialog
bool anotherRunning(); //Checks if another instance of this app is running
bool configExists(); //Checks if the config files exist
bool checkZboard(); //Checks Zboard for compatibility

// Entry point for the application
int main(int argc, char *argv[])
{
	// Let's do arguments
	if (argc < 2)
	{
		printf("No arguments provided. \nType '%s --help' for a list of arguments.\n", linuxProcInfo::getProcName(getpid()).c_str());
		return 0;
	}

	settingMan sysSetting("/usr/share/zboard-config/zboard-sys.conf");
	int iUseLoad = atoi(sysSetting.getSetting("SYS_USE_LOADKEYS").c_str());
	bool bUseLoad = false;

	if (iUseLoad == 1)
        bUseLoad = true;

	std::string sTotalArgv = ""; //The total command line
	bool killApp = false; //If this is true we are to kill the app after the area is run
	bool showH = false; //If this is true we are to show the help info
	int *iCommandCode = new int[argc]; //The var that will be set based on the arguments (create an array large enough to store all the possible data)
	std::string *sCommandCode = new std::string[argc];	//The var that will hold the corrisponding data for iCommandCode
	int totalRealArgs = 0; //This var will hold the total number of REAL arguments (not data)

	// Lets loop through the array to collect/parse the data
	for (int iLoop = 1; iLoop < argc; iLoop++)
	{
		std::string sArg = argv[iLoop];
		if (sArg == "--help")
		{
			showH = true;
			killApp = true;
		}
		else if (sArg == "-f") //Command code 1
		{
			iCommandCode[iLoop + totalRealArgs] = 1; //Set the command code
			sCommandCode[iLoop + totalRealArgs] = argv[iLoop + 1]; //Save the data
			iLoop++;
			totalRealArgs--;

			// Track the argument and advance
			sTotalArgv += sArg;
			sArg = (std::string)" " + (std::string)argv[iLoop];
		}
		else if (sArg == "-s") //Command code 2
		{
			iCommandCode[iLoop + totalRealArgs] = 2; //Set the command code
			sCommandCode[iLoop + totalRealArgs] = argv[iLoop + 1]; //Save the data
			iLoop++;
			totalRealArgs--;

			// Track the argument and advance
			sTotalArgv += sArg;
			sArg = (std::string)" " + (std::string)argv[iLoop];
		}
		else if (sArg == "start") //Command code 3
		{
			iCommandCode[iLoop + totalRealArgs] = 3; //Set the command code
		}
		else if (sArg == "stop") //Command code 4
		{
			iCommandCode[iLoop + totalRealArgs] = 4; //Set the command code
		}
		else if (sArg == "--forceError") //Invalid command code
		{
			iCommandCode[iLoop + totalRealArgs] = -1; //Get it to error
		}
		else if (sArg == "--listProc") //Command code 5
		{
			iCommandCode[iLoop + totalRealArgs] = 5; //Set the command code
		}
		else if (sArg == "status") //Command code 6
		{
			iCommandCode[iLoop + totalRealArgs] = 6; //Set the command code
		}
		else if (sArg == "--checkZboard") //Command code 7
		{
			iCommandCode[iLoop + totalRealArgs] = 7; //Set the command code
		}
		else
		{
			std::cout << "Invalid Argument - '" << sArg << "'!" << std::endl;
			std::cout << "Type '" << linuxProcInfo::getProcName(getpid()) << " --help' for a list of arguments." << std::endl;
			killApp = true;
		}

		sTotalArgv += sArg; //Track arguments

		if (iLoop >= 1 && iLoop < argc - 1)
			sTotalArgv += ",";
	}

	totalRealArgs += argc; // Set total real args

	// Parse some direct data from the switches
	if (showH)
		showHelp();

	pid_t pID = -1;

	if (!killApp)
	{
		for (int iLoop = 1; iLoop < totalRealArgs; iLoop++)
		{
			// Decide what to do
			switch (iCommandCode[iLoop])
			{
				case 1:
                    if (!mapInterface::bindNewFile("/usr/share/zboard-config/maps/" + sCommandCode[iLoop], bUseLoad))
                        printf("\033[1;31m*\033[0m Failed to bind file to device.\n");
                    else
                        printf("File bound.\n");
					break;

				case 2:
					if (mapInterface::bindString(sCommandCode[iLoop]))
						printf("New command bound to device.\n");
					else
						printf("\033[1;31m*\033[0m Failed to bind the command to the device.\n");
					break;

				case 3:
					printf("Starting Zboard config...");

					// Does the config exist?
					if (!configExists())
					{
						printf("\rStarting Zboard Config...                                \033[1;34m[\033[1;31m failed \033[1;34m]\033[0m\n");
						printf("\033[1;31m*\033[0m 'zboard.conf' or 'zboard-sys.conf' file not found!\n");
						break;
					}

					// Are we already started?
					if (anotherRunning())
					{
						printf("\rStarting Zboard Config...                                \033[1;34m[\033[1;31m failed \033[1;34m]\033[0m\n");
						printf("\033[1;31m*\033[0m Another instance is currently exicuting...\n");
						break;
					}

					// Split into two procs
					pID = fork();

					if (pID == 0)
					{
						printf("\r                         ");
						startSystem();
					}
					else if (pID < 0)
					{
						printf("\rStarting Zboard Config...                                \033[1;34m[\033[1;31m failed \033[1;34m]\033[0m\n");
					}
					else
						printf("\rStarting Zboard Config...                                \033[1;34m[\033[1;32m ok \033[1;34m]\033[0m\n");

					break;

				case 4:
					printf("Stopping Zboard Config...\r");

					// Make sure one is running
					if (!anotherRunning())
					{
						printf("\rStopping Zboard Config...                                \033[1;34m[\033[1;31m failed \033[1;34m]\033[0m\n");
						printf("\033[1;31m*\033[0m Another instance is not currently exicuting...\n");
						break;
					}

					linuxProcInfo::killPID(linuxProcInfo::getPID(linuxProcInfo::getProcName(getpid()))); // Kill IT!

					// Make sure it died
					if (anotherRunning())
					{
						printf("\rStopping Zboard Config...                                \033[1;34m[\033[1;31m failed \033[1;34m]\033[0m\n");
						printf("\033[1;31m*\033[0m Failed to kill the process...\n");
						break;
					}

					printf("Stopping Zboard Config...                                \033[1;34m[\033[1;32m ok \033[1;34m]\033[0m\n");
					break;

				case 5:
					printf("Listing the currently running processes (in order of PID):\n");
					linuxProcInfo::printRunning();
					break;

				case 6:
					if (anotherRunning())
						printf("Zboard Config is currently running.\n");
					else
						printf("Zboard Config is not currently running.\n");

					break;

				case 7:
					if (anotherRunning())
					{
						printf("\033[1;31m*\033[0m Please stop Zboard Config before testing for compatibility.\n");
					}
					else
					{
						if (checkZboard())
							printf("Your Zboard is compatible with the default configurations!\n");
						else
							printf("Your Zboard is not compatible with the default configurations.\nHowever, this program may still be of use.\n");
					}

					break;

				default:
					printf("\n\033[1;31m[Internal Error]\033[0m\n");
					printf("Please send the following output to the developer...\n\n");
					printf("vr:     %i:%i:%i\n", verMajor, verMinor, verRevision);
					printf("argc:   %s\n", sTotalArgv.c_str());
					printf("argp:   %i\n", iLoop);
					printf("argid:  %i\n", iCommandCode[iLoop]);
					printf("oxp:    cc\n");
			}
		}
	}

	// Clean-up
	delete[] iCommandCode;
	delete[] sCommandCode;

	return 0;
}

// Shows the --help dialog
void showHelp()
{
	printf("=============================\n");
	printf("Zboard Config Utility\n");
	printf("Copyright (C) 2007 Matt Razza\n");
	printf("Version: %i.%i.%i\n", verMajor, verMinor, verRevision);
	printf("=============================\n\n");

	printf("USEAGE: %s [OPTIONS]... [start/stop/status]\n\n", linuxProcInfo::getProcName(getpid()).c_str());

	printf("start/stop/status:\n");
	printf("start               Starts the Zboard Config Daemon\n");
	printf("stop                Stops the Zboard Config Daemon\n");
	printf("status              Checks if the Zboard Config Daemon is running\n");

	printf("\nOptions:\n");
	printf("-f [FILE]           Loads a custom config file\n");
	printf("-s [SETTING]        Force a given setting (even if the application is not \nrunning)\n");
	printf("--forceError        Forces the program to spit out error information (NOTE: \nCommands are exicuted in the order given!)\n");
	printf("--listProc          Lists the running processes; used to see if Zboard Config \nwill detect the app you want\n");
	printf("--checkZboard       Runs the Zboard Compatibility Wizard to check if your Zboard \nwill work.\n");
	printf("--help              Show this help infromation\n");

	printf("\nSpecial Thanks To Moordrik! :)\n\n");

	printf("If you have any questions or comments visit me at http://www.valdegames.com/pig/\n");
	printf("or e-mail me at mrazza@valdegames.com\n");
}

// Checks if another instance of this app is running
bool anotherRunning()
{
	std::string sName = linuxProcInfo::getProcName(getpid());

	if (linuxProcInfo::getPID(sName) != getpid())
		return true;

	return false;
}

// Checks if config files exist
bool configExists()
{
	if (!linuxFileInfo::fileExists("/usr/share/zboard-config/zboard.conf"))
	{
		return false;
	}

	if (!linuxFileInfo::fileExists("/usr/share/zboard-config/zboard-sys.conf"))
	{
		return false;
	}

	return true;
}

// Checks Zboard for compatibility
bool checkZboard()
{
	// Start
	printf("Zboard Compatibility Wizard\n\n");
	std::string sData = "";
	printf("Please press the following keys on your gamepad...\n");

	// Test 1
	// ------

	// Bind the keys
	mapInterface::bindString("keycode 234 = v");
	mapInterface::bindString("keycode 233 = b");
	mapInterface::bindString("keycode 232 = n");
	mapInterface::bindString("keycode 130 = m");
	mapInterface::bindString("keycode 63 = Return");

	// Ask them
	sData = getpass("Left, Right, Down, Up, Jump: ");

	// Remove map
	mapInterface::removeMap("234");
	mapInterface::removeMap("233");
	mapInterface::removeMap("232");
	mapInterface::removeMap("130");
	mapInterface::removeMap("63");

	if (sData != "vbnm") //Check it
		return false;

	return true;
}
