#ifndef __PROGRAM_H__
#define __PROGRAM_H__

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

class Statement;

/**
 *  Klasa predstavlja BASIC program. Program se sastoji od niza naredbi. 
 *  Pored samog programa, klasa cuva podatke o stanju izvrsavanja programa.
 *  Ovo ukljucuje broj tekuce naredbe koja se izvrsava i vrednosti promenljvih.
 */
class Program {
 public:
    ~Program();

    /**
     *  Metoda kojom se pokrece izvrsavanje programa
     */ 
    void run();

    /**
     *  Metoda kojom se definise naredba sa datim brojem
     */
    void addStatement(int number, Statement* statement) {
	_statements[number] = statement;
    }

    /**
     *  Metoda koja vraca naredbu sa datim brojem, odnosno 0 ukoliko takva naredba
     *  nije definisana
     */
    Statement* getStatement(int number) {
	    map<int, Statement*>::const_iterator i = _statements.find(number);
	    return i != _statements.end() ? i->second : 0;
    }

    /**
     *   Metoda kojom se prenosi kontrola izvrsavanja na liniju sa datim brojem
     */
    void Goto(int number) {
	_lineNumber = number;
    }

    /**
     *   Metoda kojom se prenosi kontrola izvrsavanja na sledecu liniju
     */
    void nextStatement() {
	      map<int, Statement*>::const_iterator i = _statements.find(_lineNumber);
	      i++;
	      _lineNumber = i->first;	
    }

    /**
     *   Pronalazi broj linije uz prvu liniju programa
     */
    int getMinStatementNumber() {
	return _statements.begin()->first;
    }

    /** 
     *   Vraca broj linije prve for naredbe cija je promenljiva iteracija jednaka
     *   datoj promenljivoj, a koja prethodni liniji koja se trenutno izvrsava.
     */
    int getForStatementNumber(string var);


    /**
     *   Postavlja vrednost promenljive
     */
    void setStringVar(string var, string value) {
	string_vars[var] = value;
    }

    /**
     *   Ocitava vrednost promenljive
     */
    string getStringVar(string var) {
	    map<string, string>::const_iterator i =
	  	string_vars.find(var);
	    return (i != string_vars.end()) ? i->second : "";
    }

    /**
     *   Postavlja vrednost promenljive
     */
    void setIntVar(string var, int value) {
	int_vars[var] = value;
    }

    /**
     *   Ocitava vrednost promenljive
     */
    int getIntVar(string var) {
	    map<string, int>::const_iterator i =
	  	int_vars.find(var);
	    return (i != int_vars.end()) ? i->second : 0;
    }

 private:
    /**
     *   Program je predstavljen preslikavanjem brojeva linija u naredbe
     */
    map<int, Statement*> _statements;

    /**
     *   Broj linije koja se trenutno izvrsava
     */
    int _lineNumber;

    /**
     *   String promenljive
     */
    map<string, string> string_vars;

    /**
     *   Int promenljive
     */
    map<string, int>    int_vars;
};

#endif
