<?

/*
 * Modele, warstwa logiczna
 * 
 */
 
 /**
 * @file model.php 
 * @author Damian Świstowski <dswistowski@gery.firma.pl>
 * @brief plik zawierający modele
 * 
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
 * 
 * W pliku tym znajduje się klasy odpowiedzialne za pobieranie i udostępnianie danych.
 */
 
 
 /**
  * @brief Klasa modelu, z niej dziedziczą wszystkie modele
  * 
  * W tej klasie znajduje się kod wspólny dla wszystkich modeli, czyli pobieranie, cachowanie, tworzenie kluczy obcych itp
  * Klasa zawiera kilka magicznych pól, które należy zdefiniować przy tworzeniu podklasy:
  * <ul>
  * 	<li>model -- nazwa modelu, używana do odczytywania opcji z configu</li>
  * 	<li>klucze_obce -- tablica postaci: ,,nazwa_klucza'' => {'model'=>nazwa_powiązanego_modelu, 'pole'=>pole_zawierające_klucz_obcy}, pole to dodaje do klasy metodę nazwa_klucza(), która to pobiera obiekt powiązanego modelu</li>
  * 	<li>nie_zamieniaj -- przy ustawieniu na true informuje o tym że dane obiektu nie są xml, więc pobierany obiekt modelu nie jest parsowany do xml'a.</li>
  * </ul>
  * 
  */
abstract class model
{
	protected $dane = null;
	protected $pobrane = false;
	protected $nie_zamieniaj = false;
	protected $klucze_obce = array();
	protected $limit = '';
	private $pobrane_klucze_obce = array();
	
	public function __construct(adcentral $adcentral)
	{
		$this->adcentral = $adcentral;
		$this->opcje  = $adcentral->opcjeModelu($this->model);
		$this->waznosc = $this->opcje['waznosc'];
	}
	
	/**
	 * @brief pobranie obiektu modelu
	 * 
	 * Metoda pobiera obiekt modelu, za cachowanie odpowiada backend. Gdy nie pamiętany jest żaden obiekt w backendzie zawsze pobierany jest nowy obiekt z serwera adcentral.
	 * @param $id id obiektu do pobrania
	 */
	public function pobierz($id)
	{
	  if(!$this->pobrane)
	  {	
		$be = $this->adcentral->pobierzBackend();
		$this->id = $id;
		$dane = $be->pobierz($this->model, $id, $this->waznosc);
		if(!$dane)
		{
			if($this->nie_zamieniaj)
			{
				$url = 'http://'.$this->adcentral->getSerwerUrl().$this->opcje['url'].$id;
				
				$dane = file_get_contents($url);
			}
			else
			{
				$fetcher = $this->adcentral->getFetcher();
				$fetcher->wyslijGet('/xml/'.$this->opcje['url'].$id.'/'.$this->limit);
			
				$dane = $fetcher->ostatniaTresc();
			}
			$be->zapisz($this->model, $id, $dane);
		}
		if($this->nie_zamieniaj)
			$this->dane = $dane;
		else
			$this->dane = simplexml_load_string($dane);
		$this->pobrane = true;
	  }
	}

	/**
	 * @brief magiczne pola
	 * 
	 * Metoda odpowiada za pobieranie magicznych pól, jeżeli model posiada klucz obcy o nazwie pola,
	 * zwracany jest obiekt połączony z tym kluczem obcym, 
	 * jeżeli natomiast pobrane dane posiadają pole o takiej nazwie zwracana jest wartość tego pola.
	 *  
	 */
	public function __get($nazwa)
	{
		if(array_key_exists($nazwa, $this->klucze_obce))
		{
			if(!isset($this->pobrane_klucze_obce[$nazwa]))
			{
				$opis =  $this->klucze_obce[$nazwa];
				
				$model = new $opis['model']($this->adcentral);
				if(!is_subclass_of($model, 'model'))
					throw new Exception('Klucz obcy powinien wskazywać na model');
				$model->pobierz($this->$opis['pole']);
				$this->pobrane_klucze_obce[$nazwa] = $model;
			}
			return $this->pobrane_klucze_obce[$nazwa];
		};
		if($this->dane)
			return $this->dane->$nazwa;
		else
			return array();
	}	
	

}

