#ifndef SEM_DEF
 #define SEM_DEF


//-------------------- SEMANTIC ANALYZER Module -----------------//
//						  v 15 . 04 .  2007						 //
//																 //
//								MT								 //
//---------------------------------------------------------------//


//---------------------- Incudes 
#include "stdio.h"
#include "ctype.h"
#include "strings.h"

#include "../../ui/onerror.hpp"

#include "../robot/robot.hpp"

#include "exec.hpp"
//====================== Includes

//---------------------- Defines
#define MACRO_YourProd	"\"YouProd\""
#define MACRO_YourFab	"\"YouFab\""
#define MACRO_AllProd	"\"AllProd\""
#define MACRO_AllRaw	"\"AllRaw\""
#define MACRO_AllEffect	"\"AllEffect\"" 
#define MACRO_Online	"\"Online\""
#define MACRO_OptiBuy	"\"OptiBuy\"" 
#define MACRO_OptiProd	"\"OptiProd\""


#define MACRO_Mmax_prod_price	"\".market.max_prod_price\""
#define MACRO_Mmin_raw_price	"\".market.min_raw_price\""
#define MACRO_Mraw				"\".market.raw\""
#define MACRO_Mprod				"\".market.prod\""

#define MACRO_YouRaw			"\".you.raw\""
#define MACRO_YouProd			"\".you.prod\""
#define MACRO_YouAuto			"\".you.auto\""
#define MACRO_YouFabrics		"\".you.fabrics\""
#define MACRO_YouMoney			"\".you.money\""


//====================== Defines

//--- Classes --- 

//--- Poliz Constants ---
template <class T> 
class PolizConst : public PolizElem {
protected:
	T val;
public:
	PolizConst(T a) { val = a; };
	virtual ~PolizConst() {};

	virtual PolizElem* Clone() const { return new PolizConst(val); };
	T inline Get() const { return val; };

	virtual void  Evaluate()
	{ 
		Push(Clone());
		exe->Debug(" Const pushed -> ");
	};
};

typedef PolizConst<int> PolizConstInt;
typedef PolizConst<char*> PolizConstStr;
typedef PolizConst<unsigned int> PolizConstVarAddr;
typedef PolizConst<PolizItem*> PolizConstLabel;
/* === */ 

//--- Poliz Functions ---
class PolizFunc : public PolizElem {
protected : 
	virtual PolizElem* PopTest()=0;
	virtual inline PolizElem* PopTestInt() {
		PolizElem *operand = Pop();
		PolizConstInt *i=dynamic_cast<PolizConstInt*>(operand);
		if(i==NULL) { throw PolizExNotInt(operand); } 
		return i;
	};

	virtual inline PolizElem* PopTestStr() {
		PolizElem *operand = Pop();
		PolizConstStr *i=dynamic_cast<PolizConstStr*>(operand);
		if(i==NULL) { throw PolizExNotStr(operand); } 
		return i;
	};

	virtual inline PolizElem* PopTestLabel() {
		PolizElem *operand = Pop();
		PolizConstLabel *i=dynamic_cast<PolizConstLabel*>(operand);
		if(i==NULL) { throw PolizExNotLabel(operand); } 
		return i;
	};
	
public :
	virtual PolizElem *EvaluateFunc() = 0;
	virtual void Evaluate()
	{
		exe->Debug(" EvaluateFunc -> ");
		PolizElem *res = EvaluateFunc();
		if (res!=NULL) Push(res);
	};
};

//--- Poliz Functions In Expression --- 
//--- Poliz Functions +*/% --- 
class PolizFuncPlus : public PolizFunc {
protected :
	virtual PolizElem* PopTest() 
	{
		return PopTestInt();
	}


	virtual int Operate(int o1, int o2) {
		exe->Debug("|+|");
		return o1 + o2;
	}
public :
	virtual PolizElem *EvaluateFunc()
	{
		PolizConstInt *i1, *i2;
		exe->Debug(" Oper-Pop1 -> ");
		i1 = (PolizConstInt*) PopTest();
		exe->Debug(" Oper-Pop2 -> ");
		i2 = (PolizConstInt*) PopTest();
		int res = Operate(i1->Get(), i2->Get());
		delete i1;
		delete i2;
		return new PolizConstInt(res);
	};
};

