<?php

/**
 * Exportní API serveru Realitypro.eu.
 *
 * Jejich API je kompatibilní s Srealitami (proto je tato třída původně kopie exportu na Sreality), ale ne zas tak moc.
 *
 * RealityPro nemění session ID a jejich metody mají prefix reality.XXX .
 *
 * @category   Dalten
 * @package    Export
 * @subpackage Api
 */
class Dalten_Export_Api_RealityPro implements Dalten_Export_Api_ApiInterface, Dalten_Export_Api_LoggableApiInterface,
	Dalten_Export_Api_ProjectApiInterface
{
	/**
	 * Konvertor hodnot.
	 *
	 * @var Dalten_Export_Sreality
	 */
	private $_export;

	/**
	 * Nastavení.
	 *
	 * @var Serenity_Config_Config
	 */
	private $_config;

	/**
	 * Backend.
	 *
	 * @var Dalten_Export_Api_Backend_RealityPro
	 */
	private $_backend;

	/**
	 * Fixní část Session ID.
	 *
	 * @var string|null
	 */
	private $_sessionIdFixed = null;

	/**
	 * Fixní část variabilní části session ID.
	 *
	 * @var string|null
	 */
	private $_hashKey = null;

	/**
	 * Poslední platné session ID.
	 *
	 * @var string|null
	 */
	private $_sessionId = null;

	/**
	 * Status kód - inzerát byl přijat, ale změněné povinné položky nebyly uloženy.
	 */
	const STATUS_CANNOT_MODIFY = 204;

	/**
	 * Konstruktor.
	 *
	 * @param Dalten_Export_Sreality               $export  Konvertor hodnot.
	 * @param Serenity_Config_Config               $config  Nastavení.
	 * @param Dalten_Export_Api_Backend_RealityPro $backend Backend.
	 */
	public function __construct(Dalten_Export_Sreality $export,
		Serenity_Config_Config $config,
		Dalten_Export_Api_Backend_RealityPro $backend)
	{
		$this->_export = $export;
		$this->_config = $config;
		$this->_backend = $backend;
	}

	/**
	 * Naváže spojení se vzdáleným serverem.
	 *
	 * @param string $login            Přihlašovací jméno.
	 * @param string $password         Heslo.
	 * @param string $softwareKey      Softwarový klíč.
	 * @param array  $additionalParams Pole dalších parametrů.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function openConnection($login, $password, $softwareKey = '', array $additionalParams = array())
	{
		$response = $this->_backend->login($login, $password);

		$this->_sessionId = $response->session_id;

		return new Dalten_Export_Api_ServerResponse(
			isset($response->status) && $response->status == 200,
			isset($response->status) ? $response->status : 500,
			isset($response->statusMessage) ? $response->statusMessage : 'No response from server'
		);
	}

	/**
	 * Vrací session_id. RealityPro ho na rozdíl od Srealit nemění.
	 *
	 * @return string Nové session ID.
	 */
	protected function _getSessionId()
	{
		return $this->_sessionId;
	}

	/**
	 * Vyexportuje uživatele.
	 *
	 * @param array $userData Data uživatele ve formátu iRest 1.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	public function addUser(array $userData)
	{
		$photo = null;
		if (!empty($userData['foto'])) {
			$photo = (string) realpath($userData['foto']);
			if ($photo) {
				$photo = file_get_contents($photo);
			}
		}

		$jmenoCele = $userData['uzivatel_os_jmeno'] . (!empty($userData['uzivatel_os_prostredni_jmeno']) ?  ' ' . $userData['uzivatel_os_prostredni_jmeno'] : '') . ' ' . $userData['uzivatel_os_prijmeni'];

		if (!empty($userData['uzivatel_tituly_pred_jmenem'])) {
			$jmenoCele = $userData['uzivatel_tituly_pred_jmenem'] . ' ' . $jmenoCele;
		}

		if (!empty($userData['uzivatel_tituly_za_jmenem'])) {
			$jmenoCele = $jmenoCele . ' ' . $userData['uzivatel_tituly_za_jmenem'];
		}

		$userId = $userData['id'];
		$userData = array(
			'client_login' => $userData['jmeno'],
			'client_name' => $jmenoCele,
			'contact_gsm' => $userData['telefon'],
			'contact_email' => $userData['email'],
			'contact_phone' => empty($userData['pevna_linka']) ? '' : $userData['pevna_linka'],
			'makler_note' => $userData['moto'],
			'photo' => $photo
		);


		$response = $this->_backend->addSeller(
			$this->_getSessionId(),
			'',
			$userId,
			$userData
		);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			array('remoteId' => isset($response->sellerId) ? $response->sellerId : null)
		);
	}



	/**
	 * Vyexportuje nabídku.
	 *
	 * @param array $listingData      Data nabídky ve formátu iRest 1.
	 * @param array $userData         Data uživatele (makléře, kterému nabídka patří) ve formátu iRest 1.
	 * @param array $images           Pole fotografií nabídky ve formátu iRest 1.
	 * @param array $additionalParams Pro tento export, nejsou přídavná data potřebná.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	public function addListing(
		array $listingData, array $userData, array $images = array(), array $additionalParams = array()
	)
	{
		$nazev = $listingData['nemovitost_titulek'];
		$listingData = $this->_export->convertEntityValues('listing', $listingData, $this->_config->listing);

		if (!empty($additionalParams['listing']['hide_price'])) {
			$listingData['advert_price'] = (float) 0;
			$priceNote = isset($listingData['advert_price_text_note'])
				? trim($listingData['advert_price_text_note']) : '';
			if (empty($priceNote)) {
				$listingData['advert_price_text_note'] = 'Informace v RK';
			}
		}

		if (
			isset($listingData['energy_performance_attachment'])
		) {
			$priloha = realpath($listingData['energy_performance_attachment']);
			//nemáme soubor se štítkem (realpath nechá projít prázdnou hodnotu)
			if (empty($listingData['energy_performance_attachment']) || $priloha===false) {
				unset($listingData['energy_performance_attachment']);
			} else {
				$listingData['energy_performance_attachment'] = file_get_contents($listingData['energy_performance_attachment']);
			}
		}

		if (!empty($userData)) {
			if (empty($userData['id'])) {
				$userData['id'] = sprintf('%u', crc32(serialize($userData['sreality_login'])));
			}

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

			$listingData['seller_rkid'] = (string) $userData['id'];
		}

		// Podstrkaváme titulek (Sreality si ho vymýšlí samy, Realitypro ne)
		$listingData['title'] = $nazev;

		$warningNote = null;
		$originalResponseCannotModify = null;

		$response = $this->_backend->addAdvert($this->_sessionId, $listingData);
		$remoteId = isset($response->output->advertId) ? $response->output->advertId : null;
		if ($response->status != 200) {
			if ($response->status == self::STATUS_CANNOT_MODIFY) {
				$warningNote = $this->_parseCannotModify($response);
				$originalResponseCannotModify = $response->toArray(true);
			}else{
				return new Dalten_Export_Api_ServerResponse(false, $response->status, $response->statusMessage);
			}
		}

		$remotePhotos = $this->_backend->listPhoto($this->_getSessionId(), null, $listingData['advert_rkid']);
		if ($remotePhotos['output'] instanceof Dalten_Data_ArrayObject) {
			$remotePhotos = $remotePhotos['output']->toArray();
		} else {
			$remotePhotos = array();
		}

		if ($this->_comparePhotos($images, $remotePhotos) === false) {
			$this->_deleteImages($listingData['advert_rkid']);
		}

		$response = $this->_addImages($listingData['advert_rkid'], $images);
		if (!$response->wasSuccessful()) {
			return $response;
		}

		$response =  new Dalten_Export_Api_ServerResponse(
			true,
			200,
			((!empty($warningNote)) ? $warningNote : ''),
			array('remoteId' => $remoteId)
		);

		if ($originalResponseCannotModify) {
			$response->setData($originalResponseCannotModify);
		}

		return $response;
	}

	/**
	 * Odstraní nabídku ze vzdáleného serveru.
	 *
	 * @param array $listingData      Data nabídky ve formátu iRest 1.
	 * @param array $additionalParams Specifická data pro daný export (zde prázdné pole).
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function deleteListing(array $listingData, array $additionalParams = array())
	{
		$response = $this->_backend->delAdvert(
			$this->_getSessionId(),
			null,
			isset($listingData['kod']) ? $listingData['kod'] : null
		);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage
		);
	}

	/**
	 * Implementace interface.
	 *
	 * @throws BadMethodCallException
	 */
	public function getListingsList()
	{
		throw new BadMethodCallException("Method 'getListingsList' IS NOT implemented yet.");
	}

	/**
	 * Vždy uspěje.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function closeConnection()
	{
		return new Dalten_Export_Api_ServerResponse(true);
	}

	/**
	 * Vrátí statistiky. Pokud jsou $advertId a $advertRkId prázdná vrací statistiky pro všechny inzeráty.
	 *
	 * Statistiky prozatím vracíme v syrové formě tak jak je dostáváme.
	 *
	 * @param array $advertId   Pole ID nabídek.
	 * @param array $advertRkId Pole vlastních ID nabídek.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function listStat(array $advertId, array $advertRkId)
	{
		$response = $this->_backend->listStat(
			$this->_getSessionId(),
			$advertId,
			$advertRkId
		);
		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			$response->output
		);
	}

	/**
	 * Vrací denní statistiky.
	 *
	 * Statistiky prozatím vracíme v syrové formě.
	 *
	 * @param int    $advertId   ID nabídky.
	 * @param string $advertRkId Vlastní ID nabídky.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function listDailyStat($advertId, $advertRkId)
	{
		$response = $this->_backend->listDailyStat(
			$this->_getSessionId(),
			$advertId,
			$advertRkId
		);
		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			$response->output
		);
	}

	/**
	 * Nastaví logger pro backend.
	 *
	 * Logger bude použit pouze pokud to backend dovoluje.
	 *
	 * @param Dalten_Export_Api_Backend_Logger_LoggerInterface $logger Instance loggeru.
	 *
	 * @return bool Podařilo se přiřadit backendu logger?
	 */
	public function setLogger(Dalten_Export_Api_Backend_Logger_LoggerInterface $logger)
	{
		if ($this->_backend instanceof Dalten_Export_Api_Backend_LoggableBackendInterface) {
			$this->_backend->setLogger($logger);

			return true;
		}

		return false;
	}

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

		return $this;
	}

	/**
	 * Porovná obrázky, přiložené k fotce, s obrázky, které jsou již nahrány na serveru srealit.
	 *
	 * @param array $listingImages Pole informací o fotkách nabídky ve formátu iRest1.
	 * @param array $remoteImages  Pole informací o fotkách nabídky ve formátu výsledku metody listPhoto.
	 *
	 * @return bool Jsou fotky stejné?
	 */
	private function _comparePhotos(array $listingImages, array $remoteImages)
	{
		if (count($listingImages) != count($remoteImages)) {
			return false;
		}

		$listingImages = array_values($listingImages);

		$indexedListingImages = array();
		foreach ($listingImages as $listingImage) {
			if (isset($listingImage['poradi'])) {
				$indexedListingImages[$listingImage['poradi']] = $listingImage;
			} else {
				// pokud někde chybí pořadí, nebudeme podle něj řadit :)
				$indexedListingImages = $listingImage;
				break;
			}
		}
		ksort($indexedListingImages);
		$listingImages = array_values($indexedListingImages);
		$remoteImages = array_values($remoteImages);

		foreach ($listingImages as $index => $image) {
			if (empty($remoteImages[$index])) {
				return false;
			}
			if ($image['id'] != $remoteImages[$index]['photo_rkid']) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Odstraní existující fotografie dané nabídky ze serveru.
	 *
	 * @param string $listingCode Kód nabídky.
	 *
	 * @return Dalten_Export_Api_ServerResponse Informace o výsledku smazání.
	 */
	private function _deleteImages($listingCode)
	{
		$success = true;
		$status = 200;
		$message = '';

		$remoteImages = $this->_backend->listPhoto($this->_getSessionId(), null, $listingCode)->toArray(true);

		if (isset($remoteImages['output']) && is_array($remoteImages['output'])) {
            foreach ($remoteImages['output'] as $imageData) {
                $response = $this->_backend->delPhoto($this->_getSessionId(), $imageData['photo_id'], null);
                if ($response->status != 200) {
                    $success = false;
                    $status = $response->status;
                    $message = $response->statusMessage;
                }
            }
        }

		return new Dalten_Export_Api_ServerResponse($success, $status, $message);
	}

	/**
	 * Odstraní existující fotografie daného projektu ze serveru.
	 *
	 * @param string $projectRkId Kód projektu.
	 *
	 *  @return Dalten_Export_Api_ServerResponse Informace o výsledku smazání.
	 */
	private function _deleteImagesProject($projectRkId)
	{
		$success = true;
		$status = 200;
		$message = '';

		$remoteImages = $this->_backend->listPhoto($this->_getSessionId(), null, $projectRkId)->toArray(true);

        if (isset($remoteImages['output']) && is_array($remoteImages['output'])) {
            foreach ($remoteImages['output'] as $imageData) {
                $response = $this->_backend->delProjectPhoto($this->_getSessionId(), $imageData['photo_id'], null);
                if ($response->status != 200) {
                    $success = false;
                    $status = $response->status;
                    $message = $response->statusMessage;
                }
            }
        }

		return new Dalten_Export_Api_ServerResponse($success, $status, $message);
	}

	/**
	 * Vyexportuje fotografie nabídky.
	 *
	 * @param string $listingCode Kód nabídky ve formátu Nxxxxx.
	 * @param array  $images      Pole fotografií ve formátu iRest 1.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	private function _addImages($listingCode, array $images)
	{
		$success = true;
		$status = 200;
		$message = "Fotografie: \n";
		foreach (array_values($images) as $i => $image) {
			$file = realpath($image['soubor']);
			if ($file) {
				$image = array(
					'data' => file_get_contents($file),
					'main' => !$i,
					'order' => $image['poradi'],
					'alt' => $image['popis'],
					'photo_rkid' => $image['id']
				);

				$response = $this->_backend->addPhoto(
					$this->_getSessionId(),
					null,
					$listingCode,
					$image
				);

				$status = $response->status;
				$message .= basename($file) . ' - ' . $response->statusMessage . PHP_EOL;

				if ($status != 200) {
					$success = false;
				}
			}
		}

		return new Dalten_Export_Api_ServerResponse($success, $status, $message);
	}

	/**
	 * Vyexportuje fotografie projektu.
	 *
	 * @param string $projectRkId Kód projektu.
	 * @param array  $images      Pole fotografií ve formátu iRest 1.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	private function _addImagesProject($projectRkId, array $images)
	{
		$success = true;
		$status = 200;
		$message = "Fotografie: \n";
		foreach (array_values($images) as $i => $image) {
			$file = realpath($image['soubor']);
			if ($file) {
				$image = array(
					'data' => file_get_contents($file),
					'main' => !$i,
					'order' => $image['poradi'],
					'alt' => $image['popis'],
					'photo_rkid' => $image['id']
				);

				$response = $this->_backend->addProjectPhoto(
					$this->_getSessionId(),
					null,
					$projectRkId,
					$image
				);

				$status = $response->status;
				$message .= basename($file) . ' - ' . $response->statusMessage . PHP_EOL;

				if ($status != 200) {
					$success = false;
				}
			}
		}

		return new Dalten_Export_Api_ServerResponse($success, $status, $message);
	}

	/**
	 * Vyexportuje projekt.
	 *
	 * @param array $projectData      Data projektu ve formátu iRest 1.
	 * @param array $userData         Data uživatele (makléře, kterému projekt patří) ve formátu iRest 1.
	 * @param array $listingIds       Pole s IDčky nabídek (ve tvaru id=>kod).
	 * @param array $images           Pole fotografií projektu ve formátu iRest 1.
	 * @param array $additionalParams Údaje které vrací server při exportu a jsou potřeba pro další
	 *                                práci s nabídkou.
	 *                                Data můžou sloužit pro editaci apod...
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	public function addProject(array $projectData, array $userData, array $listingIds = array(),
							   array $images = array(), array $additionalParams = array())
	{
		$projectData = $this->_export->convertEntityValues('project', $projectData, $this->_config->project);

		if (!empty($userData)) {
			if (empty($userData['id'])) {
				$userData['id'] = sprintf('%u', crc32(serialize($userData['sreality_login'])));
			}

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

			$projectData['seller_rkid'] = (string) $userData['id'];
		}

		$response = $this->_backend->addProject($this->_getSessionId(), $projectData);
		$remoteId = isset($response->output->projectId) ? $response->output->projectId : null;

		$warningNote = null;

		if ($response->status != 200) {
			if ($response->status == self::STATUS_CANNOT_MODIFY) {
				$warningNote = $this->_parseCannotModify($response);
			} else {
				return new Dalten_Export_Api_ServerResponse(false, $response->status, $response->statusMessage);
			}
		}

		$remotePhotos = $this->_backend->listProjectPhoto($this->_getSessionId(), null, $projectData['project_rkid']);
		if ($remotePhotos['output'] instanceof Dalten_Data_ArrayObject) {
			$remotePhotos = $remotePhotos['output']->toArray();
		} else {
			$remotePhotos = array();
		}

		if ($this->_comparePhotos($images, $remotePhotos) === false) {
			$this->_deleteImagesProject($projectData['project_rkid']);
		}

		$response = $this->_addImagesProject($projectData['project_rkid'], $images);
		if (!$response->wasSuccessful()) {
			return $response;
		}

		return new Dalten_Export_Api_ServerResponse(
			true,
			200,
			(!empty($warningNote) ? $warningNote : ''),
			array('remoteId' => $remoteId)
		);

	}

	/**
	 * Odstraní projekt ze vzdáleného serveru.
	 *
	 * @param array $projectData      Data projektu ve formátu iRest 1.
	 * @param array $additionalParams Specifická data pro daný export.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function deleteProject(array $projectData, array $additionalParams = array())
	{
		$response = $this->_backend->delProject(
			$this->_getSessionId(),
			'',
			$projectData['id_projekt']
		);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage
		);
	}

	/**
	 * Pomocná funkce. Převede odpověď serveru na uživatelsky přívětivou hlášku o nezměnitelných položkách.
	 *
	 * Položky zatím nevypisujeme.
	 *
	 * @param $response object Odpověď serveru.
	 *
	 * @return string Zpracovaná chybová hláška.
	 */
	protected function _parseCannotModify($response)
	{
		$warningNote = 'Inzerát byl přijat, ale změněné povinné položky nebyly uloženy';
		/*if (isset($response->cannotModify)) {
			$refusedChanges = array();
			foreach ($response->cannotModify as $item) {
				$refusedChanges[] = sprintf(
					'%s z "%s" na "%s"', $item->item_desc, $item->old_val, $item->new_val
				);
			}
			$warningNote = $warningNote . ' Nepodařilo se změnit tyto položky: ' . implode(', ',$refusedChanges) . '';
		}*/
		return $warningNote;
	}

}
