/*
 *
 *  $Id: initwx.cpp $
 *  Ginkgo CADx Project
 *
 *  Copyright 2008-14 MetaEmotion S.L. All rights reserved.
 *  http://ginkgo-cadx.com
 *
 *  This file is licensed under LGPL v3 license.
 *  See License.txt for details
 *
 *
 */

#define SINGLE_INSTANCE
#if defined (_WIN32) && defined (_GINKGO_DEBUG)
#include <cairo/cairo.h>
#if defined _GINKGO_CHECK_LEAKS
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
#endif

#include <cctype>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <fcntl.h>

#include <wx/image.h>
#include <wx/splash.h>
#include <wx/msgout.h>
#include <wx/msgdlg.h>
#include <wx/dcmemory.h>
#include <wx/bitmap.h>
#include <wx/statbmp.h>
#include <wx/bmpbuttn.h>
#include <wx/filename.h>
#include <wx/stdpaths.h>
#include <wx/dir.h>
#include <wx/sysopt.h>
#include <wx/log.h>
#include <wx/datetime.h>
#include <wx/stdpaths.h>
#include <wx/filename.h>
#include <wx/wfstream.h>
#include <wx/wxsqlite3/wxsqlite3.h>
#include <wx/socket.h>
#include <wx/dcclient.h>

#include <main/controllers/configurationcontroller.h>
#include <main/tools/coretools.h>
#include "singleinstance.h"
#include "initwx.h"
#include <curl/curl.h>

#if defined(__DEPRECATED)
#undef __DEPRECATED
#endif

#include <vtkPolyDataMapper.h>

#include <itkObject.h>
#include <vtkThreadedStreamingPipeline.h>
#include <itkMultiThreader.h>
#if defined(_GINKGO_DEBUG) && !defined(OMITIR_VENTANA_ERRORES_VTK)
#include <vtkObject.h>
#endif

#if defined(_WIN32)
#define _WINSOCKAPI_ 
#include <windows.h>
#include <io.h>
#endif
#if defined(_WIN32) && defined(_GINKGO_DEBUG) && !defined(_WIN32_WINNT_WIN7)
//#include <vld.h>
#endif
#if !defined(_WIN32)
#include <sys/signal.h>
#endif

#include <main/license.h>
#include <api/globals.h>
#include <api/imodulo.h>
#include <api/integration/template.h>
#include <api/toolsystem/itoolsregistry.h>
#include <api/controllers/imodulecontroller.h>
#include <api/controllers/icontroladorlog.h>
#include <main/controllers/commandcontroller.h>
#include <api/controllers/ieventscontroller.h>
#include <api/dicom/idicomconformance.h>
#include <eventos/hidesplashwindow.h>

#include "main/entorno.h"

#include <main/controllers/controladorextensiones.h>
#include <main/controllers/controladorvistas.h>
#include <main/controllers/pacscontroller.h>
#include <main/controllers/controladorcarga.h>
#include <main/controllers/controladorhl7.h>
#include <main/controllers/controladorenviohl7.h>
#include <main/controllers/historycontroller.h>
#include <main/controllers/controladorpermisos.h>
#include <main/controllers/controladorbbddhl7.h>
#include <main/controllers/controladoracciones.h>
#include <main/controllers/integrationcontroller.h>
#include <main/controllers/dcmtk/dicomservers.h>
#include <main/controllers/controladorinternacionalizacion.h>
#include <main/controllers/controladorautenticacion.h>
#include <main/controllers/inactivitycontroller.h>
#include <main/controllers/configurationcontroller.h>
#include <main/controllers/thumbnailcontroller.h>
#include <main/controllers/historytoolscontroller.h>
#include <main/controllers/hangingprotocolcontroller.h>
#include <main/controllers/autocleaningcontroller.h>
#include <main/controllers/modalitysettingscontroller.h>
#include <main/controllers/anonusagestats.h>
#include <main/controllers/smartretrievecontroller.h>
#include <main/controllers/storedqueriescontroller.h>

#include <main/gui/mainwindow/ventanaprincipal.h>

#include <resources/ginkgoresourcesmanager.h>

#define _GINKGO_ENABLE_SPLASH

using namespace GIL;

#if defined(_WIN32)

