#ifndef __FORMULA_H__
#define __FORMULA_H__

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

#include "relacija.h"
extern map<string, Relacija*> relacije;

class Formula {
 public:
    virtual ~Formula() {}
    virtual bool vrednost() = 0;
};

class Atom : public Formula {
 public:
    Atom(const string& ime, const vector<int>& argumenti) 
	: _imeRelacije(ime), _argumenti(argumenti) {
    }

    virtual bool vrednost() {
	return (relacije[_imeRelacije])->uRelaciji(_argumenti);
    }
 private:
    string _imeRelacije;
    vector<int> _argumenti;
};

class BinarniOperator : public Formula {
 protected:
    BinarniOperator(Formula* op1, Formula* op2) 
	: _op1(op1), _op2(op2) {
    }
    
    ~BinarniOperator() {
	delete _op1;
	delete _op2;
    }
    
    virtual bool vrednost() {
	return primeniOperator(_op1->vrednost(), _op2->vrednost());
    }

    virtual bool primeniOperator(bool v1, bool v2) = 0;

 private:
    Formula *_op1, *_op2;
};

class Disjunkcija : public BinarniOperator {
 public:
    Disjunkcija(Formula* f1, Formula* f2) 
	: BinarniOperator(f1, f2) 
	{}
    virtual bool primeniOperator(bool v1, bool v2) {
	return v1 || v2;
    }
};

class Konjunkcija : public BinarniOperator {
 public:
    Konjunkcija(Formula* f1, Formula* f2) 
	: BinarniOperator(f1, f2) 
	{}
    virtual bool primeniOperator(bool v1, bool v2) {
	return v1 && v2;
    }
};

class Implikacija : public BinarniOperator {
 public:
    Implikacija(Formula* f1, Formula* f2) 
	: BinarniOperator(f1, f2) 
	{}
    virtual bool primeniOperator(bool v1, bool v2) {
	return (!v1) || v2;
    }
};

class Negacija : public Formula {
 public:
    Negacija(Formula* op) 
	: _op(op) {
    }

    ~Negacija() {
	delete _op;
    }

    virtual bool vrednost() {
	return !_op->vrednost();
    }
 private:
    Formula *_op;
};
#endif
