<?php
/**
 * Exportní API serveru Grandreality.
 *
 * Jejich API je kompatibilní s Srealitami (proto je tato třída původně kopie exportu na Sreality), ale ne zas tak moc.
 *
 * @category   Dalten
 * @package    Export
 * @subpackage Api
 */
class Dalten_Export_Api_Grandreality implements Dalten_Export_Api_ApiInterface, Dalten_Export_Api_LoggableApiInterface
{
	/**
	 * Konvertor hodnot.
	 *
	 * @var Dalten_Export_Sreality
	 */
	private $_export;

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

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

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

    /**
	 * Konstruktor.
	 *
	 * @param Dalten_Export_Sreality                 $export  Konvertor hodnot.
	 * @param Serenity_Config_Config                 $config  Nastavení.
	 * @param Dalten_Export_Api_Backend_Grandreality $backend Backend.
	 */
	public function __construct(Dalten_Export_Sreality $export,
								Serenity_Config_Config $config,
								Dalten_Export_Api_Backend_Grandreality $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);
			}
		}

		$userId = $userData['id'];
		$userData = array(
			'client_login' => $userData['jmeno'],
			'client_name' => $userData['uzivatel_os_jmeno'] . ' ' . (!empty($userData['uzivatel_os_prostredni_jmeno']) ?  ' ' . $userData['uzivatel_os_prostredni_jmeno'] : '') . $userData['uzivatel_os_prijmeni'],
			'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(
			'',
			$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($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(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.");
	}


	/**
	 * 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(null, $listingCode);
		if ($remoteImages instanceof Dalten_Data_ArrayObject) {
			/** @var $data Dalten_Data_ArrayObject */
			$remoteImages = $remoteImages->toArray(true);
		} else {
			$remoteImages = (array) $remoteImages;
		}

		foreach ((array) $remoteImages['output'] as $imageData) {
			$response = $this->_backend->delPhoto($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 = (array) $this->_backend->listPhoto(null, $projectRkId);

		foreach ((array) $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(
					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);
	}

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

}