class PolizFuncMinus : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		exe->Debug("|---|");
		return o2-o1;
	};
};

class PolizFuncMult : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		exe->Debug("|*|");
		return o1*o2;
	};
};

class PolizFuncDiv : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		exe->Debug("|/|");
		if (o1!=0) return (int) ((int)o2 /(int)o1);
		else return 0;
	};
};

class PolizFuncMod : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		exe->Debug("|%|");
		return o1%o2;
	};
};

//--- Poliz Functions !- ---
class PolizFuncPriMinus : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) 
		{ exe->Debug("|-|"); return -o1; };
public:
	virtual PolizElem *EvaluateFunc()
	{
		PolizConstInt *i1;
		exe->Debug(" FuncOperMinus::PopTest operand 1 -> ");
		i1 = (PolizConstInt*) PopTest();
		int res = Operate(i1->Get(), 0);
		delete i1;
		
		return new PolizConstInt(res);
	};
};

class PolizFuncWow : public PolizFuncPriMinus {
protected: 
	virtual int Operate(int o1, int o2) 
		{ exe->Debug("|!|"); return !o1; };
};


//--- Poliz Functions & | < > == ---
class PolizFuncAnd : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		return o1 & o2;
	};
};

class PolizFuncOr : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		return o1 | o2;
	};
};

class PolizFuncLower : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		return o1 > o2;
	};
};

class PolizFuncHigher : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		return o1 < o2;
	};
};

class PolizFuncEq : public PolizFuncPlus {
protected: 
	virtual int Operate(int o1, int o2) {
		return o1 == o2;
	};
};


//--- Poliz Function Var Read/Write --- 
class PolizFuncVar : public PolizFunc {
protected: 
	char *s;

protected: 
	virtual PolizElem* PopTest() 
	{
		exe->Debug("FuncVar[%s] ->", s);
		PolizElem *operand = Pop();
		PolizConstInt *i=dynamic_cast<PolizConstInt*>(operand);
		if(i==NULL) { throw PolizExNotInt(operand); } 
		return i;
	}

	virtual void ReadStack() {
		
		PolizConstInt *red = (PolizConstInt*) PopTest();
		exe->SetVar(s, red->Get());
		delete red;
	};
};

class PolizFuncVarRead : public PolizFuncVar {
public:
	PolizFuncVarRead(char *str) { s=str; };
	virtual PolizElem *EvaluateFunc() {
		ReadStack();
		exe->Debug("VTWriteVar[%s] ->", s);
		return NULL;
	};
};

class PolizFuncVarWrite : public PolizFuncVar {
public:
	PolizFuncVarWrite(char *str) { s=str; };
	virtual PolizElem *EvaluateFunc() {
		exe->Debug("VTReadVar[%s] ->", s);
		return new PolizConstInt(exe->GetVar(s));
	};
};

//--- Poliz Function Var Array Read/Write --- 
class PolizFuncVarArrayRead : public PolizFuncVar {
protected: 
	int n, val;
public:
	PolizFuncVarArrayRead(char *str) { s=str; };
	
	virtual PolizElem *EvaluateFunc() {
		n=0; val=0;
		exe->Debug("VTWriteArray[%s] ->", s);

		PolizConstInt *red = (PolizConstInt*) PopTest();
		val = red->Get();
		delete red;
		
		red = (PolizConstInt*) PopTest();
		n = red->Get();
		delete red;

		exe->SetVar(s, val, n);

		return NULL;
	};
};

class PolizFuncVarArrayWrite : public PolizFuncVar {
public:
	PolizFuncVarArrayWrite(char *str) { s=str; };
	virtual PolizElem *EvaluateFunc() {
		exe->Debug("VTReadArray[%s] ->", s);
		PolizConstInt *p = (PolizConstInt*) PopTest();
		int n = p->Get();
		delete p;
		return new PolizConstInt(exe->GetVar(s, n));
	};
};
//--- Poliz Function Robot Read/Write --- 
class PolizFuncRoboWrite : public PolizFunc {
protected: 
	char *s1, *s2;
	int n;
	char typ;

	virtual PolizElem* PopTest()
		{ 
			return PopTestInt();
		};
public:
	PolizFuncRoboWrite(char *s_1, char *s_2, char t) 
		{ s1=s_1; s2=s_2; n=0; typ=t; };

