#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;	
}