/*
 * $Id: interpreter.cpp 4717 2017-09-27 12:08:17Z 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.
 */

#include "interpreter.h"
#include "commands.h"
#include <wx/filename.h>
#include <wx/dir.h>
#include <wx/dynlib.h>
#include "textparser.h"
#include "kernel.h"
#include "eventhandler.h"
#include "scenemanager.h"

#ifdef VRUT_HPC
#include "modulehandle.h"
#else
#include "rendermanager.h"
#include <wx/display.h>
#include "basedefs.h"
#endif


using namespace VRUT;

// if 1 use a separate thread to process script commands
// this allows the script to stop and wait for particular amount of time
// or wait for a particular event (e.g. scene import done)
#define USE_SCRIPT_THREAD 1

Interpreter::Interpreter()
{
	///Fill commands list
	ArgList args;
	///CMD_EXIT
	commandEntries.insert(CommandEntries::value_type(CMD_EXIT, args));
	///CMD_USEMODULE
	args.clear();
	args.push_back(Argument(wxT("moduleName"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_USEMODULE, args));
	///CMD_FORBIDMODULE
	args.clear();
	args.push_back(Argument(wxT("moduleName"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_FORBIDMODULE, args));
	///CMD_RUNMODULE
	args.clear();
	args.push_back(Argument(wxT("moduleName"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_RUNMODULE, args));
	///CMD_IMPORTSCENE
	args.clear();
	args.push_back(Argument(wxT("fileName"), ARG_STRING, true));
	args.push_back(Argument(wxT("sceneID"), ARG_UNSIGNED, false));
	args.push_back(Argument(wxT("nodeID"), ARG_UNSIGNED, false));
	commandEntries.insert(CommandEntries::value_type(CMD_IMPORTSCENE, args));
	///CMD_EXPORTSCENE
	args.clear();
	args.push_back(Argument(wxT("sceneID"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("fileName"), ARG_STRING, true));
	args.push_back(Argument(wxT("rootID"), ARG_UNSIGNED, false));
	commandEntries.insert(CommandEntries::value_type(CMD_EXPORTSCENE, args));
	///CMD_LISTSCENES
	args.clear();
	commandEntries.insert(CommandEntries::value_type(CMD_LISTSCENES, args));
	///CMD_RENDERSCENE
	args.clear();
	args.push_back(Argument(wxT("sceneID"), ARG_UNSIGNED, false));
	commandEntries.insert(CommandEntries::value_type(CMD_RENDERSCENE, args));
	///CMD_RENDERIMAGE
	args.clear();
	args.push_back(Argument(wxT("sceneID"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("cameraID"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("width"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("height"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("fileName"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_RENDERIMAGE, args));
	///CMD_SETPARAM
	args.clear();
	args.push_back(Argument(wxT("module[.param[.instID]]"), ARG_STRING, true));
	args.push_back(Argument(wxT("value"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_SETPARAM, args));
	///CMD_GETPARAM
	args.clear();
	args.push_back(Argument(wxT("module[.param[.instID]]"), ARG_STRING, false));
	commandEntries.insert(CommandEntries::value_type(CMD_GETPARAM, args));
	///CMD_FIT
	args.clear();
	args.push_back(Argument(wxT("windowID"), ARG_UNSIGNED, true));
	commandEntries.insert(CommandEntries::value_type(CMD_FIT, args));
	///CMD_FULLSCREEN
	args.clear();
	args.push_back(Argument(wxT("windowID"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("enable"), ARG_BOOL, false));
	commandEntries.insert(CommandEntries::value_type(CMD_FULLSCREEN, args));
	///CMD_FULLSCREENSET
	args.clear();
	args.push_back(Argument(wxT("windowID"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("fsMode"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("positionX"), ARG_UNSIGNED, false));
	args.push_back(Argument(wxT("positionY"), ARG_UNSIGNED, false));
	args.push_back(Argument(wxT("sizeX"), ARG_UNSIGNED, false));
	args.push_back(Argument(wxT("sizeY"), ARG_UNSIGNED, false));
	args.push_back(Argument(wxT("colorRGB"), ARG_UNSIGNED, false));
	commandEntries.insert(CommandEntries::value_type(CMD_FULLSCREENSET, args));
	///CMD_RESETVIEW
	args.clear();
	args.push_back(Argument(wxT("windowID"), ARG_UNSIGNED, true));
	commandEntries.insert(CommandEntries::value_type(CMD_RESETVIEW, args));
	///CMD_SETLOGLEVEL
	args.clear();
	args.push_back(Argument(wxT("loglevel"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_SETLOGLEVEL, args));
	///CMD_LISTMODULES
	args.clear();
	commandEntries.insert(CommandEntries::value_type(CMD_LISTMODULES, args));
	///CMD_MODHELP
	args.clear();
	args.push_back(Argument(wxT("module"), ARG_STRING, false));
	commandEntries.insert(CommandEntries::value_type(CMD_MODHELP, args));
	///CMD_LS
	args.clear();
	args.push_back(Argument(wxT("path"), ARG_STRING, false));
	commandEntries.insert(CommandEntries::value_type(CMD_LS, args));
	///CMD_GETVIDEOMODES
	args.clear();
	args.push_back(Argument(wxT("displayID"), ARG_UNSIGNED, false));
	commandEntries.insert(CommandEntries::value_type(CMD_GETVIDEOMODES, args));
	///CMD_SETVIDEOMODE
	args.clear();
	args.push_back(Argument(wxT("displayID"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("width"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("height"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("bpp"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("refresh"), ARG_UNSIGNED, true));
	commandEntries.insert(CommandEntries::value_type(CMD_SETVIDEOMODE, args));
	///CMD_SWITCHVIDEOOUTS
	args.clear();
	args.push_back(Argument(wxT("displayID"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("width"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("height"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("bpp"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("refresh"), ARG_UNSIGNED, true));
	commandEntries.insert(CommandEntries::value_type(CMD_SWITCHVIDEOOUTS, args));
	///CMD_CARDISPLAY
	args.clear();
	args.push_back(Argument(wxT("texturepath"), ARG_STRING, true));
	args.push_back(Argument(wxT("ratiox"), ARG_UNSIGNED, true));
	args.push_back(Argument(wxT("ratioy"), ARG_UNSIGNED, true));
	commandEntries.insert(CommandEntries::value_type(CMD_CARDISPLAY, args));
	///CMD_SHOWPANE
	args.clear();
	args.push_back(Argument(wxT("panename"), ARG_STRING, true));
	args.push_back(Argument(wxT("show"), ARG_BOOL, true));
	commandEntries.insert(CommandEntries::value_type(CMD_SHOWPANE, args));
	///CMD_SHOWPARAM
	args.clear();
	args.push_back(Argument(wxT("paramname"), ARG_STRING, true));
	args.push_back(Argument(wxT("show"), ARG_BOOL, true));
	commandEntries.insert(CommandEntries::value_type(CMD_SHOWPARAM, args));
	///CMD_ADAMSTODELTAGEN
	args.clear();
	args.push_back(Argument(wxT("adamsfile"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_ADAMSTODELTAGEN, args));
	///CMD_HELP
	args.clear();
	commandEntries.insert(CommandEntries::value_type(CMD_HELP, args));
	///CMD_WAIT
	args.clear();
	args.push_back(Argument(wxT("time[ms]"), ARG_UNSIGNED, true));
	commandEntries.insert(CommandEntries::value_type(CMD_WAIT, args));
	///CMD_BIN2C
	args.clear();
	args.push_back(Argument(wxT("filename"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_BIN2C, args));
	//CMD_RUNONCLIENT
	args.clear();
	args.push_back(Argument(wxT("nodename"), ARG_STRING, true));
	args.push_back(Argument(wxT("command"), ARG_STRING, true));
	commandEntries.insert(CommandEntries::value_type(CMD_RUNONCLIENT, args));

	scriptThread = NULL;
	scriptThreadIsRunning=false;
}


Interpreter::~Interpreter()
{
	if (scriptThread)
	{
		if (scriptThread->IsRunning())
			scriptThread->Delete();
		while (scriptThreadIsRunning)
			wxThread::Sleep(1);
	}
}


wxString Interpreter::getUsageString(CommandEntries::const_iterator cmdEntry) const
{
	wxString usage(cmdEntry->first);
	for (auto &arg : cmdEntry->second)
	{
		wxString argStr = arg.name;
		switch (arg.type)
		{
		case ARG_STRING:
			argStr << wxT(":string");
			break;
		case ARG_INT:
			argStr << wxT(":integer");
			break;
		case ARG_UNSIGNED:
			argStr << wxT(":unsigned");
			break;
		case ARG_FLOAT:
			argStr << wxT(":float");
			break;
		case ARG_BOOL:
			argStr << wxT(":bool");
			break;
		}
		if (!arg.mandatory)
			argStr.Prepend(wxT("[")).Append(wxT("]"));
		usage << wxT(" ") << argStr;
	}
	return usage;
}


size_t Interpreter::GetCommandsStarting(const wxString & cmdPart, std::vector<wxString> * cmdList) const
{
	for (CommandEntries::const_iterator cmd = commandEntries.begin(); cmd != commandEntries.end(); ++cmd)
	{
		if (cmd->first.Lower().StartsWith(cmdPart.Lower().Trim().Trim(false)))
			cmdList->push_back(getUsageString(cmd));
	}
	return cmdList->size();
}


size_t Interpreter::GetFilesStarting(const wxString & filePart, std::vector<wxString> * fileList) const
{
	// get a list of files starting with cmdPart
	wxFileName fullName(filePart);
	bool useNativeSeparator = false;

	// enforce unix path separators unless there is already a blackslash in the filename part
	if (filePart.Find('\\')!=-1)
		useNativeSeparator = true;

	wxString path = fullName.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR, useNativeSeparator ? wxPATH_NATIVE: wxPATH_UNIX);
	//LOG(path);
	if (path.IsEmpty())
		path = wxString::FromAscii("./");
	if (!wxDir::Exists(path))
		return 0;
	wxDir dir(path);
	if (!dir.IsOpened())
		return 0;

	// first enumarate directories
	wxString name = fullName.GetFullName();
	wxString filename;
	bool cont = dir.GetFirst(&filename, name + wxString::FromAscii("*"), wxDIR_DIRS);
	while (cont)  {
		wxString str = path + filename;
		// enforce case sensitivity
		if (str.Find(filePart)!=-1) {
			if (useNativeSeparator)
				str += wxFileName::GetPathSeparator();
			else // enforce unix path
				str += wxString::FromAscii("/");
			fileList->push_back(str);
		}
		cont = dir.GetNext(&filename);
	}

	cont = dir.GetFirst(&filename, name + wxString::FromAscii("*"), wxDIR_FILES);
	while (cont)  {
		wxString str = path + filename;
		if (str.Find(filePart)!=-1) 
			fileList->push_back(str);
		cont = dir.GetNext(&filename);
	}
  
	return fileList->size();
}


size_t Interpreter::GetModulesStarting(const wxString & namePart, std::vector<wxString> * moduleList) const
{
	char modulePaths[4][32]  = { "./modules/", "./modules/io/", "./modules/manip/", "./modules/render/"};
	for (int i=0; i < 4; i++) {
		if (wxDir::Exists(wxString::FromAscii(modulePaths[i]))) {
			wxString str;
			wxDir dir(wxString::FromAscii(modulePaths[i]));
			bool cont = dir.GetFirst(&str, namePart + wxDynamicLibrary::CanonicalizeName(wxT("*"), wxDL_MODULE), wxDIR_FILES);
			while (cont)  {
				// enforce case sensitivity
				if (namePart == str.Mid(0, namePart.length())) {
					wxFileName filename(str);
					moduleList->push_back(filename.GetName());
				}
				cont = dir.GetNext(&str);
			}
		}
	}
	return moduleList->size();
}


bool Interpreter::CheckSyntax(const wxString & cmd) const
{
	if (cmd.IsEmpty())
		return false;

	TextParser txtParse(cmd.utf8_str());
	wxString cmdName = txtParse.GetWxStringUtf8();

	CommandEntries::const_iterator cmdEntry = commandEntries.find(cmdName);
	if (cmdEntry == commandEntries.end())
	{
		LOGERROR(wxT("<Interpreter>Unrecognized command: '")+cmdName+wxT("'"));
		return false;
	}

	for (auto &arg : cmdEntry->second)
	{
		if (txtParse.IsEmpty())
		{
			if (arg.mandatory)
			{
				LOGERROR(wxT("<Interpreter>Not enough arguments. Usage: '")+getUsageString(cmdEntry)+wxT("'"));
				return false;
			}
			else
				return true;
		}

		wxString cmdArg = txtParse.GetWxStringUtf8();
		//try to solve problem with quoted parameter name
		//TODO: check other cases with quotes
		size_t quoteCount=0;
		for (size_t i=0; i<cmdArg.size(); i++)
			if (cmdArg[i]==wxT('\"'))
				quoteCount++;
		if (quoteCount==1)
		{
			txtParse.GetWxString("\"");
			txtParse.GetChar();
		}

		bool valid = true;
		long tmpl;
		unsigned long tmpul;
		float tmpf;
		switch (arg.type)
		{
		case ARG_INT:
			valid = cmdArg.ToLong(&tmpl);
			break;
		case ARG_UNSIGNED:
			valid = cmdArg.ToULong(&tmpul);
			break;
		case ARG_FLOAT:
			valid = TextParser(cmdArg.utf8_str()).myatof(tmpf);
			break;
		case ARG_STRING:
		case ARG_BOOL:
			break;
		}

		if (!valid)
		{
			LOGERROR(wxT("<Interpreter>Invalid argument '")+cmdArg+wxT("' Usage: ")+getUsageString(cmdEntry));
			return false;
		}
	}

	if (!txtParse.IsEmpty())
	{
		LOGERROR(wxT("<Interpreter>Too many arguments. Usage: ")+getUsageString(cmdEntry));
		return false;
	}

	return true;
}

/*inline __m128 CrossProductTest(__m128 a, __m128 b)
{
	return _mm_sub_ps(
		_mm_mul_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)), _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2))),
		_mm_mul_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)), _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)))   );
}
inline float DotProductTest(__m128 a, __m128 b)
{
	return _mm_dp_ps(a, b, 0xF1).m128_f32[0];
}*/

bool Interpreter::ProcessCommand(const wxString &cmd)
{
	wxString command(cmd);
	command.Trim().Trim(false);
	if (command.IsEmpty() || command.GetChar(0) == '#')
		return false;

	LOG(cmd);
	if (CheckSyntax(command))
	{
		TextParser txtParser(command.utf8_str());
		wxString commandName = txtParser.GetWxStringUtf8();
		if (commandName.IsSameAs(CMD_EXIT))
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_EXIT(), true);
		else if (commandName.IsSameAs(CMD_USEMODULE))
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_MODULE_PREFER(txtParser.GetWxStringUtf8()));
		else if (commandName.IsSameAs(CMD_FORBIDMODULE))
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_MODULE_FORBID(txtParser.GetWxStringUtf8()));
		else if (commandName.IsSameAs(CMD_RUNMODULE))
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_MODULE_RUN(txtParser.GetWxStringUtf8()));
		else if (commandName.IsSameAs(CMD_IMPORTSCENE))
		{
			wxString fileName(txtParser.GetWxStringUtf8());
			SCENE_ID sceneID=SCENE_ID_NONE;
			NODE_ID nodeID=NODE_ID_NONE;
			long tmp;
			if (txtParser.ParseLong(&tmp))
			{
				sceneID=(SCENE_ID)tmp;
				if (txtParser.ParseLong(&tmp))
					nodeID=(NODE_ID)tmp;
			}
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_IO_SCENE_IMPORT(fileName, sceneID, nodeID));
		}
		else if (commandName.IsSameAs(CMD_EXPORTSCENE))
		{
			long sceneID = 0;
			txtParser.ParseLong(&sceneID);
			wxString fname(txtParser.GetWxStringUtf8());
			long rootID;
			if (!txtParser.ParseLong(&rootID))
				rootID=-1;
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_IO_SCENE_EXPORT((SCENE_ID)sceneID, (NODE_ID)rootID, fname));
		}
		else if (commandName.IsSameAs(CMD_RENDERSCENE))
		{
			long argL = 0;
			if (!txtParser.ParseLong(&argL))
			{
				std::vector<SCENE_ID> scenes;
				KERNEL->sceneManager->GetSceneIDs(scenes);
				if (scenes.size()>0)
					argL = scenes.back();
			}
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_RENDER_SCENE(SCENE_ID(argL)));
		}
		else if (commandName.IsSameAs(CMD_RENDERIMAGE))
		{
			long argSceneID = 0;
			if (!txtParser.ParseLong(&argSceneID))
				return false;
			long argCameraID = 0;
			if (!txtParser.ParseLong(&argCameraID))
				return false;
			int argWidth = 0;
			if (!txtParser.ParseInt(&argWidth))
				return false;
			int argHeight = 0;
			if (!txtParser.ParseInt(&argHeight))
				return false;
			wxString fileName(txtParser.GetWxStringUtf8());
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_RENDER_IMAGE((SCENE_ID)argSceneID, (NODE_ID)argCameraID, argWidth, argHeight, fileName, true, false));
		}
		else if (commandName.IsSameAs(CMD_LISTSCENES))
		{
			std::vector<smart_pointer_v2<Scene> > scenes;
			KERNEL->sceneManager->GetScenes(scenes);
			for (size_t i=0; i<scenes.size(); ++i)
				LOG(wxString::Format(wxT("SceneID = %lu, name = "), (unsigned long)scenes[i]->GetID())+scenes[i]->GetName());
		}
		else if (commandName.IsSameAs(CMD_SETPARAM))
		{
			Parameter::ParameterIdentifier pi;
			if (!txtParser.IsEmpty())
				pi.poolName = txtParser.GetWxStringUtf8(". \t");
			if (!txtParser.IsEmpty() && (txtParser.NextCharIs('.', NULL, false)))
				pi.paramName = txtParser.GetWxStringUtf8(". \t");
			if (!txtParser.IsEmpty() && (txtParser.NextCharIs('.', NULL, false)))
				pi.instName = txtParser.GetWxStringUtf8(". \t\n\r");
			wxString value = txtParser.GetWxStringUtf8();
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_PARAM_SET_DO(pi, value));
		}
		else if (commandName.IsSameAs(CMD_GETPARAM))
		{
			Parameter::ParameterIdentifier pi;
			if (!txtParser.IsEmpty())
				pi.poolName = txtParser.GetWxStringUtf8(". \t");
			if (!txtParser.IsEmpty() && (txtParser.NextCharIs('.', NULL, false)))
				pi.paramName = txtParser.GetWxStringUtf8(". \t");
			if (!txtParser.IsEmpty() && (txtParser.NextCharIs('.', NULL, false)))
				pi.instName = txtParser.GetWxStringUtf8(". \t\n\r");
			std::vector<Environment::NameValue> vals;
			KERNEL->environment.GetParams(pi, vals);
			for (std::vector<Environment::NameValue>::const_iterator it = vals.begin(); it != vals.end(); ++it)
				LOG(it->first+wxT(" = ")+it->second);
		}
		else if (commandName.IsSameAs(CMD_FIT) || commandName.IsSameAs(CMD_RESETVIEW))
		{
#ifndef VRUT_HPC
			long argL = 0;
			txtParser.ParseLong(&argL);
			const GLWindow * glw = KERNEL->renderManager->GetGLWindow(RENDER_WINDOW_ID(argL));
			if (glw && glw->GetRenderModule())
			{
				if (commandName.IsSameAs(CMD_FIT))
					KERNEL->GetMessageSink()->PostEvent(GET_EVT_SCENE_CAM_FIT(glw->GetRenderModule()->GetSceneID(), glw->GetRenderModule()->GetCameraID()));
				else
					KERNEL->GetMessageSink()->PostEvent(GET_EVT_SCENE_CAM_RESETVIEW(glw->GetRenderModule()->GetSceneID(), glw->GetRenderModule()->GetCameraID()));
			}
			else
				LOGERROR(wxString::Format(wxT("<Interpreter>No window with ID %li found or no render module associated with window"), argL));
#endif
		}
		else if (commandName.IsSameAs(CMD_FULLSCREEN))
		{
			long argL = 0;
			txtParser.ParseLong(&argL);
			bool fs = txtParser.IsEmpty() || isTrue(txtParser.GetWxString());
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_RENDER_FULLSCREEN_SET(argL, fs?3:0));
		}
		else if (commandName.IsSameAs(CMD_FULLSCREENSET))
		{
			unsigned long windowID = 0;
			int fsMode = 0;
			int positionX = -1;
			int positionY = -1;
			int sizeX = -1;
			int sizeY = -1;
			unsigned long colorRGB = 0;
			txtParser.ParseULong(&windowID);
			if (!txtParser.IsEmpty())
				txtParser.ParseInt(&fsMode);
			if (!txtParser.IsEmpty())
				txtParser.ParseInt(&positionX);
			if (!txtParser.IsEmpty())
				txtParser.ParseInt(&positionY);
			if (!txtParser.IsEmpty())
				txtParser.ParseInt(&sizeX);
			if (!txtParser.IsEmpty())
				txtParser.ParseInt(&sizeY);
			if (!txtParser.IsEmpty())
				txtParser.ParseULong(&colorRGB);
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_RENDER_FULLSCREEN_SET(windowID, fsMode, positionX, positionY, sizeX, sizeY, colorRGB));
		}
		else if (commandName.IsSameAs(CMD_SETLOGLEVEL))
		{
			const char *keywords[] = {"disable", "errors", "warnings", "messages", "all", ""};
			int logLevel = txtParser.KeywordsSwitch(keywords);
			if (logLevel>=0)
				KERNEL->GetMessageSink()->PostEvent(GET_EVT_LOG_LEVEL_SET(logLevel), true);
			else
				LOGWARNING(wxT("<Interpreter> Unknown log level"));
		}
		else if (commandName.IsSameAs(CMD_LISTMODULES))
		{
			LOG(wxT("Available modules:"));
			std::vector<wxFileName> mods = KERNEL->GetAvailableModules();
			for (std::vector<wxFileName>::iterator it = mods.begin(); it != mods.end(); ++it)
				LOG(it->GetFullPath());

			ModuleList insts;
			LOG(wxT("Instances:"));
			KERNEL->GetModules(&insts, wxT("*"));
			for (ModuleList::iterator iit = insts.begin(); iit != insts.end(); ++iit)
				LOG(iit->first->GetName()+wxString::Format(wxT(".%lu ("), (unsigned long)iit->second)+iit->first->GetID().ToString()+wxT(")"));
		}
		else if (commandName.IsSameAs(CMD_MODHELP))
		{
			ModuleList insts;
			wxString modMask = wxT("*");
			if (!txtParser.IsEmpty())
				modMask = txtParser.GetWxStringUtf8();
			KERNEL->GetModules(&insts, modMask);
			for (ModuleList::iterator iit = insts.begin(); iit != insts.end(); ++iit)
			{
				LOG(iit->first->GetName()+wxString::Format(wxT(".%lu"), (unsigned long)iit->second));
				LOG(iit->first->GetDesc());
			}
		}
		else if (commandName.IsSameAs(CMD_LS))
		{
			wxString path = wxT(".");
			wxString mask = wxT("*");
			if (!txtParser.IsEmpty())
			{
				wxString arg = txtParser.GetWxStringUtf8();
				path = arg.BeforeLast('/');
				if (path.IsEmpty())
					path = wxT(".");
				mask = arg.AfterLast('/');
				if (mask.IsEmpty())
					mask = wxT("*");
			}
			wxDir dir(path);
			if (dir.IsOpened())
			{
				wxString filename;
				bool cont = dir.GetFirst(&filename, mask);
				while (cont)
				{
					LOG(filename);
					cont = dir.GetNext(&filename);
				}
			}
		}
		else if (commandName.IsSameAs(CMD_GETVIDEOMODES))
		{
#ifndef VRUT_HPC
			unsigned long displayID = 0;
			txtParser.GetWxString().ToULong(&displayID);
			wxDisplay display(displayID);
			wxArrayVideoModes videomodes = display.GetModes();
			wxString logStr(wxT("Display <") + display.GetName() + (display.IsPrimary()? wxT("> Primary\n") : wxT(">\n")));
			wxVideoMode currentMode = display.GetCurrentMode();
			logStr += wxString::Format(wxT("CurrentMode: %i %i %i %i\n"), currentMode.GetWidth(), currentMode.GetHeight(), currentMode.GetDepth(), currentMode.refresh);
			wxRect geometry = display.GetGeometry();
			logStr += wxString::Format(wxT("Geometry: %i %i %i %i\n"), geometry.GetX(), geometry.GetY(), geometry.GetWidth(), geometry.GetHeight());
			for (size_t i = 0; i < videomodes.size(); i++)
				logStr += wxString::Format(wxT("Mode: %i %i %i %i\n"), videomodes[i].GetWidth(), videomodes[i].GetHeight(), videomodes[i].GetDepth(), videomodes[i].refresh);
			LOG(logStr);
#endif
		}
		else if (commandName.IsSameAs(CMD_SETVIDEOMODE))
		{
#ifndef VRUT_HPC
			unsigned long displayID = 0, width = 0, height = 0, bpp = 0, refresh = 0;
			txtParser.GetWxString().ToULong(&displayID);
			txtParser.GetWxString().ToULong(&width);
			txtParser.GetWxString().ToULong(&height);
			txtParser.GetWxString().ToULong(&bpp);
			txtParser.GetWxString().ToULong(&refresh);
			wxVideoMode videomode(width, height, bpp, refresh);
			wxDisplay display(displayID);
			wxArrayVideoModes videomodes=display.GetModes(videomode);
			if (videomodes.size()>0)
			{
				display.ChangeMode(videomodes[0]);
				LOG(wxString::Format(wxT("Mode: %i %i %i %i"), videomodes[0].GetWidth(), videomodes[0].GetHeight(), videomodes[0].GetDepth(), videomodes[0].refresh));
			}
			else
			{
				LOGERROR(wxT("Video mode is not valid."));
				display.ChangeMode(videomode);
			}
#endif
		}
		else if (commandName.IsSameAs(CMD_SWITCHVIDEOOUTS))
		{
#ifndef VRUT_HPC
			//Note that this is very special function needed by Skoda auto.
			//It is proved to work on NVIDIA QUADRO FX 5600.
			//It switches output from one card output to another.
			//If you need to change this function or generalize it, please contact antonin.misek@skoda-auto.cz.
			//Note that wxWidgets 2.8.9 are lost when you attach/detach monitor, because it not expected such things.
			//After fixing and enhancing of the wxDisplay it should be deleted.
#ifdef __WINDOWS__
			unsigned long displayID = 0, width = 0, height = 0, bpp = 0, refresh = 0;
			txtParser.GetWxString().ToULong(&displayID);
			txtParser.GetWxString().ToULong(&width);
			txtParser.GetWxString().ToULong(&height);
			txtParser.GetWxString().ToULong(&bpp);
			txtParser.GetWxString().ToULong(&refresh);
			wxString origName, otherName;
/*			for (size_t i=0; i<wxDisplay::GetCount(); i++)
			{
				wxDisplay display(i);
				if (display.IsPrimary())
				{
					origName = display.GetName();
					if (origName==wxT("\\\\.\\DISPLAY1"))
						otherName = wxT("\\\\.\\DISPLAY2");
					else
						otherName = wxT("\\\\.\\DISPLAY1");
					break;
				}
			}*/
			origName=wxString::Format(wxT("\\\\.\\DISPLAY%i"), 2-displayID);
			otherName=wxString::Format(wxT("\\\\.\\DISPLAY%i"), displayID+1);
			LONG lStatus;
			//move primary display out of 0,0 which is reserved to primary display
			DEVMODE dm1;
			EnumDisplaySettings(origName.c_str(), ENUM_REGISTRY_SETTINGS, &dm1);
			dm1.dmFields = DM_POSITION;
			dm1.dmPosition.x = -(int)dm1.dmPelsWidth;
			dm1.dmPosition.y = 0;
			lStatus = ChangeDisplaySettingsEx (origName.c_str(), &dm1, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
			if (lStatus)
				LOGERROR(wxString::Format(wxT("ChangeDisplaySettingsEx 1: %i"), lStatus));
			lStatus = ChangeDisplaySettingsEx (NULL, NULL, NULL, 0, NULL);
			if (lStatus)
				LOGERROR(wxString::Format(wxT("ChangeDisplaySettingsEx 2: %i"), lStatus));

			//enable and set primary to the "another"
			DEVMODE dmode;
			memset(&dmode, 0, sizeof(DEVMODE));
			dmode.dmSize = sizeof(DEVMODE);
			dmode.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
			dmode.dmPelsWidth = width;
			dmode.dmPelsHeight = height;
			dmode.dmPosition.x = 0;
			dmode.dmPosition.y = 0;
			dmode.dmBitsPerPel = bpp;
			dmode.dmDisplayFrequency = refresh;
			lStatus = ChangeDisplaySettingsEx (otherName.c_str(), &dmode, NULL, CDS_SET_PRIMARY | CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
			if (lStatus)
				LOGERROR(wxString::Format(wxT("ChangeDisplaySettingsEx 3: %i"), lStatus));

			//disable the original output
			dm1.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
			dm1.dmPelsWidth = 0;
			dm1.dmPelsHeight = 0;
			dm1.dmPosition.x = 0;
			dm1.dmPosition.y = 0;
			lStatus = ChangeDisplaySettingsEx (origName.c_str(), &dm1, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
			if (lStatus)
				LOGERROR(wxString::Format(wxT("ChangeDisplaySettingsEx 4: %i"), lStatus));
			lStatus = ChangeDisplaySettingsEx (NULL, NULL, NULL, 0, NULL);
			if (lStatus)
				LOGERROR(wxString::Format(wxT("ChangeDisplaySettingsEx 5: %i"), lStatus));
#else
			LOGERROR(wxT("Not supported on Linux, I need it only on Windows, sorry."));
#endif
#endif //VRUT_HPC
		}
		else if (commandName.IsSameAs(CMD_CARDISPLAY))
		{
			wxString texturepath = txtParser.GetWxStringUtf8().MakeLower();
			unsigned long ratiox = 0, ratioy = 0;
			txtParser.GetWxString().ToULong(&ratiox);
			txtParser.GetWxString().ToULong(&ratioy);
			wxInitAllImageHandlers();
			wxImage image(texturepath);
			wxImage image_out(image.GetWidth()*(ratiox+1), image.GetHeight()*(ratioy+1));
			image_out.SetRGB(wxRect(0, 0, image.GetWidth()*(ratiox+1), image.GetHeight()*(ratioy+1)), 127, 127, 127);
			for (long i = 0; i<image.GetWidth(); i++)
			{
				for (long j = 0; j<image.GetHeight(); j++)
				{
					image_out.SetRGB(wxRect(i*(ratiox+1), j*(ratioy+1), ratiox, ratioy), image.GetRed(i,j), image.GetGreen(i,j), image.GetBlue(i,j));
				}
			}
			wxImage image_out1(image_out);
			unsigned char colors[8];
			for (long i = 0; i<image_out.GetWidth(); i++)
			{
				for (long j = 0; j<image_out.GetHeight(); j++)
				{
					if (image_out.GetRed(i,j)==127)
					{
						colors[0] = ((i>0) && (j>0))?image_out.GetRed(i-1,j-1):127;
						colors[1] = (j>0)?image_out.GetRed(i,j-1):127;
						colors[2] = ((i<image_out.GetWidth()-1) && (j>0))?image_out.GetRed(i+1,j-1):127;
						colors[3] = (i>0)?image_out.GetRed(i-1,j):127;
						colors[4] = (i<image_out.GetWidth()-1)?image_out.GetRed(i+1,j):127;
						colors[5] = ((i>0) && (j<image_out.GetHeight()-1))?image_out.GetRed(i-1,j+1):127;
						colors[6] = (j<image_out.GetHeight()-1)?image_out.GetRed(i,j+1):127;
						colors[7] = ((i<image_out.GetWidth()-1) && (j<image_out.GetHeight()-1))?image_out.GetRed(i+1,j+1):127;

						unsigned char color = 127;
						if (colors[1]!=127)
						{
							if (colors[1]==colors[6])
								color = 255-colors[1];
						}
						else
						{
							if (colors[3]!=127)
							{
								if (colors[3]==colors[4])
									color = 255-colors[3];
							}
							else
							{
								long tmpCol=0;
								int count=0;
								for (int k=0; k<8; k++)
								{
									if (colors[k]!=127)
									{
										tmpCol+=colors[k];
										count++;
									}
								}
								if (count>0)
									color=255-tmpCol/count;
							}
						}
						image_out1.SetRGB(i, j, color, color, color);
					}
				}
			}
			image_out1.SaveFile(texturepath+wxT("_new.png"));
			wxImage::CleanUpHandlers();

			//wxInitAllImageHandlers();
			/*wxImage image(2331, 2400);//left and right (must be flipped)
			for (size_t i=0; i<2331; ++i)
			{
				for (size_t j=0; j<2400; ++j)
				{
					if ((j%100==0) || (j==10) || (j==2399) || (i%100==0) || (i%100==j%100) || (i%100==(100-j%100)))
						image.SetRGB(i, j, 255, 255, 255);
				}
			}*/
			/*wxImage image(2337, 2400);//front (must be flipped and mirrored)
			for (size_t i=0; i<2337; ++i)
			{
				for (size_t j=0; j<2400; ++j)
				{
					if ((j%100==0) || (j==10) || (j==2399) || (i%100+==0) || (i%100==j%100) || (i%100==(100-j%100)))
						image.SetRGB(i, j, 255, 255, 255);
				}
			}*/
			/*wxImage image(2560, 2560);//bottom (must be rotated)
			for (size_t i=0; i<2560; ++i)
			{
				for (size_t j=0; j<2560; ++j)
				{
					float XtoMM = 6.0f+(i/2560.0f)*2200.0f;
					float Xgrid = 160.0f / 2560.0f * 2212.0f;
					float YtoMM = 6.0f + (j / 2560.0f)*2200.0f;
					float Ygrid = 160.0f / 2560.0f * 2206.0f;
					while (XtoMM > Xgrid)
						XtoMM -= Xgrid;
					while (YtoMM > Ygrid)
						YtoMM -= Ygrid;
					if ((std::abs(XtoMM)<1.0f) || (std::abs(YtoMM)<1.0f))
						image.SetRGB(i, j, 255, 255, 255);
				}
			}

			image.SaveFile(wxT("D:\\grid.png"));
			wxImage::CleanUpHandlers();*/
		}
		else if (commandName.IsSameAs(CMD_SHOWPANE))
		{
#ifndef VRUT_HPC
			wxString paneName = txtParser.GetWxStringUtf8();
			int paneID = -1;
			/*if (paneName.IsSameAs(wxT("Status"), false))
				paneID = ID_MainWin_View_Status;
			else*/
			if (paneName.IsSameAs(CONSOLE_NOTEBOOK_NAME, false))
				paneID = ID_MainWin_View_Console;
			else if (paneName.IsSameAs(LOG_NOTEBOOK_NAME, false))
				paneID = ID_MainWin_View_Log;
			else if (paneName.IsSameAs(RENDER_NOTEBOOK_NAME, false))
				paneID = ID_MainWin_View_RenderNotebook;
			else if (paneName.IsSameAs(PARAMS_NOTEBOOK_NAME, false))
				paneID = ID_MainWin_View_Parameters;
			if (paneID!=-1)
				KERNEL->GetMessageSink()->PostEvent(GET_EVT_GUI_PANE_SHOW(paneID, isTrue(txtParser.GetWxString())));
#endif
		}
		else if (commandName.IsSameAs(CMD_SHOWPARAM))
		{
			wxString paramName = txtParser.GetWxStringUtf8();
			Parameter::ParameterIdentifier pi(Parameter::ParameterIdentifier::FromParamName(paramName));
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_GUI_PARAM_SHOW(pi, isTrue(txtParser.GetWxString())));
		}
		else if (commandName.IsSameAs(CMD_ADAMSTODELTAGEN))
		{
			wxString adamsFile = txtParser.GetWxStringUtf8();
			wxFileName wxFname(adamsFile);
			if (wxFname.FileExists())
			{
				wxInputStream * sceneStream = new wxFileInputStream(wxFname.GetFullPath());
				TextParser textParser(sceneStream, 10000, 1000);
				bool newSection=false;
				size_t index=0;
				std::vector<std::vector<float> > values;
				while (!textParser.IsEmpty())
				{
					TextParser textParser1(textParser.GetWxLine().utf8_str());
					float tmp[10];
					size_t count=textParser1.ParseVector(tmp, 10, NULL, " \t");
					if (count>0)
					{
						if (newSection)
						{
							LOG(wxT("Start new section"));
							newSection=false;
							index=0;
						}
						if (values.size()<=index)
						{
							std::vector<float> row;
							values.push_back(row);
						}
						for (size_t i=0; i<count; i++)
							values.at(index).push_back(tmp[i]);
						index++;
					}
					else
						newSection=true;
				}
				//time
				wxFileName timename(adamsFile+wxT("_time.txt"));
				wxOutputStream * timeOS = new wxFileOutputStream(timename.GetFullPath());
				timeOS =new wxBufferedOutputStream(*timeOS);
				TextWriter timeTW((wxBufferedOutputStream*)timeOS);
				for (size_t i=0; i<values.size(); i++)
					timeTW.Write("\t\t")->Write((float)i/(values.size()-1))->Write("\r\n");
				timeOS->Sync();
				delete timeOS;
				//translation
				wxFileName tranname(adamsFile+wxT("_tran.txt"));
				wxOutputStream * tranOS = new wxFileOutputStream(tranname.GetFullPath());
				tranOS =new wxBufferedOutputStream(*tranOS);
				TextWriter tranTW((wxBufferedOutputStream*)tranOS);
				for (size_t i=0; i<values.size(); i++)
					tranTW.Write("\t\t")->Write(values.at(i).at(0))->Write(" ")->Write(values.at(i).at(1))->Write(" ")->Write(values.at(i).at(2))->Write(" ")->Write("\r\n");
				tranOS->Sync();
				delete tranOS;
				//rotation
				wxFileName rotname(adamsFile+wxT("_rot.txt"));
				wxOutputStream * rotOS = new wxFileOutputStream(rotname.GetFullPath());
				rotOS = new wxBufferedOutputStream(*rotOS);
				TextWriter rotTW((wxBufferedOutputStream*)rotOS);
				for (size_t i=0; i<values.size(); i++)
				{
					Matrix mm(Matrix::RotationZ(-values.at(i).at(3)/180*3.14159)*Matrix::RotationX(-values.at(i).at(4)/180*3.14159)*Matrix::RotationZ(-values.at(i).at(5)/180*3.14159));
					Vector3 axis;
					float angle;
					mm.ToAxisAngle(axis, angle);
					rotTW.Write("\t\t")->Write(axis.x)->Write(" ")->Write(axis.y)->Write(" ")->Write(axis.z)->Write(" ")->Write(angle)->Write(" \r\n");
				}
				rotOS->Sync();
				delete rotOS;
			}
			else
				LOGERROR(wxT("<AdamsToDeltaGen>File '") + adamsFile + wxT("' not found"));
		}
		else if (commandName.IsSameAs(CMD_HELP))
		{
			std::vector<wxString> commands;
			for (CommandEntries::const_iterator cmd = commandEntries.begin(); cmd != commandEntries.end(); ++cmd)
				commands.push_back(getUsageString(cmd));
			std::sort(commands.begin(), commands.end());
			wxString tmpLog(wxT("Available commands:\n"));
			for (auto &command : commands)
				tmpLog += command + wxT("\n");
			LOG(tmpLog);

/*
			class EventMain : public Event {};
			class EventMainTest : public Event {int i;};
			class EventMainTest2 : public EventMain {int i;};
			LOG(wxString::Format(wxT("sizeof(Event)=%i"), sizeof(Event)));
			LOG(wxString::Format(wxT("sizeof(EventMain)=%i"), sizeof(EventMain)));
			LOG(wxString::Format(wxT("sizeof(EventMainTest)=%i"), sizeof(EventMainTest)));
			LOG(wxString::Format(wxT("sizeof(EventMainTest2)=%i"), sizeof(EventMainTest2)));
*/
/*
			Vector3 aa(2, 0, 0);
			Vector3 ba(2, 0, 0);
			__m128 a;
			__m128 b;
			Vector3 cb;
			float result[4];
			wxULongLong start=VRUTGetTime();
			for (size_t i = 0; i < 100000000; ++i)
			{
				a=_mm_setr_ps(aa.x, aa.y, aa.z, 0);
				b=_mm_setr_ps(ba.x, ba.y, ba.z, 0);
				//a=CrossProductTest(a, b);
				//__m128 c=_mm_sub_ps(
				//	_mm_mul_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)), _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2))),
				//	_mm_mul_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)), _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)))   );
				//_mm_storeu_ps(result, c);
				//memcpy(cb._v, result, 12);
				////cb=Vector3(result);
				result[0]=DotProductTest(a, b);
			}
			wxULongLong start1=VRUTGetTime();
			for (size_t i = 0; i < 100000000; ++i)
				cb=aa.Dot(ba);
			wxULongLong end=VRUTGetTime();
			Vector3 ca(result);
			LOG(wxT("Dot SSE=")+ca.ToString()+wxT(" normal=")+cb.ToString());
			LOG(wxT("Dot SSE=")+(start1-start).ToString()+wxT(" C++=")+(end-start1).ToString());
*/			
			/*
			wxMutex mmm;
			wxCriticalSection ccc;
			volatile unsigned int atomic;
			EventQueue tmpQueue2;
			wxULongLong mstart=VRUTGetTime();
			for (size_t i = 0; i < 1000000; ++i)
			{
				mmm.Lock();
				mmm.Unlock();
			}
			wxULongLong cstart=VRUTGetTime();
			for (size_t i = 0; i < 1000000; ++i)
			{
				ccc.Enter();
				ccc.Leave();
			}
			wxULongLong cend=VRUTGetTime();
			for (size_t i = 0; i < 1000000; ++i)
			{
				wxAtomicInc((wxUint32 &)atomic);
			}
			wxULongLong aend=VRUTGetTime();
			for (size_t i = 0; i < 1000000; ++i)
			{
				Event *ev=new Event();
				tmpQueue2.Post(ev);
			}
			wxULongLong q2end1=VRUTGetTime();
			for (size_t i = 0; i < 1000000; ++i)
			{
				Event *ev=tmpQueue2.ReceiveTimeout(1000);
				delete ev;
			}
			wxULongLong q2end2=VRUTGetTime();
			LOG(wxT("wxMutex time=")+(cstart-mstart).ToString()+wxT(" wxCriticalSection time=")+(cend-cstart).ToString()+wxT(" wxAtomicInc time=")+(aend-cend).ToString()
				+wxT(" tmpQueue2.Post time=")+(q2end1-aend).ToString()+wxT(" tmpQueue2.ReceiveTimeout time=")+(q2end2-q2end1).ToString());
			//*/

			/*wxFileSystem::AddHandler(new wxMemoryFSHandler);
			//wxMemoryFSHandler::AddFile("logo.png", wxBITMAP(logo), wxBITMAP_TYPE_PNG);
			wxMemoryFSHandler::AddFile("about.htm", "<html><body>About: <img src=\"memory:logo.png\"></body></html>");
			wxDialog dlg(NULL, -1, wxString(wxT("About")));
			wxBoxSizer *topsizer;
			topsizer = new wxBoxSizer(wxVERTICAL);
#define USE_WEBVIEW
#ifdef USE_WEBVIEW
			wxWebView* browser = wxWebView::New(&dlg, wxID_ANY, wxWebViewDefaultURLStr, wxDefaultPosition, wxSize(380, 160));
			//browser->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
			//browser->LoadURL("memory:about.htm");
			browser->LoadURL("file://C:/data/Tonda/vrut/trunk/documents/Plan_vyvoje.html");
			//browser->LoadURL("http://soutez.ristorante.cz/");
			//browser->SetPage(wxT("<!DOCTYPE html><html><body style=\"background-color:rgba(0,0,0,0.5);\"><font style=\"background-color:rgba(10,10,10,0.5);color:rgb(255,0,0);\">�erven�</font></body></html>"), wxT(""));
#else // Use wxHtml
			wxHtmlWindow *browser;
			browser = new wxHtmlWindow(&dlg, -1, wxDefaultPosition, wxSize(380, 160), wxHW_SCROLLBAR_NEVER);
			browser->SetBorders(0);
			browser->LoadPage("memory:about.htm");
			browser->SetSize(browser->GetInternalRepresentation()->GetWidth(), browser->GetInternalRepresentation()->GetHeight());
#endif
			topsizer->Add(browser, 1, wxALL, 10);
			topsizer->Add(new wxStaticLine(&dlg, -1), 0, wxEXPAND | wxLEFT | wxRIGHT, 10);
			topsizer->Add(new wxButton(&dlg, wxID_OK, "Ok"), 0, wxALL | wxALIGN_RIGHT, 15);
			dlg.SetAutoLayout(true);
			dlg.SetSizer(topsizer);
			topsizer->Fit(&dlg);
			dlg.Centre();
			dlg.ShowModal();
			//wxMemoryFSHandler::RemoveFile("logo.png");
			wxMemoryFSHandler::RemoveFile("about.htm");//*/

			/*wxBitmap bitmap(100, 100);
			if (!bitmap.IsOk())
				return false;
			wxMemoryDC mem_dc(bitmap);
			if (!mem_dc.IsOk())
				return false;
			wxHtmlDCRenderer htmlRenderer;
			htmlRenderer.SetDC(&mem_dc, 1);
			htmlRenderer.SetSize(100,100);
			htmlRenderer.SetHtmlText(wxT("<html><body style=\"background-color: red\"><p>text</p></body></html>"));
			wxArrayInt known_pagebreaks; 
			int y=htmlRenderer.Render(0,0, known_pagebreaks);
			//bitmap.SaveFile(wxT("d:\\html.bmp"), wxBITMAP_TYPE_BMP);
			wxImage im(bitmap.ConvertToImage());
			//im.SaveFile(wxT("d:\\htmlIM.png"), wxBITMAP_TYPE_PNG);
			/*wxAlphaPixelData apdata(bitmap);
			wxAlphaPixelData::Iterator p(apdata);
			wxImage image(100, 100);
			image.InitAlpha();
			for ( int y = 0; y < 100; ++y )
			{
				for ( int x = 0; x < 100; ++x)
				{
					p.MoveTo(apdata, x,y);
					image.SetRGB(x, y, p.Red(), p.Green(), p.Blue());
					image.SetAlpha(x, y, 255-p.Alpha());
				}
			}
			image.SaveFile(wxT("d:\\html.png"), wxBITMAP_TYPE_PNG);//*/
			/*wxImage image(bitmap.ConvertToImage());
			if (!image.HasAlpha())
				image.InitAlpha();
			for (size_t i = 0; i < image.GetHeight(); ++i)
			{
				for (size_t j = 0; j < image.GetWidth(); ++j)
				{
					if ((image.GetRed(i,j)==0) && (image.GetGreen(i,j)==0) && (image.GetBlue(i,j)==0))
						image.SetAlpha(i,j, 0);
				}
			}
			image.Rescale(100, 100, wxIMAGE_QUALITY_BICUBIC);
			image.SaveFile(wxT("d:\\html.png"), wxBITMAP_TYPE_PNG);//*/
		}
#if USE_SCRIPT_THREAD
		else if (commandName.IsSameAs(CMD_WAIT))
		{
			// Wait for a given amount of time before continuing processing of
			// the script
			// Intended for use from the script
			// be careful when using from the console - currently it freezes the
			// whole application for the specified amount of time
			// this will partially change when events will be processed in their
			// own thread (main thread and the GUI will not get freezed)
			long argL = 0;
			if (txtParser.ParseLong(&argL) && argL>0)
			{
				LOG(wxString::Format(wxT("<Interpreter>Waiting %li ms"), argL));
				wxThread::Sleep(argL);
			}
		}
#endif
		else if (commandName.IsSameAs(CMD_BIN2C))
		{
			wxString filename = txtParser.GetWxStringUtf8();
			wxFileName fname(filename);
			if (!fname.FileExists())
			{
				LOGERROR(wxT("<Interpreter>bin2c '") + filename + wxT("' not found"));
				return false;
			}
			wxFileInputStream is(fname.GetFullPath());
			if (!is.IsOk())
				return false;
			wxFileOutputStream os(fname.GetFullPath()+wxT(".h"));
			if (!os.IsOk())
				return false;
			TextParser textParser(&is, 10000, 1);
			os.Write("static const unsigned char ", strlen("static const unsigned char "));
			filename=fname.GetFullName();
			filename.Replace(wxT("."), wxT("_"));
			os.Write(filename.char_str(), filename.size());
			wxString bytesCount(wxString::Format(wxT("[%lu]={"), (unsigned long)is.GetSize()));
			os.Write(bytesCount.char_str(), bytesCount.size());
			int count=0;
			bool comma=false;
			while (!textParser.IsEmpty(NULL, false))
			{
				if (comma)
					os.Write(", ", 2);
				else
					comma=true;
				if (((count++)%25)==0)
					os.Write("\n", 1);
				os.Write(wxString::Format(wxT("0x%.2x"), (unsigned char)textParser.GetChar(NULL, false)).char_str(), 4);
			}

			os.Write("};\n", 3);
			os.Sync();
		}
		else if (commandName.IsSameAs(CMD_RUNONCLIENT))
		{
			wxString nodeName = txtParser.GetWxStringUtf8();
			if (nodeName.Lower() != wxGetHostName().Lower())
				return false;
			ProcessCommand(txtParser.GetWxStringUtf8());
		}
	}

	return true;
}


bool Interpreter::ExecuteScriptFile(const wxString & scriptFileName)
{
#if USE_SCRIPT_THREAD
	bool noerr = true;
	if (scriptThread == NULL) {
		scriptThread = new ScriptThread(*this);
		if (scriptThread->Create() == wxTHREAD_NO_ERROR) 
			noerr = (scriptThread->Run() == wxTHREAD_NO_ERROR);
		else
			noerr = false;
	}
	if (noerr)
		scriptThread->ProcessFile(scriptFileName);
	else {
		delete scriptThread;
		scriptThread = NULL;
		return false;
	}
	return true;
#else
	wxFileInputStream scriptFile(scriptFileName);
	if (scriptFile.IsOk())
	{
		wxTextInputStream scriptText(scriptFile);
		while (!scriptFile.Eof())
			ProcessCommand(scriptText.ReadLine());

		return true;
	}
	return false;
#endif
}

wxThread::ExitCode ScriptThread::Entry()
{
	interpreter.scriptThreadIsRunning=true;
	while (!TestDestroy()) {
		ScriptFilenameQueueNode *fileNameNode = scriptFileNames.ReceiveTimeout(1000);
		if (fileNameNode)
		{
			wxFileInputStream scriptFile(fileNameNode->fileName);
			delete fileNameNode;
			if (scriptFile.IsOk()) {
				wxTextInputStream scriptText(scriptFile);
				while (!scriptFile.Eof()) {
					if (KERNEL->IsExiting())
						return 0;// exit asap
					interpreter.ProcessCommand(scriptText.ReadLine());
				}
			}
		}
	}
	interpreter.scriptThreadIsRunning=false;
	return 0;
}
