<?php

class Dalten_Export_Api_Backend_Idnes implements Dalten_Export_Api_Backend_LoggableBackendInterface
{

	/**
	 * @var Dalten_Ftp_ConnectorInterface
	 */
	private $_ftpAdapter = null;

	/**
	 * @var Dalten_Export_Api_Backend_Idnes_RequestInterface
	 */
	private $_request = null;

	/**
	 * Uzivatelske jméno maklere pod kterym exportujeme.
	 *
	 * @var string
	 */
	private $_username = '';

	/**
	 * Heslo maklere.
	 *
	 * @var string
	 */
	private $_password = '';

	/**
	 * Url k exportum.
	 *
	 * @var string
	 */
	private $_url = '';

	/**
	 * Url na kontrolu prihlasovacih udaju.
	 *
	 * @var string
	 */
	private static $_loginUrl = '/check_login.php?login=%(username)&pwd=%(password)';

	/**
	 * Url pro pridani nabidky.
	 *
	 * @var string
	 */
	private static $_addListingUrl = '/import.php?login=%(username)&pwd=%(password)&filename=%(filename)';

	/**
	 * Url pro získání seznamu nabídek.
	 *
	 * @var string
	 */
	private static $_getListingsListUrl = '/get_list.php?login=%(username)&pwd=%(password)';

	/**
	 * @var string URL pro hopování (topování) nabídek.
	 */
	private static $_hopListingUrl = '/hop.php?login=%(username)&pwd=%(password)&id_exported=%(id_exported)';

	/**
	 * Instance loggeru komunikace se serverem.
	 *
	 * @var Dalten_Export_Api_Backend_Logger_LoggerInterface
	 */
	private $_logger;

	/**
	 * Nastavi objekt pro exportovani.
	 *
	 * @param Dalten_Ftp_ConnectorInterface                    $ftpAdapter Adapter pro praci s ftp.
	 * @param Dalten_Export_Api_Backend_Idnes_RequestInterface $request    Trida pro http get pingani.
	 * @param string                                           $url        Url importniho rozhrani.
	 */
	public function __construct(
		Dalten_Ftp_ConnectorInterface $ftpAdapter,
		Dalten_Export_Api_Backend_Idnes_RequestInterface $request,
		$url = 'https://import.reality.idnes.cz/import/'
	)
	{
		$this->_ftpAdapter = $ftpAdapter;
		$this->_request = $request;
		$this->_url = $url;
	}

