#ifndef __FUNCTION_H__
#define __FUNCTION_H__

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

class SynTreeNode;

// Klasa kojom se predstavlja funkcija programskog jezika
// U okviru ove klase, napravljen je i registar kreiranih funkcija koji 
// omogucava da se definisanoj funkciji pristupi na osnovu imena
class Function
{
public:
    // Konstruktor na osnovu imena, argumenata, imena rezultujuce promenljive i sintaksnog stabla 
    // koje predstavlja kod same funkcije
    // Prilikom konstrukcije, funkcija se upisuje u registar
    Function(const string& name, const vector<string>& args, const string result, SynTreeNode* code)
    	: _args(args), _result(result), _code(code)
    {
    	map<string, Function*>::iterator i = _functions.find(name);
    	if (i!=_functions.end())
    		throw "Function redefinition";
 
    	// Upis funkcije u registar
    	_functions[name] = this;
    }
    
    // Destruktor
    ~Function();
    
    // Metod kojim se vrsi poziv funkcije sa datim imenom za date 
    // vrednosti argumenata
    static int Call(const string& name, const vector<int>& values)
    {
    	// Pronalazimo odgovarajucu funkciju u registru
    	Function* f = GetFunction(name);
    	// Proveravamo da li funkcija postoji
    	if (f == 0)
    		throw "Undefined function called";
    	// Pozivamo funkciju
	return f->Call(values);
    }

    
    // Staticki metod koji uklanja sve funkcije iz registra
    static void DeleteFunctions()
    {	map<string, Function*>::iterator i;
    	for (i = _functions.begin(); i!=_functions.end(); i++)
    		delete i->second;
    }

private:
    // Kod koji vrsi poziv ove funkcije sa datim vrednostima argumenata
    int Call(const vector<int>& values);

    // Staticki metod kojim se iz registra funkcija pronalazi 
    // funkcija sa datim imenom
    static Function* GetFunction(const std::string& name)
    {	
    	map<string, Function*>::iterator i = _functions.find(name);
    	return i==_functions.end() ? 0 : i->second;	
    }


    // Imena ulaznih promenljivih funkcije
    vector<string> _args;
    
    // Ime rezultujuce promenljive
    string _result;
    
    // Sintaksno stablo za predstavljanje koda funkcije
    SynTreeNode* _code;
    
    // Globalni registar funkcija
    static map<string, Function*>  _functions;
};

#endif

