#ifndef __IZRAZI_H_
#define __IZRAZI_H_

#include <map>
#include <vector>
using namespace std;

#include "funkcija.h"

class Izraz {
public:
	virtual ~Izraz() {}
	virtual int Vrednost(const map<string, int>& promenljive) = 0;

protected:
};

class Konstanta : public Izraz {
public:
	Konstanta(int vr) 
		: vr_(vr) {
	}

	virtual int Vrednost(const map<string, int>& promenljive) {
		return vr_;
	}
	
protected:
	int vr_;
};

class Promenljiva : public Izraz {
public:
	Promenljiva(string ime)
		: ime_(ime) {
	}

	virtual int Vrednost(const map<string, int>& promenljive) {
		map<string, int>::const_iterator i = promenljive.find(ime_);
		return i != promenljive.end() ? i->second : 0;
	}

protected:
	string ime_;
};

class Operator : public Izraz {
public:
	Operator(Izraz* op1, Izraz* op2)
		: op1_(op1), op2_(op2) {
	}

	~Operator() {
		delete op1_;
		delete op2_;
	}

	virtual int Vrednost(const map<string, int>& promenljive) {
		return operacija(op1_->Vrednost(promenljive),
			         op2_->Vrednost(promenljive));
	}

protected:
	virtual int operacija(int o1, int o2) = 0;

	Izraz *op1_, *op2_;
};

class Plus : public Operator {
public:
	Plus(Izraz* op1, Izraz* op2)
		: Operator(op1, op2) {
	}

	virtual int operacija(int o1, int o2) {
		return o1 + o2;
	}
};

class Puta : public Operator {
public:
	Puta(Izraz* op1, Izraz* op2)
		: Operator(op1, op2) {
	}

	virtual int operacija(int o1, int o2) {
		return o1 * o2;
	}
};

class Minus : public Operator {
public:
	Minus(Izraz* op1, Izraz* op2)
		: Operator(op1, op2) {
	}

	virtual int operacija(int o1, int o2) {
		return o1 - o2;
	}
};

class Jednako : public Operator {
public:
	Jednako(Izraz* op1, Izraz* op2)
		: Operator(op1, op2) {
	}

	virtual int operacija(int o1, int o2) {
		return o1 == o2;
	}
};

class Manje : public Operator {
public:
	Manje(Izraz* op1, Izraz* op2)
		: Operator(op1, op2) {
	}

	virtual int operacija(int o1, int o2) {
		return o1 < o2;
	}
};


class IfThenElse : public Izraz {
public:
	IfThenElse(Izraz* op1, Izraz* op2, Izraz* op3)
	 : op1_(op1), op2_(op2), op3_(op3) {
	}

	~IfThenElse() {
		delete op1_;
		delete op2_;
		delete op3_;
	}

	virtual int Vrednost(const map<string, int>& promenljive) {
		return op1_->Vrednost(promenljive) ? 
			op2_->Vrednost(promenljive) :
			op3_->Vrednost(promenljive);
	}
private:
	Izraz *op1_, *op2_, *op3_;
};


class PozivFunkcije : public Izraz {
public:
	PozivFunkcije(const string& ime, vector<Izraz*>* parametri)
		: ime_(ime), parametri_(parametri) {
	}

	virtual int Vrednost(const map<string, int>& promenljive) {
		vector<int> vrednosti(parametri_->size());
		for (size_t i = 0; i < parametri_->size(); i++)
			vrednosti[i] = (*parametri_)[i]->Vrednost(promenljive);
		return Funkcija::Pozovi(ime_, vrednosti);
	}

protected:
	string ime_;
	vector<Izraz*>* parametri_;
};

#endif