	/**
	 * Přihlásí uživatele na ftp a provede kontrolu přihlašovacích údajů přes http login.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function connect()
	{
		try {
			$this->_ftpAdapter->getConnection();
		} catch (Dalten_Ftp_Exception_BadLoginOrPassword $e) {
			return new Dalten_Export_Api_ServerResponse(false, 401, $e->getMessage());
		} catch (Dalten_Ftp_Exception_Connect $e) {
			return new Dalten_Export_Api_ServerResponse(false, 500, $e->getMessage());
		}

		$url = $this->getUrl(self::$_loginUrl);

		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteCall('login', $url);
		}
		$httpResponse = $this->_request->get($url);
		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteResponse('login', $httpResponse);
		}
		$httpResponse = $this->_explodeResponse($httpResponse);

		if (isset($httpResponse[0]) && trim($httpResponse[0]) !== 'OK') {
			$response =  new Dalten_Export_Api_ServerResponse(false, 401, implode($httpResponse, '\n'));
		} else {
			$response =  new Dalten_Export_Api_ServerResponse(true, 200, 'Přihlášení proběhlo v pořádku.');
		}

		return $response;
	}

	/**
	 * Přidá nabídku na server.
	 *
	 * @param array $data     Data která chceme vyexportovat.
	 * @param array $userData Data o makléři.
	 * @param array $images   Data o obrázcích.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function addListing($data, array $userData = array(), array $images = array())
	{
		if (!empty($userData)) {
			$data = array_merge($this->addUser($userData), $data);
		}

		if (!empty($images)) {
			$data = array_merge($this->addImages($this->_username, $images), $data);
		}

		return $this->_exportListingData($data, $data['id_exported']);
	}

	/**
	 * Smaze nabidku ze serveru.
	 *
	 * @param integer $listingId Id nabidky kterou chceme smazat.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function deleteListing($listingId)
	{
		$data = array(
			'id_exported' => (integer) $listingId,
			'akce' => 'delete'
		);

		return $this->_exportListingData($data, $listingId);
	}

	/**
	 * Vytopuje nabídku na serveru.
	 *
	 * @param integer $listingId ID nabídky, kterou chceme vytopovat.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function hopListing($listingId)
	{
		$url = $this->getUrl(self::$_hopListingUrl, array('%(id_exported)' => $listingId));

		$httpResponse = $this->_request->get($url);
		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteResponse('addListing', $httpResponse);
		}

		$responseParts = $this->_explodeResponse($httpResponse);
		if (isset($responseParts[0]) && trim($responseParts[0]) !== 'OK') {
			$response =  new Dalten_Export_Api_ServerResponse(false, 500, $httpResponse);
		} else {
			$response =  new Dalten_Export_Api_ServerResponse(true, 200, $httpResponse);
		}
		return $response;
	}

	/**
	 * Vrátí Server response s nastavenými daty, kde je seznam inzerátů na serveru.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function getListingsList()
	{
		$url = $this->getUrl(self::$_getListingsListUrl);

		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteCall('getListings', $url);
		}
		$httpResponse = $this->_request->get($url);
		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteResponse('getListings', $httpResponse);
		}
		$responseParts = $this->_explodeResponse($httpResponse);

		if (isset($responseParts[0]) && trim($responseParts[0]) !== 'OK') {
			$response =  new Dalten_Export_Api_ServerResponse(false, 500, $httpResponse);
		} else {
			array_shift($responseParts); // odstranime "OK"
			$responseParts = array_map('intval', $responseParts);
			$responseParts = array_filter($responseParts, function($item){return !!$item;});
			$response =  new Dalten_Export_Api_ServerResponse(true, 200, $httpResponse, $responseParts);
		}
		return $response;
	}

	/**
	 * Vyexportuje data na server a pingne url pro zpracovani nabidek.
	 *
	 * Z dat predanych v poli vygeneruje xml, ktere nahraje pomoci ftp na server a pak pingne
	 * url sefl::$_addListingUrl.
	 *
	 *
	 * @param array   $data      Data k vyexportovani.
	 * @param integer $listingId Id nabidky.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	private function _exportListingData(array $data, $listingId)
	{
		$filename = sprintf('%s_%s.xml', $this->_username, $listingId);

		$xml = $this->generateXmlFromData($data);

		if (!$this->_ftpAdapter->putContent($xml, $filename)) {
			return new Dalten_Export_Api_ServerResponse(false, 500, 'Nahravani souboru se nezdarilo.');
		}

		$url = $this->getUrl(self::$_addListingUrl, array('%(filename)' => $filename));

		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteCall('addListing', $url);
		}
		$httpResponse = $this->_request->get($url);
		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteResponse('addListing', $httpResponse);
		}

		$responseParts = $this->_explodeResponse($httpResponse);
		if (isset($responseParts[0]) && trim($responseParts[0]) !== 'OK') {
			$response =  new Dalten_Export_Api_ServerResponse(false, 500, $httpResponse);
		} else {
			$response =  new Dalten_Export_Api_ServerResponse(true, 200, $httpResponse);
		}
		return $response;
	}


	/**
	 * Nahraje obrázky na server pomocí ftp a vrátí pole s jejich pořadím a názvy.
	 *
	 * Toto pole se dále používá pro vytvoření xml.
	 *
	 * @param string $username Přihlašovací jméno uživatele.
	 * @param array  $images   Pole s obrázky.
	 *
	 * @return array
	 */
	public function addImages($username, array $images)
	{
		$data = array();
		$ord = 0;
		foreach (array_values($images) as $image) {
			$file = realpath($image['soubor']);
			if ($file) {
				$hash = md5_file($file);
				$serverFilename = sprintf('%s.%s', $hash, $this->_getFileExtension($file));
				$result = $this->_ftpAdapter->put($file, $serverFilename, FTP_BINARY);
				if ($result) {
					$data['foto'][] = array(
						'ord' => $ord++,
						'hash' => $hash,
						'filename' => $serverFilename
					);
				}
 			}
		}
		return $data;
	}


