/////////////////////////////////////////////////////////////////////////////
// Name:        sitplus_main.cpp
// Author:      Cesar Mauri Loba
// Copyright:   (C) 2011 Cesar Mauri Loba - CREA Software Systems
// 
//  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 "sitplus_main_window.h"

#include "sphost/langutils.h"

#include "spcore/coreruntime.h"
#include "spcore/basictypes.h"
#include "spcore/language.h"
#include "spcore/paths.h"
#include "spcore/configuration.h"

#include "3rdparty/nvwa/debug_new.h"
#ifndef NDEBUG
#include "testcommon/testcommon.h"
#endif

#include <wx/wx.h>
#include <iostream>

#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)
	// Include Xlib for latter use on main
	#include <X11/Xlib.h>
#endif

/*
	Check threads enabled
*/
#if !wxUSE_THREADS
     #error "This program requires thread support."
#endif // wxUSE_THREADS

using namespace spcore;
using namespace sphost;
using namespace std;

// ----------------------------------------------------------------------------
// show initialization errors
// ----------------------------------------------------------------------------
class LogInitErrors : public spcore::ILogTarget
{
public:
	virtual void LogMessage (ICoreRuntime::LogSeverityLevel severity, const char* message) {
		const char* msgtype= NULL;
		switch (severity) {
		case ICoreRuntime::LOG_FATAL: 
			msgtype= "FATAL ERROR. ";
			break;
		case ICoreRuntime::LOG_ERROR:
			msgtype= "ERROR. ";
			break;
		case ICoreRuntime::LOG_WARNING:
			msgtype= "WARNING. ";
			break;
		case ICoreRuntime::LOG_INFO:
			msgtype= "INFORMATION. ";
			break;
		case ICoreRuntime::LOG_DEBUG:
			msgtype= "DEBUG. ";
			break;
		default: 
			assert (false);
		}

#ifdef WIN32
		//MessageBoxA(NULL, message, msgtype, MB_OK);
		fprintf (stderr, "%s: %s\n", msgtype, message);
#else
		fprintf (stderr, "%s: %s\n", msgtype, message);
#endif
	}
};

LogInitErrors g_logInitErrors;


// ----------------------------------------------------------------------------
// load modules
// ----------------------------------------------------------------------------
static
bool LoadModule(const char* mname)
{
	ICoreRuntime* cr= getSpCoreRuntime();
	int retval= cr->LoadModule(mname, cr->GetPaths().GetPluginsDir());
	if (retval== 0) return true;

	// Load failed. Try without specifiyig directory
	retval= cr->LoadModule(mname);
	if (retval== 0) return true;

	// Load failed	
	char buff[250];
	sprintf (buff, "error %d loading %s", retval, mname);
	g_logInitErrors.LogMessage(ICoreRuntime::LOG_FATAL, buff);
	return false;
}

bool LoadModules()
{
	if (!LoadModule("spmod_camera")) return false;
	if (!LoadModule("spmod_wiimotes")) return false;
	if (!LoadModule("spmod_sdl")) return false;
//	if (!LoadModule("spmod_sdl_gui")) return false;
	if (!LoadModule("spmod_midi")) return false;
	if (!LoadModule("spmod_vision")) return false;
	if (!LoadModule("spmod_widgets")) return false;
	if (!LoadModule("spmod_score_player")) return false;
	if (!LoadModule("spmod_collage")) return false;
	if (!LoadModule("spmod_puredata")) return false;
	if (!LoadModule("spmod_io")) return false;
	if (!LoadModule("spmod_hid")) return false;
	if (!LoadModule("spmod_audio")) return false;
	if (!LoadModule("spmod_ipl_sdl")) return false;

	return true;
}

static
bool DoSetLanguage(const char* lang) {
	ICoreRuntime* cr= getSpCoreRuntime();

	if (spSetLanguage (lang)!= 0) return false;
	spBindTextDomain("sitplus", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-mod_camera", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-mod_midi", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-mod_puredata", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-mod_score_player", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-mod_widgets", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-mod_wiimotes", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-sp", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-spcore", cr->GetPaths().GetLocalesDir());
	spBindTextDomain("sitplus-sphost", cr->GetPaths().GetLocalesDir());

	return true;
}

static
void SetLanguage()
{
	string lang;

	if (LoadLanguageFromConfiguration(lang) && DoSetLanguage(lang.c_str())) return;

	// Set system default language
	lang= "";
	if (DoSetLanguage(lang.c_str())) SaveLanguageToConfiguration(lang);
}

// ----------------------------------------------------------------------------
// enter gui
// ----------------------------------------------------------------------------
int EnterGUI(int argc, char *argv[])
{
	ICoreRuntime* cr= getSpCoreRuntime();

	if (cr->InitGUISupport (argc, argv)) {
		fprintf (stderr, "wxEntryStart failed");
		return -1;
	}

#ifndef NDEBUG
	::DumpCoreRuntime(cr);
	fprintf (stderr, "Data dir: %s\n", cr->GetPaths().GetDataDir());
#endif

	SetLanguage();

	SitplusMainWindow* mw= new SitplusMainWindow(NULL);
	mw->Show();

	// Remove loger
	cr->UnregisterLogTarget(&g_logInitErrors);
		
	// Run wxWidgets message pump
	cr->RunMessageLoop ();

	// GUI cleanup
	cr->CleanupGUISupport();
	
	return 0;
}

// ----------------------------------------------------------------------------
// main_common
// ----------------------------------------------------------------------------
int main_common(int argc, char* argv[])
{
	// Initialize spcore
	ICoreRuntime* cr= getSpCoreRuntime();
	if (!cr) return -1;

#ifndef NDEBUG
	// In debug mode set the location of data and locales properly
	cr->GetPaths().SetDataDir(PROJECT_SOURCE_DIR);
	cr->GetPaths().SetLocalesDir(PROJECT_BINARY_DIR "/" SP_LOCALEDIR);
#endif	// NDEBUG
	
	// Add loger for initialization
	cr->RegisterLogTarget(&g_logInitErrors);
	
	int retval= 0;
	if (LoadModules()) retval= EnterGUI(argc, argv);

	// Free spcore
	freeSpCoreRuntime();

	return retval;
}


// ----------------------------------------------------------------------------
// main
// ----------------------------------------------------------------------------
#ifdef WIN32
// WIN32 entry point
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
#ifndef NDEBUG
	// Allocates a console in debug mode
	if(AllocConsole()) {
		freopen("CONOUT$", "wt", stdout);
		freopen("CONOUT$", "wt", stderr);
		SetConsoleTitle(_T("Debug Console"));
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
	}
#endif

	return main_common(0, NULL);
}

#else

int main(int argc, char *argv[]) {

#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)
	// Under X11 it's necessary enable threading support
	if ( XInitThreads() == 0 ) {
		fprintf(stderr, "Unable to initialize multithreaded X11 code (XInitThreads failed)");		
		exit( EXIT_FAILURE );
	}
#endif

	return main_common(argc, argv);
}
#endif