/**
 * @brief model ogłoszeń użytkownika
 * 
 * Model ten służy do pobierania wszystkich ogłoszeń użytkownika
 * @see model
 */
class ogloszenia_uzytkownika extends model
{
	protected $model = 'ogloszenia_uzytkownika';
	protected $limit = 1000000;
	protected $klucze_obce = array(
		'uzytkownik'=>array('model'=>'uzytkownik','pole'=>'id')
	);
		
	/**
	 * @brief metoda zwraca link do ogłoszeń użytkownika na serwerze adcentral
	 * 
	 * Link do strony z ogłoszeniami użytkownika na serwerze adcentral.
	 */
	public function link()
	{
		$url = 'http://'.$this->adcentral->getSerwerUrl().'lu/'.$this->id;
		return $url;
	}
}

/**
 * @brief model ogłoszeń kategorii
 * 
 * Model ten służy do pobierania wszystkich ogłoszeń z wybranej kategorii.
 * 
 * Posiada następujące pola:
 * <ul>
 * 	<li>kategoria -- klucz obcy do modelu kategoria</li>
 *  <li>item -- zbiór ogłoszeń kategorii o polach:</li>
 * 	<ul>
 * 		<li>id -- id ogłoszenia</li>
 * 		<li>naglowek -- nagłowek ogłoszenia</li>
 * 		<li>data_dodania -- data dodania ogłoszenia</li>
 * 		<li>data_waznosci -- data ważności ogłoszenia</li>
 * 		<li>rodzaj -- kod literowy rodzaju ogłoszenia</li>
 *  </ul>
 * </ul>
 * @see model
 */
class ogloszenia_kategorii extends model
{
	protected $model = 'ogloszenia_kategorii';
	protected $limit = 1000000;
	protected $klucze_obce = array(
		'kategoria'=>array('model'=>'kategoria','pole'=>'id')
	);
	
	/**
	 * @brief metoda zwraca link do ogłoszeń kategorii na serwerze adcentral
	 * 
	 * Link do strony z ogłoszeniami kategorii na serwerze adcentral.
	 */
	public function link()
	{
		$url = 'http://'.$this->adcentral->getSerwerUrl().'lk/'.$this->id;
		return $url;
	}

	public function pobierz($id)
	{
		parent::pobierz($id);
	}
	
}

/***
 * @brief model kategorii
 * 
 * Model ten służy do pobierania informacji o podanej kategorii
 * 
 * Posiada następujące pola:
 * <ul>
 * 		<li>nazwa -- nazwa kategorii</li>
 * 		<li>rodzic -- klucz obcy do rodzica tej kategorii</li>
 * 		<li>opis_kategorii -- klucz obcy do modelu opis_kategorii</li>
 * 		<li>lisc -- jeżeli zawiera ,,T'' oznacza, że kategoria nie ma podkategorii</li>
 * 		<li>pod_kategorie.item -- zbiór podkategorii tej kategorii o polach:</li>
 * 		<ul>
 * 			<li>id -- id podkategorii</li>
 * 			<li>nazwa -- nazwa podkategorii</li>
 * 		</ul> 
 * </ul>
 * @see model
 */
class kategoria extends model
{
	protected $model = 'kategoria';	
	protected $opis = false;
	
	protected $klucze_obce = array(
		'opis_kategorii'=>array('model'=>'opis_kategorii','pole'=>'id'),
		'rodzic'=>array('model'=>'kategoria','pole'=>'dzial_id')
	);

	/**
	 * @brief generowanie linku do ogłoszenia kateogrii
	 * 
	 * Generuje i zwraca lokalny link do ogłoszenia kategorii
	 * 
	 * @return link do ogłoszenia kategorii 
	 */
	public function link_ogloszenia_kategorii()
	{
		if($this->adcentral->config->kontroler['ogloszenia_kategorii'])
			return $this->adcentral->config->bazowy_url.'?'.$this->adcentral->config->kontroler['ogloszenia_kategorii'].'='. (int) $this->id;
		else
			return $this->adcentral->config->bazowy_url;
	}
	
	public function pobierz($id)
	{
	 	if($id!='-1')
	 		parent::pobierz($id);
	 	else
	 		$this->dane = array();
	}
	
}

