<?php
/**
 Backend pro novou verzi Idnesu.
**/
class Dalten_Export_Api_Backend_Idnes2 extends Dalten_Export_Api_Backend_Idnes
{

	/**
	 * @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 = '/login_check.php?login=%(username)&pwd=%(password)';

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

	/**
	 * Url pro odebrání nabídky.
	 *
	 * @var string
	 */
	private static $_removeListingUrl = '/nemo_remove.php?login=%(username)&pwd=%(password)&id_exported=%(id_exported)';

	/**
	 * @var string URL pro získání URL nabídky.
	 */
	private static $_getListingUrlUrl = '/nemo_get_url.php?login=%(username)&pwd=%(password)&id_exported=%(id_exported)';

	/**
	 * Url pro přidání makléře.
	 *
	 * @var string
	 */
	private static $_addAgentUrl = '/agent_import.php?login=%(username)&pwd=%(password)&filename=%(filename)';

	/**
	 * Url pro odebrání makléře.
	 *
	 * @var string
	 */
	private static $_removeAgentUrl = '/agent_remove.php?login=%(username)&pwd=%(password)&id_agen_exported=%(id_agen_exported)';

	/**
	 * 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 = '/nemo_hop.php?login=%(username)&pwd=%(password)&id_exported=%(id_exported)';

    /**
     * @var string URL pro získání URL nabídky.
     */
    private static $_getVideoInfoUrl = '/nemo_get_video_info.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/v2'
	)
	{
		$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());
		}

		return $this->callScript(self::$_loginUrl);
	}

	/**
	 * 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())
	{
        $synchronizeVideos = isset($data['videos']);
        $videos = isset($data['videos']) ? $data['videos'] : [];
        unset($data['videos']); // aby se info o videu nepropsalo do XML

		$addUserResponse = $this->addUser($userData);
		if (!$addUserResponse->wasSuccessful()) {
			return $addUserResponse;
		}

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

        $videosChanged = false;
        if ($synchronizeVideos) {
            $videoAlreadyUp = false;
            // zjistíme, zda jsme předtím nahráli nějaké video
            $videoInfoResponse = $this->callScript(self::$_getVideoInfoUrl, array('%(id_exported)'=>$data['id_exported']));
            if ($videoInfoResponse->wasSuccessful()) {
                $videoInfo = $videoInfoResponse->getOutput()->toArray(true);
                if (!empty($videoInfo['nemovitost']['video_hash'])) {
                    // pokud jsme ho nahráli a už je tam to správné
                    if (isset($videos[0]) && $videoInfo['nemovitost']['video_hash']==$videos[0]['md5']) {
                        // tak jen přidáme do XML info o tom, že už video je a chceme ho zobrazovat
                        $data = array_merge($this->addVideoWithoutUpload($this->_username, $videos[0]), $data);
                        $videoAlreadyUp = true;
                        $videosChanged = true;
                    }
                }
            }

            if (isset($videos[0]) && !$videoAlreadyUp) {
                // pokud video ještě není nebo se změnilo - posíláme video nově
                $data = array_merge($this->addVideo($this->_username, $videos[0]['path']), $data);
                $videosChanged = true;
            }

            // odstranění videa se děje implicitně když není v XML
        }

		$exportResponse =  $this->_exportListingData($data, $data['id_exported']);

		if ($exportResponse->wasSuccessful()) {
			// pokud byla nabídka úspěšně vyexportována, zeptáme se na serveru na URL nabídky
			$getURLResponse = $this->callScript(self::$_getListingUrlUrl, array('%(id_exported)'=>$data['id_exported']));
			$urlData = $getURLResponse->getOutput();
			if ($getURLResponse->wasSuccessful() && !empty($urlData['url'])) {
				$exportResponse->setData(array('detailUrl'=>$urlData['url']));
                if ($videosChanged) {
                    $exportResponse->setData(array('detailUrl'=>$urlData['url'], 'videoStatus'=>'waiting'));
                }
			}
		}

		return $exportResponse;
	}

	/**
	 * Smaze nabidku ze serveru.
	 *
	 * @param integer $listingId Id nabidky kterou chceme smazat.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function deleteListing($listingId)
	{
		return $this->callScript(self::$_removeListingUrl, array('%(id_exported)'=>$listingId));
	}

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

	/**
	 * Vrátí Server response s nastavenými daty, kde je seznam inzerátů na serveru.
	 *
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function getListingsList()
	{
		throw new BadMethodCallException('Not yet implemented.');
	}

	/**
	 * 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.');
		}

		return $this->callScript(self::$_addListingUrl, array('%(filename)' => $filename));
	}


	/**
	 * 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 = 1;
		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['images'][] = array(
						'ord' => $ord++,
						'hash' => $hash,
						'filename' => $serverFilename
					);
				}
 			}
		}
		return $data;
	}

    /**
     * Nahraje videa 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 string $path     Cesta k souboru videa.
     *
     * @return array
     */
    public function addVideo($username, $path)
    {
        $data = array();
        $ord = 1;
        $file = realpath($path);
        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['videos'][] = array(
                    'ord' => $ord++,
                    'hash' => $hash,
                    'filename' => $serverFilename
                );
            }
        }
        return $data;
    }

    /**
     * Přidá informaci o nahraném videu bez toho aby se fyzicky posílalo.
     *
     * @param string $username  Přihlašovací jméno uživatele.
     * @param array  $videoInfo Informace o nahraném videu.
     *
     * @return array
     */
    public function addVideoWithoutUpload($username, $videoInfo)
    {
        $data = [];
        if (!empty($videoInfo)) {
            $serverFilename = sprintf('%s.%s', $videoInfo['md5'], pathinfo($videoInfo['path'], PATHINFO_EXTENSION));
            $data['videos'][] = array(
                'ord' => 1,
                'hash' => $videoInfo['md5'],
                'filename' => $serverFilename
            );
        }

        return $data;
    }


	/**
	 * Vyexportuje makléře
	 *
	 * @param array $userData
	 * @return Dalten_Export_Api_ServerResponse
	 */
	public function addUser(array $userData)
	{
		$data = array();
		$photo = null;

		static $map = array(
			'id' => 'id_agen_exported',
			'uzivatel_os_jmeno' => 'jmeno',
			'uzivatel_os_prijmeni' => 'prijmeni',
			'uzivatel_tituly_pred_jmenem' => 'titul',
			'email' => 'email',
			'telefon' => 'telefon',
            'makler_ico' => 'agent_ico'
		);

		/** @var Dalten_Xml_SimpleXml $xml */
		$xml = simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><agent/>', 'Dalten_Xml_SimpleXml');

		foreach ($map as $originalName => $exportedName) {
			if (isset($userData[$originalName])) {
				$xml->addChild($exportedName, $userData[$originalName]);
			}
		}

		if (!empty($userData['foto'])) {
			$photo = realpath($userData['foto']);
			$resizePhoto = false;
			if (!empty($userData['foto_detail']) && realpath($userData['foto_detail'])) {
			    $photo = realpath($userData['foto_detail']);
			    $resizePhoto = true;
            }

			if ($photo) {
				$maklerFoto = file_get_contents($photo);

				if ($resizePhoto) {
				    $maklerFoto = $this->_resizeImage($maklerFoto);
				}

				if ($maklerFoto) {
					$xml->addChild('image_base64', base64_encode($maklerFoto));
					$xml->addChild('image_hash', md5($maklerFoto));
				}
			}
		}

		$filename = sprintf('%s_ag_%s.xml', $this->_username, $userData['id']);
		$xml = $xml->getMultilineXml();

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

		return $this->callScript(self::$_addAgentUrl, array('%(filename)'=>$filename));
	}

    /**
     * Zmenší obrázek v paměti bez ukládání dočasného souboru.
     */
	protected function _resizeImage($image)
    {
        $toResize = imagecreatefromstring($image);
        if (!$toResize) {
            return false;
        }
        $resizedPhoto = imagecreatetruecolor(500, 500);
        if (imagecopyresampled($resizedPhoto, $toResize, 0,0,0,0,500,500,1000,1000)) {
            ob_start();
            imagejpeg($resizedPhoto, null, 95);
            $ret = ob_get_clean();
            imagedestroy($toResize);
            imagedestroy($resizedPhoto);
            return $ret;
        }
        return false;
    }

	/**
	 * 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_Idnes2_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;
	}

	/**
	 * Zavolá skript na Idnesu a vrátí výstup ve formě Dalten_Export_Api_ServerResponse.
	 *
	 * Loguje a provádí potřebné převody dat.
	 *
	 * @param  string $url  URL skriptu Idnesu.
	 * @param  array  $args Pole parametrů skriptu s klíči ve formátu `%(param)`.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	protected function callScript($url, $args = array())
	{
		$tmp = explode('?', $url);
		$debugName = array_shift($tmp);
		$url = $this->getUrl($url, $args);

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

		if (isset($responseXML->control->status) && $responseXML->control->status=='ok') {
			$output = null;

			if (!empty($responseXML->data)) {
				// převádíme SimpleXml na PHP pole, aby to šlo uložit do Dalten_Data_ArrayObject
				// neděláme to sice čistou cestou, ale je to jednoduchý a celkem kompatibilní s výstupem Idnesu (který nepoužívá atributy)
				// viz https://gist.github.com/Thinkscape/6243184 pro detaily rizik
				$output = json_decode(json_encode($responseXML->data), true);
			}

			$response =  new Dalten_Export_Api_ServerResponse(
				true,
				200,
				isset($responseXML->control->message) ? $responseXML->control->message : $debugName . ' OK',
				$output
			);
		} else {
			$response =  new Dalten_Export_Api_ServerResponse(
				false,
				500,
				isset($responseXML->control->message) ? $this->translateErrorMessage($responseXML->control->message) : $debugName . ' FAIL'
			);
		}

		return $response;
	}

    /**
     * Přeloží části chybové hlášky.
     *
     * @param string $statusMessage Hláška k přeložení.
     *
     * @return string Přeložená hláška.
     */
    protected function translateErrorMessage(string $statusMessage)
    {
        return str_replace(
        ['pl_uzitna'],
        ['Plocha užitná'],
        $statusMessage
        );
    }

    /**
     * Získá dotazy k nemovitosti za datum.
     *
     * @param DateTime $dateTime Datum ke kterému se vztahujeme.
     * @return Dalten_Export_Api_ServerResponse Dotazy k nemovitosti.
     */
    public function getResponses(DateTime $dateTime)
    {
        $responsesUrl = '/nemo_get_responses.php?login=%(username)&pwd=%(password)&date_from=%(datum)&date_to=%(datum)';
        $response = $this->callScript($responsesUrl, ['%(datum)'=>$dateTime->format('Y-m-d')]);
        if ($response->wasSuccessful()) {
            // překládáme vrácené dotazy
            // vzhledem k tomu, že je to SimpleXML, tak je to $data['response'] buď už konkrétní dotaz nebo pole dotazů :-(
            $data = $response->getOutput()->toArray(true);
            $dotazy = [];
            if (isset($data['response']['id_exported'])) {
                $dotazy[] = $data['response'];
            } else {
                foreach ($data['response'] as $dotaz) {
                    $dotazy[] = $dotaz;
                }
            }
            $response = new Dalten_Export_Api_ServerResponse(true, 200, 'OK', $dotazy);
        }
        return $response;
    }

    /**
     * Získá statistiky nemovitostí pro datum.
     *
     * @param DateTime $dateTime Datum ke kterému se vztahujeme.
     * @return Dalten_Export_Api_ServerResponse Statistiky nemovitostí.
     */
    public function getStats(DateTime $dateTime)
    {
        $responsesUrl = '/nemo_get_stats.php?login=%(username)&pwd=%(password)&date=%(datum)';
        return $this->callScript($responsesUrl, ['%(datum)'=>$dateTime->format('Y-m-d')]);
    }

    /**
     * Vrátí seznam nabídek, které jsou na vzdáleném serveru.
     *
     * Ve výstupu je pole, kde každý vrácený řádek reprezentuje jednu nemovitost a musí obsahovat `kod` nebo `id`.
     *
     * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
     */
    public function listListings()
    {
        $responsesUrl = '/nemo_get_list.php?login=%(username)&pwd=%(password)';
        $response = $this->callScript($responsesUrl, []);

        if ($response->wasSuccessful()) {
            // překládáme seznam nemovitostí
            $listingList = [];
            $listings = $response->getOutput()->toArray(true);
            if (isset($listings['nemovitost']) && count($listings['nemovitost'])>1) {
                $listings = $listings['nemovitost'];
            } else {
                $listings = [];
            }
            if (isset($listings['id_exported'])) {
                $listings = [$listings];
            }
            foreach ($listings as $listing) {
                $listing['id'] = $listing['id_exported'];
                $listingList[] = $listing;
            }
            $response = new Dalten_Export_Api_ServerResponse(true, 200, 'OK', $listingList);
        }
        return $response;
    }

    public function videoStatus(array $listingData, array $additionalParams = array())
    {
        $responsesUrl = '/nemo_get_video_info.php?login=%(username)&pwd=%(password)&id_exported=%(id_exported)';
        $response = $this->callScript($responsesUrl, ['%(id_exported)'=>$listingData['id']]);

        if ($response->wasSuccessful()) {
            $output = $response->getOutput()->toArray(true);
            if (isset($output['nemovitost'])) $output = $output['nemovitost'];
            $response = new Dalten_Export_Api_ServerResponse(true, 200, 'OK', $output);
        }

        return $response;
    }
}
