#include "safe_include.h" 
#include <gpac/m4_terminal.h>
#include <gpac/intern/m4_esm_dev.h>

#include "wx/wxprec.h"

#ifndef WX_PRECOMP
  #include "wx/wx.h"
#endif

#include "wxGPACPanel.h"
#include "V4StudioFrame.h"
#include "V4StudioApp.h"
#include "V4Service.h"

bool GPACInit(void *application, MPEG4CLIENT *term, M4User *user, bool quiet);

wxGPACPanel::wxGPACPanel(V4SceneManager *parent, const char *path) 
{
	this->parent = parent;
	m_term = NULL;
	m_pService = NULL;

	// Initializes the MPEG-4 terminal
	GPACInit(this, &m_term, &m_user, true);			
	if (!m_term) return;

	// Setting all the variables needed for picking of objects.
	m_iDragging = 0;
	m_transformMode = 0;
	dragX = dragY = 0;
	picked = NULL;

	if (path) {
		m_pService = new V4Service(path);
		M4T_OpenService(m_term, m_pService->GetServiceInterface());
	}
}

wxGPACPanel::~wxGPACPanel()
{
	if (m_pService) delete m_pService;
	if (m_term) M4T_Delete(m_term);
	if (m_user.plugins) PM_Delete(m_user.plugins);
	if (m_user.config) IF_Delete(m_user.config);
}


Bool V4S_EventProc(void *par, M4Event *evt)
{
	wxGPACPanel *panel = (wxGPACPanel *)par;
	if (!panel->GetMPEG4Terminal()) return 0;

	switch (evt->type) {
	case M4E_REFRESH:
		SR_RefreshWindow(panel->GetSceneRenderer());
		break;
	case M4E_WINDOWSIZE:
		SR_SizeChanged(panel->GetSceneRenderer(), evt->size.width, evt->size.height);
		panel->Update();
		break;
	case M4E_LEFTDOWN:
		panel->picked = SR_PickNode(panel->GetSceneRenderer(), evt->mouse.x, evt->mouse.y);
		panel->m_iDragging ++;
		if (panel->picked) {
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->SetSelectedItem(panel->picked);	
			panel->dragX = evt->mouse.x;
			panel->dragY = evt->mouse.y;
			panel->m_transformMode = 0;
		}
		break;
	case M4E_LEFTUP:
		panel->m_iDragging --;
		if (panel->picked) {
			int dX = evt->mouse.x - panel->dragX;
			int dY = evt->mouse.y - panel->dragY;
			panel->dragX = evt->mouse.x;
			panel->dragY = evt->mouse.y;
			wxString pos;
			pos << dX;
			pos << ',';
			pos << dY;
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->Translate(dX,dY);
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetStatusBar()->SetStatusText(pos);
		}
		break;
	case M4E_RIGHTDOWN:
		panel->m_iDragging ++;
		panel->picked = SR_PickNode(panel->GetSceneRenderer(), evt->mouse.x, evt->mouse.y);
		if (panel->picked) {
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->SetSelectedItem(panel->picked);	
			panel->dragX = evt->mouse.x;
			panel->dragY = evt->mouse.y;
			panel->m_transformMode = 1;
		}
		break;
	case M4E_RIGHTUP:
		panel->m_iDragging --;
		if (panel->picked) {
			int dX = evt->mouse.x - panel->dragX;
			int dY = evt->mouse.y - panel->dragY;
			panel->dragX = evt->mouse.x;
			panel->dragY = evt->mouse.y;
			wxString pos;
			pos << dX;
			pos << ',';
			pos << dY;
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->Scale(dX,dY);
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetStatusBar()->SetStatusText(pos);
		}
		break;
	case M4E_MIDDLEDOWN:
		panel->m_iDragging ++;
		panel->picked = SR_PickNode(panel->GetSceneRenderer(), evt->mouse.x, evt->mouse.y);
		if (panel->picked) {
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->SetSelectedItem(panel->picked);	
			panel->dragX = evt->mouse.x;
			panel->dragY = evt->mouse.y;
			panel->m_transformMode = 2;
		}
		break;
	case M4E_MIDDLEUP:
		panel->m_iDragging --;
		if (panel->picked) {
			int dX = evt->mouse.x - panel->dragX;
			int dY = evt->mouse.y - panel->dragY;
			panel->dragX = evt->mouse.x;
			panel->dragY = evt->mouse.y;
			wxString pos;
			pos << dX;
			pos << ',';
			pos << dY;
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->Rotate(dX,dY);
			panel->GetV4SceneManager()->GetV4StudioFrame()->GetStatusBar()->SetStatusText(pos);
		}
		break;
	case M4E_MOUSEMOVE:
	{
		wxString pos;
		if (panel->picked && panel->m_iDragging) {
			int dX = evt->mouse.x - panel->dragX;
			int dY = evt->mouse.y - panel->dragY;
			panel->dragX = evt->mouse.x;
			panel->dragY = evt->mouse.y;
			pos << dX;
			pos << ',';
			pos << dY;
			switch (panel->m_transformMode) {
			case 0:
				panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->Translate(dX,dY);
				break;
			case 1:
				panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->Scale(dX,dY);
				break;
			case 2:			
				panel->GetV4SceneManager()->GetV4StudioFrame()->GetTreeView()->Rotate(dX,dY);
				break;
			}
		} else {
			pos << evt->mouse.x;
			pos << ',';
			pos << evt->mouse.y;
		}
		panel->GetV4SceneManager()->GetV4StudioFrame()->GetStatusBar()->SetStatusText(pos);
	}
		break;
	case M4E_QUIT:
		panel->GetV4SceneManager()->GetV4StudioFrame()->Close(TRUE);
		break;
	}
	return 0;
}