/***
 * @brief model opisu kategorii
 * 
 * Model ten służy do pobierania opisu pól kategorii
 * 
 * Posiada następujące pola:
 * <ul>
 * 		<li>id -- id opisywanej kategorii</li>
 * 		<li>dzial_id -- numer nadkategorii </li>
 *      <li>nazwa -- nazwa kategorii</li>
 * 		<li>item -- zbiór opisów dodatkowych pól do ogłoszeń kategorii o polach:</li>
 * 		<ul>
 * 			<li>nazwa -- nazwa pola</li>
 * 			<li>opis -- czytelny opis pola</li>
 * 			<li>typ -- typ danych przechowywanych przez pole</li>
 * 			<li>wymagane -- zawiera ,,T'' jeżeli pole jest wymagane</li>
 * 		</ul>
 * </ul>
 * @see model
 */
class opis_kategorii extends model
{
	protected $model = 'opis_kategorii';	
	protected $opis = false;
	
}

/***
 * @brief model ogłoszenia
 * 
 * Model ten służy do pobierania ogłoszenia
 * 
 * Posiada następujące pola:
 * <ul>
 * 	<li>id -- id ogłoszenia</li>
 * 	<li>dzial_id -- id kategorii do której należy ogłoszenie</li>
 *  <li>naglowek -- nagłowek ogłoszenia</li>
 *  <li>opis -- opis ogłoszenia</li>
 *  <li>rodzaj -- kod rodzaju</li>
 *  <li>cena -- cena wystawianego przedmiotu</li>
 *  <li>forma_sprzedazy -- kod formy sprzedazy: ,,o'' - ogłoszenie jest zwykłym ogłoszeniem; ,,p'' - ogłoszenie jest produktem w sklepie</li>
 *  <li>data_dodania -- data dodanie ogłoszenia<li>
 *  <li>data_waznosci -- data, do której ogłoszenie jest ważne</li>
 *  <li>szczegoly -- pola definiujące pola specyficzne dla wybranej kategorii</li>
 * </ul>
 * @see model
 */
class ogloszenie extends model
{
	protected $model = 'ogloszenie';	
	protected $pobrana_kategoria = false;
	
	protected $klucze_obce = array(
		'kategoria'=>array('model'=>'kategoria','pole'=>'dzial_id'),
		'uzytkownik'=>array('model'=>'uzytkownik','pole'=>'user_id'),		
	);
	
	/**
	 * Link do ogłoszenia na serwerze adcentral
	 */
	public function link()
	{
		$url = 'http://'.$this->adcentral->getSerwerUrl().'p/'.$this->id;
		return $url;
	}
	
	
	
	/**
	 * @brief tworzy listę zdjęć ogłoszenia
	 * 
	 * Tworzy listę id zdjęć ogłoszeń, dzieki temu że model ogłoszeń nie jest xml, link do niego nie jest przetwarzany \
	 * przez silnik templatów i powoduje wyświetlanie ogłoszeń to samo id ogłoszenia wystarcza do wyświetalnia go.
	 */
	public function zdjecia_ogloszenia()
	{
		foreach($this->zdjecia->item as $zdjecie)
			$ret[] = array('id'=> array_shift(explode('.',(array_pop(explode('/', $zdjecie))))));
		return $ret;
	}
	
	/**
	 * @brief tworzy listę filmów ogłoszenia
	 * 
	 * Tworzy listę id filmów ogłoszeń, dzieki temu że model ogłoszeń nie jest xml, link do niego nie jest przetwarzany \
	 * przez silnik templatów i powoduje wyświetlanie ogłoszeń to samo id ogłoszenia wystarcza do wyświetalnia go.
	 */
	public function filmy_ogloszenia()
	{
		foreach($this->filmy->item as $film)
			$ret[] = array('id'=> array_shift(explode('.',(array_pop(explode('/', $film))))));
		return $ret;
	}
	
	
	/**
	 * @brief pole opisu szczegółowego
	 * 
	 * Zwraca dane szczegółowe specyficzne dla ogłoszenia z wybranej kategorii, dane te są zbiorem tablic w postaci
	 * {'pole'=>nazwa_pola, 'label'=>czytelny_opis_opla, 'wartosc'=>dane_ogłoszenia_dla_tego_pola }
	 */
	public function pola_opisu()
	{
		$def_pol = array();
		$pola_specjalne = $this->kategoria->opis_kategorii->pola_specjalne->item;
		
		if($pola_specjalne && $this->dane->szczegoly)
		{
			foreach($pola_specjalne as $pole)
				$def_pol[(string)$pole->nazwa] = $pole;
			$opis = $this->dane->szczegoly->children();
			
			$dane = array();
			
			foreach($opis as $pole=>$wartosc)
			{
				$wartosc = (string) $wartosc;
				if($wartosc && $wartosc!='0')
				{
					$pole = $def_pol[(string)$pole];
					if($pole->typ=='enum')
						$wartosc=(string)$pole->opcje->item[((int)$wartosc)-1]->opis;
					
					$dane[] = array('pole'=>$pole, 'label'=>(string)$pole->opis, 'wartosc'=>$wartosc);
				}
			}
			return $dane;
		}
		return array();
	}
}