	virtual PolizElem *EvaluateFunc() 
	{
		if (typ==3) {
			PolizConstInt *p_int
				= dynamic_cast<PolizConstInt*>(PopTest());
			if (!p_int) throw PolizExNotInt(this);
			n = p_int->Get();
			delete p_int;
		}
		
		exe->Debug(" RData::s1(%s) -> ", s1);
		if (s2!=NULL) exe->Debug(" RData::s2(%s) -> ", s2);
		
		return new PolizConstInt(exe->GetDataInt(s1,s2,n));
	};
};


//--- Poliz Label Write in VT ---
class PolizFuncLabelRead : public PolizFuncVar {
protected : 
	unsigned int label;
public:
	PolizFuncLabelRead(char *str) { s=str; };
	virtual PolizElem *EvaluateFunc() {return NULL;};
	virtual void Evaluate() {
		label = exe->GetCurNum();
		exe->SetVar(s, label);
		exe->Debug("VTWriteLabel[%s] ->", s);
	};
};


/* === */ 

//--- Poliz Functions For Robot --- 
class PolizFuncRob : public PolizFunc {
protected :
	virtual PolizConstInt* PopTest() 
	{
		return (PolizConstInt*) PopTestInt();
	}

public :
	PolizFuncRob() { };
};

class PolizFuncRobTurn : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		exe->Robot->Turn();
		return NULL;
	};
};

class PolizFuncRobUpgrade : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		exe->Robot->Upgrade();
		return NULL;
	};
};

class PolizFuncRobAuto : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		exe->Robot->Upgrade();
		return NULL;
	};
};

class PolizFuncRobPlant : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		exe->Robot->Plant();
		return NULL;
	};
};


class PolizFuncRobABuild : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		exe->Robot->ABuild();
		return NULL;
	};
};


class PolizFuncRobProd : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		PolizConstInt *i1;
		i1 = PopTest();
		exe->Robot->Prod(i1->Get());
		delete i1;
		return NULL;
	};
};

class PolizFuncRobSell : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		PolizConstInt *i1, *i2;
		i1 = PopTest();
		i2 = PopTest();
		exe->Robot->Sell(i2->Get(),i1->Get());
		delete i1;
		delete i2;
		return NULL;
	};
};


class PolizFuncRobBuy : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		PolizConstInt *i1, *i2;
		i1 = PopTest();
		i2 = PopTest();
		exe->Robot->Buy(i2->Get(), i1->Get());
		delete i1;
		delete i2;
		return NULL;
	};
};

class PolizFuncRobPrint : public PolizFuncRob {
public :
	virtual PolizElem *EvaluateFunc()
	{
		printf("	~Robot said: ");

		PolizConstStr *s1;
		s1 = (PolizConstStr*)PopTestStr();
		char *s = s1->Get();
		delete s1;

		unsigned int i = 0;
		int c=0;
		for (i=0; i<strlen(s); i++)
			if (strncmp("%d", &s[i], 2)==0)
				c++;

		if (c==0) printf(s);
		else {
			if (c==1) {
				PolizConstInt *i1;
				i1 = PopTest();
				printf(s,i1->Get());
				delete i1;
			}
			if (c==2) {
				PolizConstInt *i1;
				i1 = PopTest();
				PolizConstInt *i2;
				i2 = PopTest();
				printf(s,i2->Get(), i1->Get());
				delete i1;
				delete i2;
			}
		}
		
		printf("\n");
		
		return NULL;
	};
};
class PolizFuncRobMacros : public PolizFuncRob {
public : 
	char *name;
public :
	PolizFuncRobMacros(char *s) { name = s; };
	virtual PolizElem *EvaluateFunc()
	{
		exe->Debug(" Macros '%s' -> ", name);
		int res = 0;
		CData *Data = exe->GetData();
		//--- Max prod
		if (strcmp(name, MACRO_YourProd)==0)
			res = exe->Robot->MaxProducing(Data->you); else
		if (strcmp(name, MACRO_YourFab)==0)
			res = exe->Robot->Fabrics(Data->you); else
		//--- All prod
		if (strcmp(name, MACRO_AllProd)==0)
			res = exe->Robot->GetAllPlayers_Prod(); else
		//--- All raw
		if (strcmp(name, MACRO_AllRaw)==0)
			res = exe->Robot->GetAllPlayers_Raw(); else
		//--- All effectivity
		if (strcmp(name, MACRO_AllEffect)==0)
			res = exe->Robot->GetAllPlayers_Producing(); else
		//--- Get living players
		if (strcmp(name, MACRO_Online)==0)
			res = exe->Robot->GetPlayingGamers(); else
		//--- Get optimal buy
		if (strcmp(name, MACRO_OptiBuy)==0)
			res = exe->Robot->GetPlayerOptimalBuyN(Data->you);else
		//--- Get optimal prod
		if (strcmp(name, MACRO_OptiProd)==0)
			res = exe->Robot->GetPlayerOptimalProdN(Data->you); else

		//--- DATA ---
		if (strcmp(name, MACRO_YouRaw)==0)
			res = Data->you.raw; else
		if (strcmp(name, MACRO_YouFabrics)==0)
			res = Data->you.fabrics; else
		if (strcmp(name, MACRO_YouMoney)==0)
			res = Data->you.money; else
		if (strcmp(name, MACRO_YouProd)==0)
			res = Data->you.prod; else
		if (strcmp(name, MACRO_YouAuto)==0)
			res = Data->you.auto_plants; else

		if (strcmp(name, MACRO_Mmax_prod_price)==0)
			res = Data->market.max_prod_price; else
		if (strcmp(name, MACRO_Mmin_raw_price)==0)
			res = Data->market.min_raw_price; else
		if (strcmp(name, MACRO_Mraw)==0)
			res = Data->market.raw; else
		if (strcmp(name, MACRO_Mprod)==0)
			res = Data->market.prod; else
		//--- --- ---
			throw PolizExWrongMacros(this);
						
		return new PolizConstInt(res);
	};
};

