/**
 * \file Main.cpp
 *
 * Implementation of the Main class
 */

#include "Common/Main.h"
#include "Common/Protocol/CommandGen.h"
#include "Common/Protocol/ServerSocket.h"
#include "Common/Protocol/Parser.h"
#include "Common/Interact.h"

#if defined(COACH)
#	include "Coach/CoachKernel.h"
#elif defined(GOALIE)
#	include "Player/GoalieTactics.h"
#	include "Player/Visualization/Visual.h"
#else // !COACH && !GOALIE
#	include "Player/PlayerTactics.h"
#	include "Player/Visualization/Visual.h"
#endif // COACH, GOALIE

#include "Support/Debug.h"
#include <stdio.h>
#include <string.h>


extern bool DribbleTesting;
extern bool PassTesting;

/// Linked list element which stores one Module
struct MODULE_ELEM
{
	Module* module;
	int task;
	int priority;
	
	MODULE_ELEM* next;
};


/// Single instance of the Main object
Main* Main::instance = NULL;


/**
 * Main module constructor
 */
Main::Main() : Module("Main", "Main module", "v0.0.003")
{
	moduleList = NULL;
	instance = this;
	run = true;
}

/**
 * Main module destructor
 */
Main::~Main()
{
	MODULE_ELEM* tmp;;

	while(moduleList)
	{
		tmp = moduleList->next;
		delete moduleList;
		moduleList = tmp;
	}
}

/**
 * Initialize main module
 * \param argc Program parameter count
 * \param argv Program parameters
 * \param task Task number
 * \return INIT_OK for success, INIT_ERR on error
 */
int Main::Init(int argc, char** argv, int task)
{
	MODULE_ELEM* elem = moduleList;
	int i, j, k;

//*************************************** Parametre na Neuronove siete
	DribbleTesting = false;
	PassTesting = false;
	for(i = 1; i < argc; i++)
	{
		if(strcmp(argv[i], "-dt") == 0)				//siet na driblovanie
		{
			DribbleTesting = true;
		} else if (strcmp(argv[i], "-pt") == 0)		//siet na passable friend
		{
			PassTesting = true;
			printf("ANO - mame pass siet\n");			

		}
	}
//*************************************** Parametre na Neuronove siete
	for(i = 1; i < argc; i++)
	{
		if(strcmp(argv[i], "-h") == 0)
		{
			fprintf(stderr, "\n%s %s switches\n\n", (char*) GetName(), (char*) GetVer());
			fprintf(stderr, "\t-h: this help\n");
			fprintf(stderr, "\t-t <task>: switches for task <task> follow\n\n");
			
			return INIT_ERR;
		}
		else if(strcmp(argv[i], "-t") == 0) break;
	}

	while(elem)
	{
		for(j = i; j < argc; j++)
		{
			if(strcmp(argv[j], "-t") == 0)
			{
				sscanf(argv[++j], "%d", &task);
				if(task == elem->task) break;
			}
		}

		for(k = j; k < argc; k++)
		{
			if(strcmp(argv[j], "-t") == 0) break;
		}
		
		fprintf(stderr, "Init: %s %s\n",
			(char*) elem->module->GetName(),
			(char*) elem->module->GetVer());
		
		if(elem->module->Init(k - j, &argv[j], elem->task)) return INIT_ERR;
		
		elem = elem->next;
	}

	return INIT_OK;
}

/**
 * Start main module
 */
void Main::Run(int)
{
	while(run)
	{
		MODULE_ELEM* elem = moduleList;
		while(elem != NULL)
		{
			elem->module->Run(elem->task);
			elem = elem->next;
		}
	}
}

/**
 * Register new module
 * \param module Module pointer
 * \param task Task number
 * \param priority Task priority
 * \return Always number 1
 */
int Main::RegisterModule(Module* module, int task, int priority)
{
	MODULE_ELEM* elem = moduleList;

	fprintf(stderr, "Register: Task number - %d, Priority - %d\n", task, priority);
	
	if(elem != NULL)
	{
		while((elem->task != task) && (elem->next != NULL))
		{
			elem = elem->next;
		}

		if(elem->task == task)
		{
			if (elem->priority >= priority) return 0;
		}
		else
		{
			elem->next = new MODULE_ELEM;
			elem = elem->next;
			elem->next = NULL;
		}
	}
	else
	{
		moduleList = elem = new MODULE_ELEM;
		elem->next = NULL;
	}

	elem->module = module;
	elem->task = task;
	elem->priority = priority;

	return 1;
}

/**
 * Get interface for a task
 * \param task Task number
 * \return Task interface
 */
Interface* Main::GetInterface(int task) const
{
	MODULE_ELEM* elem = moduleList;

	while(elem)
	{
		if(elem->task == task)
			return elem->module->GetInterface(task);
		elem = elem->next;
	}

	return NULL;
}

/**
 * Get module of a task
 * \param task Task number
 * \return Task module
 */
Module* Main::GetModule(int task) const
{
	MODULE_ELEM* elem = moduleList;

	while (elem)
	{
		if (elem->task == task) return elem->module;
		elem = elem->next;
	}

	return NULL;
}


bool DribbleTesting;
bool PassTesting;

/**
 * Main function of the player
 * \param argc Program parameter count
 * \param argv Program parameters
 * \return 0 for success, !=0 otherwise
 */
int main(int argc, char** argv)
{
	DBG_INIT();

	// These objects were global
	Main* main = new Main;
	ServerSocket* serverSocket = new ServerSocket;
	CommandGen* commandGen = new CommandGen;
	Parser* parser = new Parser;
	Interact* interact = new Interact;

#ifdef WITH_VISUAL
	Visual* visual = new Visual;
#endif

#if defined(COACH)
	CoachKernel* tactics = new CoachKernel;
#elif defined(GOALIE)
	GoalieTactics* tactics = new GoalieTactics;
#else // !COACH && !GOALIE
	PlayerTactics* tactics = new PlayerTactics;
#endif // COACH, GOALIE

	// Start player/goalie/coach
	if(main->Init(argc, argv)) return 1;
	main->Run();

	// Delete objects
	delete tactics;

#ifdef WITH_VISUAL
	delete visual;
#endif
	
	delete interact;
	delete parser;
	delete commandGen;
	delete serverSocket;
	delete main;

	DBG_DONE();

	return 0;
}
