    #include <iostream>
    #include <string>
    #include <stdlib>
    #include "BazaPodataka.h"
    using namespace std;

    class EncPodatak
    {
    public:
    	EncPodatak( const Podatak& pod )
    		: _Id( AtributInt(pod,"id") ),
    		  _Naslov( Atribut( pod, "naslov") ),
    		  _Autor( Atribut( pod, "autor") )
    		{}

    	virtual ~EncPodatak()
    		{}

    	void Prikazi( ostream& ostr ) const
    		{
    		ostr << endl;
    		PrikaziNaslov( ostr );
    		PrikaziTekst( ostr );
    		PrikaziDetalje( ostr );
    		ostr << endl;
    		PrikaziAutora( ostr );
    		ostr << endl;
    		PrikaziPovezane( ostr );
    		ostr << endl;
    		}

    	static EncPodatak* ProcitajPodatakIzBazePodataka( int id );

    	virtual string Tip() const = 0;

    protected:
    	void PrikaziNaslov( ostream& ostr ) const
    		{
    		ostr << _Naslov << endl;
    		ostr << "---------------------------------" << endl;
    		}

    	void PrikaziAutora( ostream& ostr ) const
    		{ ostr << _Autor << endl; }

    	void PrikaziPovezane( ostream& ostr ) const
    		{
    		vector<int> povezani;
    		BazaPodataka::ProcitajPovezane( _Id, povezani );
    		if( povezani.empty() )
    			ostr << "Nema povezanih podataka." << endl;
    		else{
    			ostr << "Povezani podaci:" << endl;
    			map<string,int> naslovi;
    			for( unsigned i=0; i<povezani.size(); i++ ){
    				EncPodatak* p =
    					ProcitajPodatakIzBazePodataka( povezani[i] );
    				if( p )
    					naslovi[p->_Naslov + " (" + p->Tip()] = p->_Id;
    				delete p;
    				}
    			for( map<string,int>::iterator i=naslovi.begin(); i!=naslovi.end(); i++ )
    				ostr << i->first << " " << i->second << ")" << endl;
    			}
    		}

    	virtual void PrikaziTekst( ostream& ostr ) const = 0;
    	virtual void PrikaziDetalje( ostream& ostr ) const = 0;

    	static string Atribut( const Podatak& p, const string& s )
    		{
    		Podatak::const_iterator f = p.find(s);
    		return f != p.end() ? f->second : string();
    		}

    	static int AtributInt( const Podatak& p, const string& s )
    		{
    		string a = Atribut( p, s );
    		return atoi( a.c_str() );
    		}

    	static int AtributDouble( const Podatak& p, const string& s )
    		{
    		string a = Atribut( p, s );
    		return atof( a.c_str() );
    		}

    private:
    	int 	_Id;
    	string 	_Naslov;
    	string 	_Autor;
    };

    class EncTekst : public EncPodatak
    {
    public:
    	EncTekst( const Podatak& p )
    		: EncPodatak(p),
    		  _Tekst( Atribut( p, "tekst"))
    		{}

    	string Tip() const
    		{ return "tekst"; }

    protected:
    	void PrikaziTekst( ostream& ostr ) const
    		{ ostr << _Tekst << endl; }
    	void PrikaziDetalje( ostream& ostr ) const
    		{}

    private:
    	string _Tekst;
    };

    class EncBinarni : public EncPodatak
    {
    public:
    	EncBinarni( const Podatak& p )
    		: EncPodatak(p),
    		  _Napomena( Atribut( p, "napomena"))
    		{}

    protected:
    	void PrikaziTekst( ostream& ostr ) const
    		{ ostr << _Napomena << endl; }

    private:
    	string _Napomena;
    };

    class EncSlika : public EncBinarni
    {
    public:
    	EncSlika( const Podatak& p )
    		: EncBinarni(p),
    		  _Sirina( AtributInt( p, "sirina")),
    		  _Visina( AtributInt( p, "visina")),
    		  _Slika( Atribut( p, "slika"))
    		{}

    	string Tip() const
    		{ return "slika"; }

    protected:
    	void PrikaziDetalje( ostream& ostr ) const
    		{
    		ostr << "Sirina: " << _Sirina << endl;
    		ostr << "Visina: " << _Visina << endl;
    		}

    private:
    	int 	_Sirina;
    	int 	_Visina;
    	string	_Slika;
    };

    class EncZvuk : public EncBinarni
    {
    public:
    	EncZvuk( const Podatak& p )
    		: EncBinarni(p),
    		  _Trajanje( AtributDouble( p, "trajanje")),
    		  _Zvuk( Atribut( p, "zvuk"))
    		{}

    	string Tip() const
    		{ return "zvuk"; }

    protected:
    	void PrikaziDetalje( ostream& ostr ) const
    		{
    		ostr << "Trajanje: " << _Trajanje << "s" << endl;
    		}

    private:
    	double 	_Trajanje;
    	string	_Zvuk;
    };

    class EncFilm : public EncBinarni
    {
    public:
    	EncFilm( const Podatak& p )
    		: EncBinarni(p),
    		  _Sirina( AtributInt( p, "sirina")),
    		  _Visina( AtributInt( p, "visina")),
    		  _Trajanje( AtributDouble( p, "trajanje")),
    		  _Film( Atribut( p, "film"))
    		{}

    	string Tip() const
    		{ return "film"; }

    protected:
    	void PrikaziDetalje( ostream& ostr ) const
    		{
    		ostr << "Sirina: " << _Sirina << endl;
    		ostr << "Visina: " << _Visina << endl;
    		ostr << "Trajanje: " << _Trajanje << "s" << endl;
    		}

    private:
    	int 	_Sirina;
    	int 	_Visina;
    	double 	_Trajanje;
    	string	_Film;
    };

    EncPodatak* EncPodatak::ProcitajPodatakIzBazePodataka( int id )
    {
    	Podatak podatak;
    	string tip;
    	EncPodatak* obj = 0;
    	if( BazaPodataka::ProcitajPodatak( id, podatak, tip ) ){
    		if( tip == "tekst" )
    			obj = new EncTekst(podatak);
    		else if( tip == "slika" )
    			obj = new EncSlika(podatak);
    		else if( tip == "zvuk" )
    			obj = new EncZvuk(podatak);
    		else if( tip == "film" )
    			obj = new EncFilm(podatak);
    		}

    	return obj;
    }

    main( int argc, char** argv )
    {
    	EncPodatak* p =
    		EncPodatak::ProcitajPodatakIzBazePodataka(
    			atoi(argv[1])
    			);
    	if( p )
    		p->Prikazi( cout );
    	delete p;
    	return 0;
    }