#ifndef EXEC_DEF
 #define EXEC_DEF


//------------ EXECUTER & Base Poliz Elem Module  ---------------//
//						  v 15 . 04 .  2007						 //
//																 //
//								MT								 //
//---------------------------------------------------------------//

//--- Classes
class CVar;
class CRun;
class CExecuter;
class PolizElem;
//=== Classes


//---------------------- Incudes 
#include "stdio.h"
#include "ctype.h"
#include "strings.h"
#include "../../ui/onerror.hpp"
#include "stack.hpp"

#include "../robot/data.hpp"
#include "../robot/robot.hpp"
//====================== Includes


//---------------------- Defines
#define VT_VAR_NOT_FOUND  "Var not found in VarTable."
#define VT_VAR_ARRAY_BOUND  "Array bound corrupted. "
//====================== Defines


//------------------------------- Base POLIZ --------------------------
//--- Main Poliz Element ---
class PolizElem {
protected:
	CExecuter *exe;

	void Push(PolizElem *e);
	PolizElem *Pop();

public:
	PolizElem() { exe=NULL; };
	PolizElem(CExecuter *e) { exe=e; };
	virtual ~PolizElem() {};

	virtual void Evaluate() = 0;
	virtual void Evaluate_main(CExecuter *e)
	{
		exe=e;
		Evaluate();
	};
};


/* Throw */ 
class PolizEx { 
protected:
	PolizElem *addr; 
public:
	PolizEx() { };
	PolizEx(PolizElem *cur) { addr=cur; };
	virtual PolizElem* GetAddr() { return addr; };
	virtual ~PolizEx() {};
};


class PolizExConst : public PolizEx {
public: 	
	PolizExConst(PolizElem *cur) { addr=cur; };
};

class PolizExNotInt : public PolizEx {
public: 	
	PolizExNotInt(PolizElem *cur) { addr=cur; };
};


class PolizExNotStr : public PolizEx {
public: 	
	PolizExNotStr(PolizElem *cur) { addr=cur; };
};
class PolizExNotLabel : public PolizEx {
public: 	
	PolizExNotLabel(PolizElem *cur) { addr=cur; };
};


class PolizExWrongAddr : public PolizEx {
public: 	
	PolizExWrongAddr(PolizElem *cur) { addr=cur; };
};


class PolizExWrongMacros : public PolizEx {
public: 	
	PolizExWrongMacros(PolizElem *cur) { addr=cur; };
};


//=======//

//--- Poliz Item ---
class PolizItem {
	friend class CExecuter;	
	friend class CRun;	
protected : 
	PolizItem  *next;
	PolizElem  *p; 
public : 
	inline PolizItem() { next = NULL; p = NULL; };
	inline PolizItem(PolizElem *tmp) {  next=NULL; p=tmp; };
	~PolizItem() { };

	void inline Assign(PolizElem *tmp) { p = tmp; };
};


//------------------------------- Executer ----------------------------
//--- CVar ---
class CVar {
private :
	char *name;
	int *value;
	int count;

private:

	bool TestN (int n, bool top=true)
	{
		if (top) if (n<count && n>=0) return true; 
		if (!top) if (n>=0) return true; 
		
		throw VT_VAR_ARRAY_BOUND; 
	};

public :
	CVar () { name = NULL; value = new int[1]; value[0]=0; count=1; };
	CVar (char *str, int i, int n=0) { SetName(str); SetValue(i,n); }; 
	~CVar () {}; 

	//--- Functions
	void inline  SetName(char *str) { name = strdup(str); };

	void inline  SetValue(int i, int n=0) 
	{ 
		int old_count=count;
		TestN(n, false);
		if (count < n+1) {
			count = n+1;

			int *tmp = new int [count];
			for (int j=0; j<old_count; j++)
				tmp[j]=value[j];
			for (int j=old_count; j<count-1; j++)
				tmp[j]=0;
			tmp[n]=i;

			delete[] value;
			value=tmp;
		};
		if (count >= n+1) { value[n] = i; }
	};

