/*
 * $Id: kernel.h 4851 2018-02-13 14:33:20Z antonin.misek-skoda-auto.cz $
 *
 * Description  : One line description of file.
 * Author       : Vaclav Kyba <mail/Jabber: vaseo1@gmail.com>  <ICQ: 98576293>
 *
 * Purpose      :
 *     Long description of what the file is for.
 */


#ifndef __KERNEL__H__
#define __KERNEL__H__
#include <deque>
//#include <wx/app.h>
#include <wx/filename.h>
#include <wx/dir.h>
#include <wx/stdpaths.h>

#define KERNEL Kernel::Instance()

#include "environment.h"
#include "interpreter.h"
//#include "scenemanager.h"
#ifdef VRUT_HPC
#include <wx/fileconf.h>
#else
#include "mainwindow.h"
#include <wx/display.h>
#endif
//#include "eventhandler.h"
//#include "smartptr.h"

//#define VRUT_SIGNAL_HANDLER
#ifdef VRUT_SIGNAL_HANDLER
#include <signal.h>
void SignalHandler(int signal);
#endif

#include "VrutApi.h"
#include <map>
#include <memory>
#include "FontGlyphsTexture.h"

namespace VRUT
{
	class IOManager;
#ifndef VRUT_HPC
	class RenderManager;
#endif
	class ManipulatorManager;
	class GeneralManager;
	class EventHandler;
	class SceneManager;

	///Application kernel - singleton
	class VRUT_CORE_API Kernel
	{
	public:
		typedef std::vector<wxString> ModuleNamesList;

	protected:
		///Singleton instance
		static Kernel * instance;
		///Event handler
		EventHandler * eventHandler;
		///Main thread ID
		wxThreadIdType mainThreadID;
		///Is kernel initialized?
		bool initialized;
		///Is kernel releasing data and exiting?
		bool exiting;
		///List of prefered modules to pick when loading
		ModuleNamesList preferedModules;
		///List of forbidden modules
		ModuleNamesList forbiddenModules;
		///Path to the vrut.exe
		wxString appPath;
		///Path to the user configuration
		wxString cfgPath;

		///Class constructor - disabled
#ifdef VRUT_HPC
		Kernel(const wxString &appPath);
#else
		Kernel(MainWindow * window, const wxString &appPath);
		///Application's main window
		MainWindow * mainWindow;
#endif
		///Copy constructor - disabled
		Kernel(const Kernel &);

		//Fonts
		wxCriticalSection _fontLock;
		std::vector< std::pair<wxFont, std::shared_ptr<FontGlyphsTexture> > > _fonts;

	public:
		///Environment with parameter management
		Environment environment;
		///Command interpreter
		Interpreter interpreter;
		///Input/output server
		IOManager * ioManager;
		///Manipulator manager
		ManipulatorManager * manipManager;
		///Scene manager
		SceneManager * sceneManager;
		///General manager
		GeneralManager * generalManager;
#ifdef __WXMSW__
		double VRUTGetTimeFrequency;
		bool VRUTGetTimeHasHRTimer;
#endif
		///Logging
		FlexiLog * flexiLog;
		//configuration file VRUT.gui
		wxFileConfig *VRUTConfig;

		///Create and get singleton instance
#ifdef VRUT_HPC
		static Kernel * Instantiate(const wxString &appPath);
#else
		static Kernel * Instantiate(MainWindow * window, const wxString &appPath);
		///Render server
		RenderManager * renderManager;
		///Get main window
		MainWindow * GetMainWindow() const
		{
			return mainWindow;
		}
		void WinPosSizeToVRUTConfig(const wxWindow *frame, const wxString &confName, bool size=true)
		{
			wxPoint posi = frame->GetPosition();
			VRUTConfig->Write(confName+wxT("pos_x"), posi.x);
			VRUTConfig->Write(confName+wxT("pos_y"), posi.y);
			if (size)
			{
				wxSize wsize = frame->GetSize();
				VRUTConfig->Write(confName + wxT("size_x"), wsize.x);
				VRUTConfig->Write(confName + wxT("size_y"), wsize.y);
			}
		}
		void WinPosSizeFromVRUTConfig(wxWindow *frame, const wxString &confName, const wxPoint &defPos, const wxSize &defSize, bool size = true)
		{
			frame->SetPosition(wxPoint(VRUTConfig->ReadLong(confName + wxT("pos_x"), defPos.x), VRUTConfig->ReadLong(confName + wxT("pos_y"), defPos.y)));
			if (size)
				frame->SetSize(VRUTConfig->ReadLong(confName + wxT("size_x"), defSize.x), VRUTConfig->ReadLong(confName + wxT("size_y"), defSize.y));
			if (wxDisplay::GetFromWindow(frame) == wxNOT_FOUND)
				frame->SetPosition(wxPoint(0, 0));
		}
#endif
		///Get singleton instance
		static Kernel * Instance()  { return instance; }
		///Set singleton instance
		static void SetInstance(Kernel *_instance)  { instance=_instance; }
		///Release singleton instance
		static void Release();
		///Class destructor
		~Kernel();

