/*
 * $Id: interpreter.h 4270 2016-11-06 11:02:47Z 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 __INTERPRETER_H__
#define __INTERPRETER_H__

#include "msgqueue.h"
#include <vector>
#include <wx/hashmap.h>
#include <wx/string.h>


namespace VRUT
{
	class ScriptThread;

///Command interpreter
	class Interpreter
	{
	protected:
		///Command entry argument types
		enum ARG_TYPE
		{
			ARG_STRING,
			ARG_INT,
			ARG_UNSIGNED,
			ARG_FLOAT,
			ARG_BOOL
		};

		///Interpreter command's argument structure
		struct Argument
		{
			wxString name;
			ARG_TYPE type;
			bool mandatory;

			Argument(wxString _name, ARG_TYPE _type, bool _mandatory) : name(_name), type(_type), mandatory(_mandatory)  {}
		};
		typedef std::vector<Argument> ArgList;
		WX_DECLARE_STRING_HASH_MAP(ArgList, CommandEntries);

		///Hash map with command entries
		CommandEntries commandEntries;

		///Get usage string from given command entry
		wxString getUsageString(CommandEntries::const_iterator cmdEntry) const;

		ScriptThread *scriptThread;

	public:
		bool scriptThreadIsRunning;

		///Class constructor
		Interpreter();
		///Class destructor
		virtual ~Interpreter();

		///Get commands starting with given string (case insensitive)
		///\param[in] cmdPart Starting part of command string
		///\param[out] cmdList To be filled with commands' usage whose names start with \c cmdPart
		///\return \c Number of commands found
		size_t GetCommandsStarting(const wxString & cmdPart, std::vector<wxString> * cmdList) const;

		/// Get files staring with the given prefix
		size_t GetFilesStarting(const wxString & filePart, std::vector<wxString> * fileList) const;

		/// Get modules staring with the given prefix
		size_t GetModulesStarting(const wxString & filePart, std::vector<wxString> * moduleList) const;

		///Check syntax of given command
		bool CheckSyntax(const wxString & cmd) const;
		///Process command
		///\param[in] cmd Command string
		///\return \c false if empty, \c true otherwise even for bad command
		bool ProcessCommand(const wxString & cmd);
		///Process all commands in a script file
		///\param[in] scriptFileName Path to script file
		///\return \c false if script file not found
		bool ExecuteScriptFile(const wxString & scriptFileName);
	};


	class ScriptThread : public wxThread
	{
		wxCriticalSection mutex;
		Interpreter &interpreter;
		class ScriptFilenameQueueNode : public MPMC_QueueNode
		{
		public:
			wxString fileName;
			ScriptFilenameQueueNode(const wxString &fileName) : MPMC_QueueNode(), fileName(fileName) {}
		};
		MPMC_Queue<ScriptFilenameQueueNode> scriptFileNames;

	public:
		ScriptThread(Interpreter &interpreter) : wxThread(wxTHREAD_DETACHED), interpreter(interpreter) {}

		virtual ExitCode Entry();

		void ProcessFile(const wxString & scriptFileName) {
			wxCriticalSectionLocker lock(mutex);
			scriptFileNames.Post(new ScriptFilenameQueueNode(scriptFileName));
		}
	};
}

#endif