	void inline  Set(char *str, int i, int n=0) { SetName(str); SetValue(i, n); };

	bool inline  IsNameEq(char *str) { return (strcmp(name, str) == 0); }; 

	int  inline  GetValue(int n=0) { TestN(n);	return value[n]; };
	
	char inline  *GetName() { return name; };
	int inline  *GetValueAddr() { return value; };
	int inline  GetCount() { return count; };
};


//--- CExecuter ---
class CExecuter {
	friend class CRun;
public : 
	//--- Variables Table ---
	class CVarTable {
	private :
		CVar  *var;
		int  c;

	public :
		CVarTable() { var=NULL; c=0; };
		~CVarTable() { 
			for (int i=0; i<c; i++) {
				delete[] var[i].GetName(); 
				delete[] var[i].GetValueAddr(); 
			}
			delete[] var; 
		};

		int inline Add(char *name, int val=0, int n=0) 
		{
			//--- test: is such var existed?
			for (int i=0; i<c; i++)
				if (var[i].IsNameEq(name))
					return i;

			//--- adding
			c++;
			CVar *v = new CVar[c];
			for (int i=0; i<c-1; i++) 
				v[i] = var[i];
			v[c-1].Set(name, val, n);
			delete[] var;

			var = v;
			
			return -1;
		};

		void inline SetVar(char *name, int val=0, int n=0)
		{
			int i = Add(name, val, n);
			if (i == -1) return;
			var[i].SetValue(val, n); 
		}

		int  inline GetVar(char *name, int n=0) 
		{
			for (int i=0; i<c; i++)
				if (var[i].IsNameEq(name))
					return var[i].GetValue(n);

			throw VT_VAR_NOT_FOUND;
			return 0;
		};

		void inline Print()
		{
			printf("\n");	
			for (int i=0; i<c; i++)
			{
				if (var[i].GetCount()==1) 
					printf(" %s = %d; ", 
						var[i].GetName(), var[i].GetValue());
				else
					for (int j=0; j<var[i].GetCount(); j++)
						printf(" %s[%d] = %d; ", 
							var[i].GetName(), j, var[i].GetValue(j));
				printf("\n");
			}
		};
	};

//======================

private :
	CError  Error;
	CData  *Data;
	CVarTable  VarTable;

	PolizItem  *begin, *cur;
	unsigned int cur_num;

	CStack <PolizItem>  stack;
	int flag_debug;
public : 
	CRobot  *Robot;
	
public :
	//--- Constructor 
	CExecuter (CData *d, CRobot *r) 
	{ 
		SetData(d); SetRobot(r); 
		begin=NULL; cur=NULL; 
		flag_debug=-1; cur_num = 1;		
	};

	//--- Debug
	void SetDebugMode(int m) { flag_debug = m; };
	bool Debug(char *s1, char *s2=NULL) 
		{ if (flag_debug==1) printf(s1,s2); return flag_debug==1; };
	//--- Show Error
	void ShowError(const char *str, char *str2 = NULL);
	//--- Get Data *
	inline CData* GetData() { return Data; };

	//--- Set PolizItem (next)
	unsigned int SetCur(unsigned int i, bool next);
	inline unsigned int GetCurNum() const { return cur_num; }
	PolizItem *GetCur() { return cur; }
	

	//--- Robot Data ---
	void SetData(CData *d) { Data = d; };
	void SetRobot(CRobot *r) { Robot = r; };
	int inline GetDataInt
		(char *name1, char *name2=NULL, int n=-1)
			{ return Data->Get(name1, name2, n); };

	//--- Variable Table	
	int GetVar(char *str, int n=0);
	void SetVar(char *name, int val=0, int n=0);


	//--- Stack <PolizElem> --- 
	void Push(PolizElem *e);
	PolizElem* Pop();
	bool IsStackEmpty() { 
		if (stack.IsEmpty())
			Debug("Stack Empty \n");
		return stack.IsEmpty(); 
	}

	//--- P.O.L.I.Z.
	PolizItem *GetCurCmd() { return cur; };

	//--- Destructor
	~CExecuter();
};




#endif