/* === */ 

//--- Poliz Passages --- 
class PolizFuncPass : public PolizElem {
protected : 
	char *label;

protected : 
	
	virtual inline PolizElem* PopTestInt() {
		PolizElem *operand = Pop();
		PolizConstInt *i=dynamic_cast<PolizConstInt*>(operand);
		if(i==NULL) { throw PolizExNotInt(operand); } 
		return i;
	};

	virtual inline PolizElem* PopTestStr() {
		PolizElem *operand = Pop();
		PolizConstStr *i=dynamic_cast<PolizConstStr*>(operand);
		if(i==NULL) { throw PolizExNotStr(operand); } 
		return i;
	};

	virtual inline PolizElem* PopTestLabel() {
		PolizElem *operand = Pop();
		PolizConstLabel *i=dynamic_cast<PolizConstLabel*>(operand);
		if(i==NULL) { throw PolizExNotLabel(operand); } 
		return i;
	};

	virtual PolizElem* PopTest() 
		{ return PopTestLabel(); };

public :
	virtual unsigned int EvaluatePass() = 0;
	virtual void Evaluate()
	{
		exe->Debug(" Passage -> ");
		unsigned int res = EvaluatePass();
		if (res>0) 
			exe->SetCur(res,false);
		if (res==0) throw PolizExWrongAddr(this);
	};
};

class PolizFuncPassGo : public PolizFuncPass {
public :
	PolizFuncPassGo(char *str) { label=str; };
	virtual unsigned int EvaluatePass()
	{
		return exe->GetVar(label);
	};
};

class PolizFuncPassIf : public PolizFuncPass {
protected :
	char* label_else;
public :
	PolizFuncPassIf(char *str1, char *str2) { label=str1; label_else=str2; };
	~PolizFuncPassIf() { delete[] label; }
	virtual unsigned int EvaluatePass()
	{
		PolizConstInt *p = (PolizConstInt*) PopTestInt();
		int exp = p->Get();
		delete p;
		 
		unsigned int res;
		if (exp) res = exe->GetCurNum()+1;
		else { 
			res = exe->GetVar(label_else);
			if (res==0) res = exe->GetVar(label);
			exe->Debug(" goto %s", label);
		};
		
		return res;
	};
};

/* === */ 


//--- POLIZ END ----


//--- CRun ---
class CRun {
	CExecuter *exe;
	bool collected;

public:
	CRun(CExecuter *e) { exe=e; collected = false; };
	
	void LabelCollect();
	void Execute();
	void AddElem(PolizElem *elem);
	void Debug(char *s1, char *s2=NULL);
};



#endif

