#include <set>
#include <algorithm>
#include <string>
#include <map>
#include <iostream>
#include <iterator>
using namespace std;

typedef enum {BROJ, SKUP} TIP;

class Skup;
class Broj;

//Apstraktna klasa vrednost predstavlja vrednosti promenljivih
class Vrednost
{
public:
	//Realizacija operacija se realizuje intenzivnim koriscenjem 
	//polimorfizma  i virtuelnog mehanizma. 

 
		//Sabiranje
	
	// Sabiranje dve vrednosti
	virtual Vrednost* Plus (Vrednost* v) = 0;

	// Sabiranje vrednosti sa datim skupom
	virtual Vrednost* PlusSkup(Skup* s) = 0;

	// Sabiranje vrednosti sa datim brojem
	virtual Vrednost* PlusBroj(Broj* b) = 0;


		//Mnozenje


	// Mnozenje dve vrednosti
	virtual Vrednost* Puta (Vrednost* v) = 0;

	// Mnozenje vrednosti i skupa
	virtual Vrednost* PutaSkup(Skup* s) = 0;

	// Mnozenje vrednosti i broja
	virtual Vrednost* PutaBroj(Broj* b) = 0;

	// Pravi identicnu kopiju objekta vrednosti
	virtual Vrednost* Clone() = 0;
	
	// Ispisuje vrednost u dati tok
	virtual void Print(ostream& ostr) = 0;
}; 


// Klasa broj predstavlja brojevne vrednosti promenjivih
class Broj : public Vrednost
{
	// vrednost broja
	int _broj;
public:
	
	Broj(int br)
	: _broj(br)
	{}

	// vraca brojnu vrednost
	int GetBroj()
	{ 	return _broj; }

	
	Vrednost* Plus(Vrednost* v);
	Vrednost* PlusSkup(Skup* s);
	Vrednost* PlusBroj(Broj* b);

	Vrednost* Puta(Vrednost* v);
	Vrednost* PutaSkup(Skup* s);
	Vrednost* PutaBroj(Broj* b);

	virtual Vrednost* Clone()
	{	return new Broj(*this);		}

	void Print(ostream& ostr)
	{
		ostr<<_broj;
	}
	

};

// Klasa predstavlja vrednosti promenjivih skupovnog tipa
class Skup  : public Vrednost
{
	set<int>* _skup;
public:
	Skup()
	: _skup(new set<int>())
	{}

	Skup(set<int>* s)
	: _skup(s)
	{}

	Skup(const Skup& s)
		_skup(new set<int>(*s._skup))
	{}

	~Skup()
	{	delete _skup; 	}

	Vrednost* Plus (Vrednost* v);
	Vrednost* PlusSkup(Skup* s);
	Vrednost* PlusBroj(Broj* b);


	Vrednost* Puta(Vrednost* v);
	Vrednost* PutaSkup(Skup* s);
	Vrednost* PutaBroj(Broj* b);

	virtual Vrednost* Clone()
	{	
		return new Skup(*this);
	}

	void Print(ostream& ostr)
	{
		ostr<<'{';
		copy(_skup->begin(), _skup->end(), ostream_iterator<int>(ostr, " "));
		ostr<<'}';
	}
};