		///Is kernel initialized?
		bool IsInitialized() const
		{
			return initialized;
		}
		///Is kernel and app exiting
		bool IsExiting() const
		{
			return exiting;
		}
		///Get main thread ID
		wxThreadIdType GetMainThreadID() const
		{
			return mainThreadID;
		}
		///Get event handler and main message sink
		EventHandler * GetMessageSink() const
		{
			return eventHandler;
		}
		///Get module instance with unique module ID
		Module * GetModule(const MODULE_ID & id) const;
		///Get module instance with unique module ID
		MODULE_ID RunModule(const wxString & moduleName) const;
		///Release module instance with unique module ID
		void ReleaseModule(const MODULE_ID & id);
		///Get filenames of all available (instantiated or not) modules
		std::vector<wxFileName> GetAvailableModules() const;
		///Initialize servers and search for available modules
		bool Initialize();
		///Search all servers and get modules with given module name (and instance ID optionally)
		///\param[out] moduleList Will be filled with corresponding modules
		///\param[in] moduleName Module name (filename without extension)
		///\param[in] instanceID If defined one or no module is returned, otherwise instance ID is ignored
		///\return \c false if no module with \c moduleName name exists
		bool GetModules(std::vector<std::pair<Module *, MODULE_INSTANCE_ID> > * moduleList, const wxString & moduleName, MODULE_INSTANCE_ID instanceID = MODULE_INSTANCE_ID_NONE);
		///Add module's dynamic library name to prefered modules list
		///Last added has the highest priority
		void PreferModule(const wxString & libName);
		///Get preferred modules list
		const ModuleNamesList * GetPreferedModules() const
		{
			return &preferedModules;
		}
		bool IsPrefered(const wxString &moduleName)
		{
			return std::find(preferedModules.begin(), preferedModules.end(), moduleName)!=preferedModules.end();
		}
		///Add module's dynamic library name to forbidden modules list
		void ForbidModule(const wxString & libName);
		///Is module forbidden?
		bool IsForbidden(const wxString & libName) const;
		///Get path to the VRUT directory, allows use relative paths when working directory is different
		wxString GetAppPath() const
		{
			return appPath;
		}
		wxString GetCfgPath() const
		{
			return cfgPath;
		}
		static wxString GetCommonCfgPath()
		{
			wxString configDir(wxStandardPaths::Get().GetConfigDir());
			size_t pos = configDir.rfind(wxFileName::GetPathSeparator());
			if (pos != configDir.npos)
				configDir = configDir.substr(0, pos + 1) + wxT("VRUT");
			configDir += wxFileName::GetPathSeparator();
			return configDir;
		}
		bool InitGlew();
		static bool IsAVXSupported();
		static bool IsAVX2Supported();
		static void GetHWIdentification(std::vector<wxString> &hwInfo, std::vector<wxString> &networksDescriptions);
		static bool CheckLicenceFile(const wxString &licenceFilePath, const std::vector<wxString> &hwInfo);
		static bool IsHWLicenced(std::vector<wxString> &hwInfo);
		void SaveVRUTConfig()
		{
			//wxFileOutputStream out(appPath+wxT("vrut.gui"));
			if (!wxDir::Exists(KERNEL->GetCfgPath()))
				wxDir::Make(KERNEL->GetCfgPath());
			wxFileOutputStream out(KERNEL->GetCfgPath() + wxT("vrut.gui"));
			if (out.IsOk())
				VRUTConfig->Save(out);
		}

		std::shared_ptr<FontGlyphsTexture> GetOrCreateFont(wxFont font);

		static int VRUTVersion();
	};
}

#endif