void wxGPACPanel::Update() 
{
	if (m_term) {
		//M4T_SetOption(m_term, M4O_PlayState, M4_StepPause);
		SR_Invalidate(m_term->renderer, NULL);
		SR_RenderFrame(m_term->renderer);
	}
}

bool GPACInit(void *application, MPEG4CLIENT *term, M4User *user, bool quiet) 
{
	memset(user, 0, sizeof(M4User));

	/*locate exec dir for cfg file*/
    wxPathList pathList;
	wxString currentDir(wxGetCwd());
    wxString abs_gpac_path = "";
	const char *gpac_cfg;

	if (!quiet) ::wxLogMessage("Looking for GPAC configuration file");

#if defined(__WXMAC__) && !defined(__DARWIN__)
    // On Mac, the current directory is the relevant one when the application starts.
    abs_gpac_path = wxGetCwd();
	gpac_cfg = "GPAC.cfg";
#else

#ifdef WIN32
	V4StudioApp &app = wxGetApp();
	gpac_cfg = "GPAC.cfg";
	/*locate exe*/
    if (wxIsAbsolutePath(app.argv[0])) {
        abs_gpac_path = wxPathOnly(app.argv[0]);
	} else {
		if (currentDir.Last() != wxFILE_SEP_PATH) currentDir += wxFILE_SEP_PATH;
		abs_gpac_path = currentDir + app.argv[0];
		if (wxFileExists(abs_gpac_path)) {
			abs_gpac_path = wxPathOnly(abs_gpac_path);
		} else {
			abs_gpac_path = "";
			pathList.AddEnvList(wxT("PATH"));
			abs_gpac_path = pathList.FindAbsoluteValidPath(app.argv[0]);
			if (!abs_gpac_path.IsEmpty()) {
				abs_gpac_path = wxPathOnly(abs_gpac_path);
			} else {
				/*ask user*/
				wxDirDialog dlg(NULL, "Locate GPAC config file directory");
				if ( dlg.ShowModal() != wxID_OK ) return 0;
				abs_gpac_path = dlg.GetPath();
			}
		}
	}
#else
	gpac_cfg = ".gpacrc";
	char *cfg_dir = getenv("HOME");
	if (cfg_dir) {
		abs_gpac_path = cfg_dir;
	} else {
		/*ask user*/
		wxDirDialog dlg(NULL, "Locate GPAC config file directory");
		if ( dlg.ShowModal() != wxID_OK ) return 0;
		abs_gpac_path = dlg.GetPath();
	}

#endif

#endif

	/*load config*/
	user->config = NewIniFile(abs_gpac_path.c_str(), gpac_cfg);

	if (!user->config) {
		unsigned char config_file[M4_MAX_PATH];
		strcpy((char *) config_file, (const char *) abs_gpac_path.c_str());
		if (config_file[strlen((char *) config_file)-1] != M4_PATH_SEPARATOR) {
		  char szSep[2];
		  szSep[0] = M4_PATH_SEPARATOR;
		  szSep[1] = 0;
		  strcat((char *) config_file, (const char *)szSep);
		}
		strcat((char *) config_file, gpac_cfg);
		FILE *ft = fopen((const char *) config_file, "wt");
		if (!ft) {
			wxMessageDialog(NULL, "Cannot create blank config file", "Init error", wxOK).ShowModal();
			return 0;
		}
		fclose(ft);
		user->config = NewIniFile(abs_gpac_path.c_str(), gpac_cfg);
		if (!user->config) {
			wxMessageDialog(NULL, "Cannot open GPAC configuration file", "Init error", wxOK);
			return 0;
		}
	}
	if (!quiet) ::wxLogMessage("GPAC configuration file opened - looking for plugins");
	/*get plugins*/
	const char *str = IF_GetKey(user->config, "General", "PluginsDirectory");
	Bool first_launch = 0;
	if (!str) {
	  first_launch = 1;
#ifdef M4_PLUGIN_PATH
		str = M4_PLUGIN_PATH;
#else
		str = abs_gpac_path.c_str();
#endif
	}
	user->plugins = NewPluginManager((const unsigned char *) str, user->config);

	/*initial launch*/
	if (first_launch || !PM_GetPluginsCount(user->plugins)) {
		char *sOpt;
		wxDirDialog dlg(NULL, "Locate GPAC plugins directory");
		if  (!PM_GetPluginsCount(user->plugins)) {
		  PM_Delete(user->plugins);
		  user->plugins = NULL;
			if ( dlg.ShowModal() != wxID_OK ) return false;
			str = dlg.GetPath().c_str();;
	
			user->plugins = NewPluginManager((const unsigned char *) str, user->config);
			if (!user->plugins || !PM_GetPluginsCount(user->plugins) ) {
				wxMessageDialog(NULL, "Cannot find any plugins for GPAC", "Init error", wxOK);
				IF_Delete(user->config);
				return 0;
			}		
		}

		IF_SetKey(user->config, "General", "PluginsDirectory", (const char *) str);

		/*check audio config on windows, force config*/
		sOpt = IF_GetKey(user->config, "Audio", "ForceConfig");
		if (!sOpt) {
			IF_SetKey(user->config, "Audio", "ForceConfig", "yes");
			IF_SetKey(user->config, "Audio", "NumBuffers", "8");
			IF_SetKey(user->config, "Audio", "BuffersPerSecond", "16");
		}

#ifdef WIN32
		sOpt = IF_GetKey(user->config, "Rendering", "Raster2D");
		if (!sOpt) IF_SetKey(user->config, "Rendering", "Raster2D", "gdip_rend");
		sOpt = IF_GetKey(user->config, "General", "CacheDirectory");
		if (!sOpt) {
			unsigned char str_path[MAX_PATH];
			sprintf((char *) str_path, "%scache", abs_gpac_path.c_str());
			IF_SetKey(user->config, "General", "CacheDirectory", (const char *) str_path);
		}
		/*by default use GDIplus, much faster than freetype on font loading*/
		IF_SetKey(user->config, "FontEngine", "DriverName", "gdip_rend");
		IF_SetKey(user->config, "Video", "DriverName", "DirectX Video Output");
#else
		wxDirDialog dlg3(NULL, "Please specify a cache directory for GPAC");
		dlg3.SetPath("/tmp");
		if ( dlg3.ShowModal() == wxID_OK ) 
			IF_SetKey(user->config, "General", "CacheDirectory", (const char *) dlg3.GetPath().c_str() );

		wxDirDialog dlg2(NULL, "Please locate a TrueType font repository on your system for text support");
		dlg2.SetPath("/usr/share/fonts/truetype");
		if ( dlg2.ShowModal() == wxID_OK ) 
			IF_SetKey(user->config, "FontEngine", "FontDirectory", (const char *) dlg2.GetPath().c_str() );

		IF_SetKey(user->config, "Video", "DriverName", "SDL Video Output");
#endif
	}	
	if (! PM_GetPluginsCount(user->plugins) ) {
		wxMessageDialog(NULL, "No plugins available - system cannot work", "Fatal Error", wxOK).ShowModal();
		PM_Delete(user->plugins);
		IF_Delete(user->config);
		return 0;
	}

	if (!quiet) ::wxLogMessage("%d plugins found:", PM_GetPluginsCount(user->plugins));
	for (u32 i=0; i<PM_GetPluginsCount(user->plugins); i++) {
		if (!quiet) ::wxLogMessage("\t%s", PM_GetFileName(user->plugins, i));
	}

	if (!quiet) ::wxLogMessage("Starting MPEG-4 Terminal");
	/*now load terminal*/
	user->opaque = application;
	user->EventProc = V4S_EventProc;
//	user->os_window_handler = ((wxGPACPanel *)application)->GetV4SceneManager()->GetV4StudioFrame()->GetHandle();

	// Forces the renderer to not use a thread and do the rendering by itfe
	IF_SetKey(user->config, "Systems", "NoVisualThread", "No");

	*term = NewMPEG4Term(user);
	if (!*term) {
		wxMessageDialog(NULL, "Fatal Error", "Cannot load MPEG-4 Terminal", wxOK).ShowModal();
		return 0;
	} else {
		if (!quiet) ::wxLogMessage("MPEG-4 Terminal started - using %s", IF_GetKey(user->config, "Rendering", "RendererName"));
	}

	return 1;
}