void RedirectIOToConsole()
{

	CONSOLE_SCREEN_BUFFER_INFO coninfo;
	FILE *fp;

	// allocate a console for this app
	AllocConsole();

	// set the screen buffer to be big enough to let us scroll text
	GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
		&coninfo);
	coninfo.dwSize.Y = 9999;
	SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
		coninfo.dwSize);

	// redirect unbuffered STDOUT to the console
	long lStdHandle = (long) GetStdHandle(STD_OUTPUT_HANDLE);
	long hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen(hConHandle, "w");
	*stdout = *fp;
	//setvbuf(stdout, NULL, _IONBF, 0);

	// redirect unbuffered STDIN to the console
	lStdHandle = (long) GetStdHandle(STD_INPUT_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen(hConHandle, "r");
	*stdin = *fp;
	//setvbuf(stdin, NULL, _IONBF, 0);

	// redirect unbuffered STDERR to the console
	lStdHandle = (long) GetStdHandle(STD_ERROR_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen(hConHandle, "w");
	*stderr = *fp;
	//setvbuf(stderr, NULL, _IONBF, 0);

	// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
	// point to console as well
	//ios::sync_with_stdio();
}

#endif

class GinkgoEventsDelegate: GNC::GCS::IEventsObserver
{
public:
	GinkgoEventsDelegate(Ginkgo* pApp) 
	{
		m_pApp = pApp;
		GNC::GCS::IEventsController::Instance()->Registrar(this, GNC::GCS::Events::EventHideSplashWindow());
	}

	~GinkgoEventsDelegate() 
	{
	}
	
	virtual void ProcesarEvento(GNC::GCS::Events::IEvent *evt)
	{
		GNC::GCS::Events::EventHideSplashWindow* pEvt = dynamic_cast<GNC::GCS::Events::EventHideSplashWindow*>(evt);
		if (pEvt != NULL) {
			if (m_pApp->GetLogoWindow() != NULL) {
				m_pApp->GetLogoWindow()->Hide();
			}
		}
	}

	virtual int FilterEvent(wxEvent &event)
	{
		 // Automaticlly logout when the user is Away From Keyboard (AFK) for too long
		if (wxEVT_MOTION == event.GetEventType() || wxEVT_CHAR == event.GetEventType())
		 {
			  // User has done something, so stop the AFK timer
			 GNC::GCS::InactivityController::Instance()->ResetsInactivity();
		 }
		 const int FILTER_EVENT_PROCESS_NORMALLY = -1;

		 return FILTER_EVENT_PROCESS_NORMALLY;
	}

	Ginkgo* m_pApp;
};

//Punto de entrada
IMPLEMENT_APP_NO_MAIN(Ginkgo)
#if defined(_WIN32)
int WINAPI InitWX(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
#else
int InitWX(int argc, char** argv)
{
	return wxEntry(argc, argv);
}
#endif

wxSplashScreen* Ginkgo::GetLogoWindow()
{
	return m_pVentanaLogo;
}

/* Carga las extensiones de plugins Ginkgo (Bibliotecas externas .plugin) */
void Ginkgo::LoadPlugins()
{
	GNC::ControladorExtensiones::Instance();	
}

void Ginkgo::OnSplashClose(wxCloseEvent& WXUNUSED(event))
{
	m_pVentanaLogo = NULL;
}

// Evento de incialización de la aplicación

bool Ginkgo::OnInit()
{
	m_pEventObserverDelegate = new GinkgoEventsDelegate(this);

	setlocale(LC_NUMERIC, "C");

#if defined(__WXOSX__)
	m_Inicializado = false;
#endif
	//std::cout << "OnInit()" << std::endl;
#if defined(_GINKGO_DEBUG) && defined(_WINDOWS) && defined (_GINKGO_CHECK_LEAKS)
	_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
	_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
#endif

#if (defined(_WIN32) && defined(_GINKGO_DEBUG)) || defined(FORCE_ENABLE_CONSOLE)
	RedirectIOToConsole();
#endif

	wxLog *logger = new wxLogStderr();
	wxLog::SetActiveTarget(logger);

	{ // TODO Migrate to getopt if params continues growing	
		for (int i = 1; i < argc; ++i) { // Find the first "not starting with --" argument
			wxString arg = wxString(argv[i]);
			if (arg.StartsWith("--config-file")) {
				wxString::size_type eqPos = arg.find("=");
				if (eqPos != wxString::npos) {
					wxString configFilePath = arg.substr(eqPos + 1, std::string::npos);
				
					if (!wxFile::Exists(configFilePath)) {
						LOG_ERROR("INIT", "Specified config file does not exists" << ": " << TOPATH(configFilePath));
						GNC::GCS::IControladorLog::FreeInstance();
						GNC::Entorno::FreeInstance();
						GNC::GCS::ConfigurationController::FreeInstance();
						return false;
					}
					else {
						GNC::GCS::ConfigurationController::SetPreferredConfigFile(TOPATH(configFilePath));
					}
				}
			}
		}
	}

	wxSocketBase::Initialize();

	
	wxSQLite3Database::InitializeSQLite();
	//initialize WSA on windows
#if defined(_WINDOWS)
		WSADATA wsaData;
		if (WSAStartup(MAKEWORD( 2, 2 ), &wsaData) != 0) {
			LOG_ERROR("INIT", "Error initializing network");
		}
#endif
	//initialize curl...
	/* Must initialize libcurl before any threads are started */
	curl_global_init(CURL_GLOBAL_ALL);

	WriteHeaderLog();
	
	//esto es para que no casque
	m_pServer = NULL;
	#if defined(SINGLE_INSTANCE)

	//check numero de instancias del programa
	const wxString inst_name = wxString::Format(wxT("Ginkgo-%s"), wxGetUserId().c_str());
	m_singleInstanceChecker.Create(inst_name);
	#if defined(_WINDOWS)
	const wxString& name = inst_name;
	#else
	const wxString name(wxT("40000"));
	#endif
	//comprobación una instancia
	//If using a single instance, use IPC to
	// communicate with the other instance
	if (!m_singleInstanceChecker.IsAnotherRunning())
	{
		// Create a new server
		m_pServer = new stServer;
		if ( !m_pServer->Create( name ) )
		{
			//NO ha podido crearse el servidor......
			LOG_ERROR("Core", "Error creating IPC server");
		}
	} else {
		GNC::Entorno::Instance()->SetChildInstance(true);
		LOG_INFO("Core", "Ginkgo client instance initiallized");
		m_pServer = NULL;
		// OK, there IS another one running, so try to connect to it
		// and send it any filename before exiting.
		stClient* client = new stClient;
		// ignored under DDE, host name in TCP/IP based classes
		wxString hostName = wxT("localhost");
		// Create the connection
		wxConnectionBase* connection =
			client->MakeConnection(hostName,
			name, inst_name);
		if (connection)
		{
			if (argc > 1) {
				wxString str;
				for (int i = 1; i < argc && str.IsEmpty(); ++i) { // Find the first "not starting with --" argument
					wxString arg = wxString(argv[1]);
					if (!arg.StartsWith("--")) {
						str = arg;
					}
				}

				if (!str.IsEmpty()) {				
					if (str.Lower().StartsWith(wxT("ginkgocadx://"))) {
						LOG_INFO("Core", "The client sends following URL: " << str.ToUTF8());
						// Ask the other instance to open a file or raise itself
						connection->Execute(str);
						connection->Disconnect();
						delete connection;
					}
					else {
						wxFileName fileName = wxFileName(argv[1]);
						if (fileName.IsRelative()) {
							#if defined(__WXGTK__)
							char* invocation_dir = getenv("INVOCATION_DIR");					
							if (invocation_dir != NULL) {
								wxString invocationDir = wxString::FromUTF8(invocation_dir);
								if (!invocationDir.IsEmpty()) {
									fileName = invocationDir + wxFileName::GetPathSeparator() + fileName.GetFullPath();
								}
							}					
							#else
							fileName.MakeAbsolute();
							#endif
						}			
						if (fileName.IsOk() && ((fileName.FileExists() && fileName.IsFileReadable()) || (wxDirExists(fileName.GetFullPath()) && fileName.IsDirReadable()))) {
							LOG_INFO("Core", "The client sends following file: " << fileName.GetFullPath().ToUTF8());
							// Ask the other instance to open a file or raise itself
							connection->Execute(fileName.GetFullPath());
							connection->Disconnect();
							delete connection;
						}
						else {
							wxString err = wxString::Format(wxT("Error: The file %s does not exists or is not readable"), argv[1]);
							LOG_ERROR("Core", TOPATH(err));
							wxMessageBox(err, wxT("Ginkgo CADx"), wxICON_INFORMATION|wxOK);
						}
					}
				}
			} else {
				// Ask the other instance to open a file or raise itself
				connection->Execute(wxT(""));
				connection->Disconnect();
				delete connection;
			}
		}
		else
		{
			LOG_ERROR("Core", "The client could not communicate with server because the server had opened modal dialogs");
			wxMessageBox(wxT("Sorry, the existing instance may be too busy too respond.\nPlease close any open dialogs and retry."),
				wxT("Ginkgo CADx"), wxICON_INFORMATION|wxOK);
		}
		delete client;

		//nos salimos limpiamente sin dejar leaks
		GNC::GCS::IControladorLog::FreeInstance();
		GNC::Entorno::FreeInstance();
		GNC::GCS::ConfigurationController::FreeInstance();
		return false;
	}
	#endif

	wxPNGHandler* handlerPng=new wxPNGHandler();
	wxImage::AddHandler(handlerPng);
#if defined(_GINKGO_ENABLE_SPLASH)	
	m_pVentanaLogo = NULL;
	wxBitmap bitmap = GinkgoResourcesManager::Logos::GetLogoSplash();
	wxSplashScreen splash(bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT,
		-1, NULL, -1, wxDefaultPosition, wxDefaultSize,
		wxSTAY_ON_TOP|wxNO_BORDER);
	wxIcon icono;
	icono.CopyFromBitmap(GinkgoResourcesManager::Logos::GetLogoGinkgo32x32());
	splash.SetIcon(icono);
	splash.Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(Ginkgo::OnSplashClose));
	// Copia del bitmap original de la ventana splash para pintar sobre ella
	if (m_pBitmapOriginal.Create(bitmap.GetWidth(), bitmap.GetHeight(), bitmap.GetDepth())) {
		m_pVentanaLogo = &splash;
		wxMemoryDC srcDC(bitmap);
		wxMemoryDC dstDC(m_pBitmapOriginal);
		dstDC.Blit(wxPoint(0, 0), srcDC.GetSize(), &srcDC, wxPoint(0, 0), wxCOPY, false, wxPoint(0, 0));
	}
#endif
	DoProgress(wxString(_("Initializing environment ...")));		

	//inicializamos la intrnacionalizacion del core
	{
		GNC::GCS::ControladorInternacionalizacion::Instance()->AddCatalog("cadxcore");
	}
	//permisos del core
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "reutilize_study", _Std("Open only one tab for each study"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "anonymous_history", _Std("Anonymous mode (history is cleaned)"), false, "", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "max_tabs", _Std("Max number of tabs opened"), false, "2", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "inactivity_time", _Std("Max seconds of Ginkgo CADx application inactivity"), false, "600", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "auto_close", _Std("Close automatically Ginkgo CADx after dicomize"), false, "", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "export", _Std("Export images"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "acquire", _Std("Acquire DICOM files"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.restrictions", _Std("Ginkgo CADx restrictions"), "import", _Std("Import files to DICOM format"), false, "", true);
	#ifdef GINKGO_PRO
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.help", _Std("Online manual"), "url_manual", _Std("URL of manual"), true, _Std("doc\\manual_ginkgo_cadx_pro_en.pdf"), true);
	#else
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.help", _Std("Online manual"), "url_manual", _Std("URL of manual"), true, "http://doc.ginkgo-cadx.com/", true);
	#endif
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.help", _Std("Online support"), "url_support", _Std("URL of online support"), true, _Std("http://ginkgo-cadx.com/"), true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.update", _Std("Program Updates"), "check_updates", _Std("Warn about newest Ginkgo CADx updates"), false, "http://updates.ginkgo-cadx.com/version3.xml", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.update", _Std("Program Updates"), "update_period", _Std("Update period (days)"), false, "2", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.seguridad",_Std("Security"), "setup_security", _Std("Setup Security"), false, "", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.startup", _Std("Show on startup"), "startupdefaultvalue", _Std("Show on startup default value"), true, "", true);
	
	
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.menu",_Std("Tools"),"configuracion",_Std("Settings menu"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.menu",_Std("Tools"),"licencia",_Std("License menu"), true, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.limits", _Std("PACS Limits"),"pacs_upload",_Std("Upload images to a PACS server"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.limits", _Std("PACS Limits"), "pacs_acquisition", _Std("Acquire images from PACS"),false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.limits", _Std("PACS Limits"), "remote_pacs", _Std("Enable remote PACS configuration"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.limits", _Std("PACS Limits"), "pacs_tls", _Std("Enable TLS configuration"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.limits", _Std("PACS Limits"), "patient_scope", _Std("Restrict search over selected patient"), false, "", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.limits", _Std("PACS Limits"), "study_size", _Std("Restrict study retrieval by maximum size (KB)"), false, "16384", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.limits", _Std("PACS Limits"), "force_lossless", _Std("Force lossless when upload"), false, "", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.importacion", _Std("Import"), "storage_sop_class", _Std("Specify this Storage SOP Class in dicomization"), false, "1.2.840.10008.5.1.4.1.1.77.1.4", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.importacion", _Std("Import"), "input_accno", _Std("Show accession number input"), false, "", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.importacion", _Std("Import"), "quality", _Std("Set compression, 0 implies no compression (0..14)"), false, "1", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.importacion", _Std("Import"), "codec", _Std("Recompression codec (0=JPEG Baseline(default), 1=JPEG Progressive, 2=JPEG Lossless)"), false, "0", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.importacion", _Std("Import"), "mantener", _Std("Don't change image codec (if possible)"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.importacion", _Std("Import"), "skip_demographic", _Std("Skip demographic step if it's possible"), false, "", false);

	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.hl7", _Std("HL7 Service"), "autostart", _Std("Automatically start HL7 Sender service"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.integracion", _Std("XML dicomization"), "send_message", _Std("Send Hl7 message when importing"), false, "", false);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.integracion", _Std("XML dicomization"), "upload_pacs", _Std("Send study to PACS when importing"), false, "", true);
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.integracion",_Std("XML dicomization"), "integration_template",_Std("Default ORU template"),false, DEFAULT_INTEGRATION_MESSAGE_TEMPLATE, true);


	std::string modalidades[20] = {"CR","CT","DR","DX","IO","MG","MR","NM","OT","PT","RF","RG","SC","SR","US","XA","XC","ES","ECG","HD"};
	//permisos modalidades
	for(int i = 0; i < 20; ++i) {
		wxString texto = wxString::Format(_("Download %s images"),wxString::FromUTF8(modalidades[i].c_str()).c_str());
		GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.download",_Std("PACS"),modalidades[i],std::string(texto.ToUTF8()),false, "", true);
	}
		
	wxString texto = _("Download all modalities");
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.pacs.download",_Std("PACS"),"all",std::string(texto.ToUTF8()),false, "", true);

	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("core.opengl", _Std("OpenGL"), "enable_shaders", _Std("Enable shaders"), false, "", true);

	//ginkgocloud
	GNC::GCS::IControladorPermisos::Instance()->AddDefinicionPermiso("ginkgocloud",_Std("Ginkgo Cloud"), "download",_Std("Download from Ginkgo Cloud"),false, "", true);

	//

	itk::MultiThreader::SetGlobalDefaultNumberOfThreads(4);
	itk::MultiThreader::SetGlobalMaximumNumberOfThreads(4);
	vtkThreadedStreamingPipeline::SetMultiThreadedEnabled(true);
	vtkThreadedStreamingPipeline::SetAutoPropagatePush(true);

	/*
	vtkPolyDataMapper* m = vtkPolyDataMapper::New();
	m->GlobalImmediateModeRenderingOn();
	m->Delete();
	*/
#ifdef __WXMAC__
	wxApp::s_macAboutMenuItemId = 1062;
	wxApp::s_macPreferencesMenuItemId = 1063;
	wxApp::s_macHelpMenuTitleName = wxT("A&yuda");
	//wxSystemOptions::SetOption( wxMAC_TEXTCONTROL_USE_SPELL_CHECKER, 1 );
#endif


#if !defined(_GINKGO_DEBUG) || defined(OMITIR_VENTANA_ERRORES_VTK)
	vtkObject::GlobalWarningDisplayOff();
	itk::Object::GlobalWarningDisplayOff();
#endif


	wxThread::SetConcurrency(wxThread::GetCPUCount());

	//codecs...
	wxJPEGHandler* handler=new wxJPEGHandler();
	wxImage::AddHandler(handler);

	wxGIFHandler* handlerGif=new wxGIFHandler();
	wxImage::AddHandler(handlerGif);

	wxTIFFHandler* handleTiff = new wxTIFFHandler();
	wxImage::AddHandler(handleTiff);

	GNC::Entorno::Instance()->SetApp(this);

	{
		wxWindowDisabler dis;
		m_pVentanaPrincipal = new VentanaPrincipal(NULL, wxString::FromUTF8(GNC::Entorno::Instance()->GetApplicationName().c_str()));
		m_pVentanaPrincipal->Hide();
		SetTopWindow(m_pVentanaPrincipal);
	}

	DoProgress(wxString(_("Tools loading base ...")));

	DoProgress(wxString(_("Starting tools...")));
		
	GNC::RegisterCoreTools();

	DoProgress(wxString(_("Loading plugins ...")));

	try {
		LoadPlugins();
	}
	catch (GNC::GCS::IRequestingException& ex) {
		m_pVentanaLogo->Hide();
		if (ex.shouldExit()) {
			exit(-1);
		}
	}
	catch (GNC::GCS::IException& ex) {
		m_pVentanaLogo->Hide();
		LOG_ERROR("Init", "Error loading: " << ex.GetCause());		
		wxMessageBox(_("Unable to start GinkgoCADx:\n") + wxString::FromUTF8(ex.GetCause().c_str()),_("error"),wxICON_INFORMATION);
		exit(-1);
	}

	DoProgress(wxString(_("Loading resources ...")));
	GIL::DICOM::Conformance::Load();

	DoProgress(wxString(_("Starting services...")));
	try {
		GIL::DICOM::PACSController::Instance()->StartServer();
	}
	catch(GNC::GCS::IException& ex) {
		LOG_ERROR("Init", "Error starting PACS Service: " << ex.GetCause());
	}
	try {
		GNC::GCS::SmartRetrieveController::Instance()->resetStatus();
	}
	catch(...) {
		LOG_ERROR("Init", "Error starting smartRetrieve service");
	}

	DoProgress(wxString(_("Configuring environment ...")));

	try{
		GNC::GCS::ConfigurationController::TListGroups profiles;
		GNC::GCS::ConfigurationController::Instance()->readGroupGeneral("/GinkgoCore/Profiles", profiles);

		for (GNC::GCS::ConfigurationController::TListGroups::iterator it = profiles.begin(); it != profiles.end(); ++it) {
			bool value;
			(*it).readBoolValue("Apply",value, false);
			if (value) {
				std::string xml;
				if ((*it).readStringValue("XML", xml)) {
					GNC::GCS::IControladorPermisos::Instance()->CargarXMLPermisos(xml, false);
					break;
				}
			}
		}
	}
	catch(GNC::GCS::ControladorPermisosException& ex) {
		m_pVentanaLogo->Hide();
		wxMessageBox(_("Failed to set permissions:\n") + wxString::FromUTF8(ex.GetCause().c_str()),_("error"),wxICON_INFORMATION);
	}

	//es necesario porque hay permisos que afectan a menus
	m_pVentanaPrincipal->RefrescarMenus();

	//se registran vistas y modos
	const GNC::ControladorExtensiones::ListaModulos& listaModulos = GNC::ControladorExtensiones::Instance()->Modulos();
	for(GNC::ControladorExtensiones::ListaModulos::const_iterator it = listaModulos.begin(); it != listaModulos.end(); ++it)
	{
		(*it).second->RegistrarVistas();
	}

	DoProgress(wxString(_("Updating ...")));

	m_pVentanaPrincipal->CargarHistorial();	

	DoProgress(wxString(_("Interpreting parameters ...")));


	
	//parseo
	wxCommandEvent ce(wxEVT_COMMAND_MENU_SELECTED, ID_Inicio_Aplicacion);
	m_pVentanaPrincipal->GetEventHandler()->AddPendingEvent(ce);

#if defined (__WXMAC__)
	m_Inicializado = true;
	if (m_OpenFileName.size() > 0) {
		GinkgoDispatcher::Instance()->InsertarPeticion(m_OpenFileName);
	}
#endif
#if defined(_GINKGO_ENABLE_SPLASH)
	m_pVentanaLogo = NULL;
#endif
	//launch auto cleaning controller...
	GNC::GCS::AutoCleaningController::Instance();

	LOG_STAT(ANON_STAT_RUN_GINKGO)

	return TRUE;
}

#ifdef __WXMAC__
void Ginkgo::MacOpenFile(const wxString &fileName)
{
	if (m_Inicializado) {
		GinkgoDispatcher::Instance()->InsertarPeticion( std::string(TOPATH(fileName)) );
	}
	else {
		m_OpenFileName = std::string(TOPATH(fileName));
	}

}
#endif


int Ginkgo::OnExit()
{
	LOG_INFO("Core", "Cerrando Ginkgo ");
	//UnRegister events
	delete m_pEventObserverDelegate;
	m_pEventObserverDelegate = NULL;

	//UnRegister tools
	try {
		GNC::GCS::IToolsRegistry::Instance()->UnRegisterAll();
	}
	catch (GNC::GCS::ToolsRegistryException& ex) {
		LOG_ERROR("Core", _Std("Error unregistering tools: ") << ex.str())
	}

	GNC::GCS::StoredQueryController::FreeInstance();
	GNC::GCS::SmartRetrieveController::FreeInstance();
	GNC::GCS::AutoCleaningController::FreeInstance();
	GNC::GCS::AnonUsageStats::FreeInstance();
	GNC::GCS::ThumbnailController::FreeInstance();
	GNC::GCS::ModalitySettingsController::FreeInstance();
	GNC::GCS::HangingProtocolController::FreeInstance();
	GNC::GCS::ControladorVistas::FreeInstance();
	GIL::IntegrationController::FreeInstance();
	GIL::HL7::ControladorEnvioHl7::FreeInstance();
	GNC::GCS::ControladorAcciones::FreeInstance();
	GNC::GCS::InactivityController::FreeInstance();
	GIL::DICOM::PACSController::FreeInstance();
	GNC::GCS::ICommandController::FreeInstance();
	GNC::ControladorExtensiones::FreeInstance();
	GNC::GCS::ControladorCarga::FreeInstance();
	GNC::HistoryToolsController::FreeInstance();
	GNC::GCS::IToolsRegistry::FreeInstance();
	GNC::GCS::HistoryController::FreeInstance();
	GIL::HL7::ControladorBBDDHl7::FreeInstance();
	GNC::GCS::IControladorPermisos::FreeInstance();
	GNC::GCS::ControladorInternacionalizacion::FreeInstance();
	GSEC::Auth::ControladorAutenticacion::FreeInstance();
	DicomServerList::FreeInstance();
	wxSQLite3Database::ShutdownSQLite();
	GNC::GCS::IEventsController::FreeInstance();
	
	GNC::Entorno::FreeInstance();

	wxSocketBase::Shutdown();

#if defined(_WINDOWS)
	if (m_pServer != NULL) {
		delete m_pServer;
	}
#endif
	GNC::GCS::ConfigurationController::FreeInstance();

	GNC::GCS::IControladorLog::FreeInstance();

#if defined(_WINDOWS)
		WSACleanup();
#endif
	curl_global_cleanup();

	#if defined(_WINDOWS) && defined(_DEBUG)
	cairo_debug_reset_static_data();
	#endif
	
	return wxApp::OnExit();
}

// Modificación del estado en el banner

void Ginkgo::DoProgress(wxString str)
{
	if (m_pVentanaLogo == NULL) {
		return;
	}
	wxSplashScreenWindow* pSplashWin = m_pVentanaLogo->GetSplashWindow();

	wxMemoryDC srcDC(m_pBitmapOriginal);
	wxClientDC wdc(pSplashWin);

	wxColour colorTexto;

	colorTexto.Set(70,70,70);

	// Restauración del logo
	wdc.Blit(wxPoint(0, 0), srcDC.GetSize(), &srcDC, wxPoint(0, 0), wxCOPY, false, wxPoint(0, 0));

	// Dibujado del texto
	wdc.SetTextForeground(colorTexto);
	wdc.DrawText(str, 190, srcDC.GetSize().y - 37);
}

void Ginkgo::WriteHeaderLog(){
	LOG_INFO("Core", _Std("Starting") << " " << GNC::Entorno::Instance()->GetApplicationName() << " " << GNC::GCS::IEntorno::Instance()->GetGinkgoVersionString());
}
//endregion