	/**
	 * Přegeneruje data uživatele.
	 *
	 * @param array $userData
	 * @return array
	 */
	public function addUser(array $userData)
	{
		$data = array();
		$photo = null;
		if (!empty($userData['foto'])) {
			$photo = realpath($userData['foto']);
			if ($photo) {
				$data['makler_foto'] = sprintf(
					'%s',
					base64_encode(file_get_contents($photo))
				);
			}
		}
		static $map = array(
			'id' => 'makler_id',
			'uzivatel_os_jmeno' => 'makler_jmeno',
			'uzivatel_os_prijmeni' => 'makler_prijmeni',
			'uzivatel_tituly_pred_jmenem' => 'makler_titul',
			'telefon' => 'makler_telefon',
			'email' => 'makler_email'
		);
		foreach ($map as $key => $value) {
			if (isset($userData[$key])) {
				$data[$value] =  $userData[$key];
			}
		}

		return $data;
	}

	/**
	 * Vrátí koncovku souboru.
	 *
	 * @param string $filename Název souboru.
	 *
	 * @return string
	 */
	private function _getFileExtension($filename)
	{
		$e = explode('.', $filename);
		return end($e);
	}

	/**
	 * Vygeneruje z dat xml soubory.
	 *
	 * @param array $data Data ze kterých chceme vygenerovat xml.
	 *
	 * @return string
	 */
	public function generateXmlFromData(array $data)
	{
		$xml = new Dalten_Export_Api_Backend_Idnes_Xml($data);
		return $xml->build();
	}

	/**
	 * Nastavi uzivatelske jemno.
	 *
	 * @param string $username Uzivatelske jemno.
	 *
	 * @return Dalten_Export_Api_Backend_Idnes
	 */
	public function setUsername($username)
	{
		$this->_username = (string) $username;
		return $this;
	}

	/**
	 * Nastavi heslo uzivatele.
	 *
	 * @param string $password
	 * @return Dalten_Export_Api_Backend_Idnes
	 */
	public function setPassword($password)
	{
		$this->_password = (string) $password;
		return $this;
	}

	/**
	 * Nahradi v url sablone placeholdery za hodnoty predave v poli.
	 *
	 * Protoze username a password je soucasti objektu tak je doplnuje automaticky.
	 *
	 * @param string $urlPattern Sablona url s placeholdery.
	 * @param array  $args       Pole s hodnotami placeholderu.
	 *
	 * @return string
	 */
	public function getUrl($urlPattern, array $args = array())
	{
		$userArgs = array(
			'%(username)' => $this->_username,
			'%(password)' => $this->_password
		);
		$args = array_merge($userArgs, $args);

		$patterns = array_keys($args);
		$replacemant = array_values($args);
		return $this->_url . str_replace($patterns, $replacemant, $urlPattern) . '&utf8=1';
	}

	/**
	 * Pomocna metoda ktera rozparsuje odpoved serveru.
	 *
	 * @param string $response Odpoved serveru.
	 *
	 * @return array
	 */
	private function _explodeResponse($response)
	{
		return preg_split('~\r\n~', $response);
	}

	/**
	 * Nastaví logger pro backend.
	 *
	 * Logger bude použit pouze pokud to backend dovoluje.
	 *
	 * @param Dalten_Export_Api_Backend_Logger_LoggerInterface $logger Instance loggeru.
	 *
	 * @return Dalten_Export_Api_LoggableApiInterface Fluent interface.
	 */
	public function setLogger(Dalten_Export_Api_Backend_Logger_LoggerInterface $logger)
	{
		if ($this->_ftpAdapter instanceof Dalten_Export_Api_Backend_LoggableBackendInterface) {
			$this->_ftpAdapter->setLogger($logger);
		}

		$this->_logger = $logger;

		return $this;
	}

	/**
	 * Odstraní nastavený logger.
	 *
	 * @return Dalten_Export_Api_LoggableApiInterface Fluent interface.
	 */
	public function removeLogger()
	{
		if ($this->_ftpAdapter instanceof Dalten_Export_Api_Backend_LoggableBackendInterface) {
			$this->_ftpAdapter->removeLogger();
		}

		$this->_logger = null;

		return $this;
	}

    public function getResponses(DateTime $dateTime)
    {
        throw new BadMethodCallException('Implementovano jen pro Idnes2.');
    }

    public function getStats(DateTime $dateTime)
    {
        throw new BadMethodCallException('Implementovano jen pro Idnes2.');
    }

    public function listListings()
    {
        throw new BadMethodCallException('Implementovano jen pro Idnes2.');
    }

    public function videoStatus(array $listingData, array $additionalParams = array())
    {
        throw new BadMethodCallException('Implementovano jen pro Idnes2.');
    }
}