/***
 * @brief model użytkownika
 * 
 * Model ten służy do pobierania danych użytkownika
 * @see model
 */
class uzytkownik extends model
{
	protected $model = 'uzytkownik';	
	protected $opis = false;
	
	public function link()
	{
		$url = 'http://'.$this->login.'.'.$this->adcentral->getSerwerUrl();
		return $url;
	}
	
}

/**
 * @brief model zdjęcia
 * 
 * Model ten służy do pobierania zdjęć, w przeciwieństwie do zwykłych modeli zwraca plik a nie xml
 * @see model
 */
class zdjecie extends model
{
	protected $model = 'zdjecie';	
	protected $nie_zamieniaj = true;
	 
	public function pobierz($id)
	{
		parent::pobierz($id[0].'/'.$id[1].'/'.$id.'.jpg');
		
		header('Content-Type: image/jpeg');
		print $this->dane;
	}

	public function __get($nazwa)
	{
		
	}
}


/**
 * @brief model film
 * 
 * Model ten służy do pobierania filmów , w przeciwieństwie do zwykłych modeli zwraca plik a nie xml
 * @see model
 */
class film extends model
{
	protected $model = 'film';	
	protected $nie_zamieniaj = true;
	 
	public function pobierz($id)
	{
		parent::pobierz($id[0].'/'.$id[1].'/'.$id.'.flv');
		
		header('Content-Type: video/x-flv');
		print $this->dane;
	}

	public function __get($nazwa)
	{
		
	}
}

/**
 * @brief model miniatury
 * 
 * Model do pobierania i cachowania miniatur
 */
class miniatura extends model
{
	protected $model = 'miniatura';	
	protected $nie_zamieniaj = true;
	 
	public function pobierz($id)
	{
		parent::pobierz($id[0].'/'.$id[1].'/'.$id.'.jpg');
		
		header('Content-Type: image/jpeg');
		print $this->dane;
	}

	public function __get($nazwa)
	{
		
	}
}


/*
 * Modele, Dostęp do danych
 * 
 */

/**
 * @brief klasa backendu
 * 
 * Klasy backendu powinny dziedziczyć od tej klasy. Metoda pobierz powinna zwracać dane zapisane przez zapisz, jeżeli ich ważność nie upłynęła. 
 */
abstract class backend
{
	public function __construct($opcje)
	{
		$this->opcje = $opcje;
	}
	/**
	 * @brief pobieranie obiektu modelu
	 * 
	 * Zwraca obiekt modelu $model o żądanym $id jeżeli $waznosc nie upłynęła
	 * 
	 * @param $model nazwa modelu którego obiekt ma być pobrany
	 * @param $id id pobieranego obiektu
	 * @param $waznosc długość przetrzymywania obiektu a cache w sekundach
	 * @return obiekt podanego modelu 
	 */
	abstract public function pobierz($model, $id, $waznosc);
	/**
	 * @brief zapisuje obiekt
	 * 
	 * zapisuje dane obiektu o podanym id, należącego do modelu $model
	 * 
	 * @param $model nazwa modelu którego obiekt ma być zapisany
	 * @param $id id obiektu, którego dane będą zapisywane
	 * @param $dane dane zapisywanego obiektu
	 */
	abstract public function zapisz($model, $id, $dane);
}

?>