<?php
class Dalten_Export_Api_CeskerealityThree implements Dalten_Export_Api_ApiInterface, Dalten_Export_Api_LoggableApiInterface, Dalten_Export_Api_ListListingsInterface, Dalten_Export_Api_TopListingInterface, Dalten_Export_Api_ProjectApiInterface
{
    private $_backend = null;
    private $_export = null;
    private $_addressConverter = null;
    private $_entities;

    protected $_accessToken = null;
    protected $_idFirmy = null;


    function __construct(
        Dalten_Export_Ceskereality $export,
        Dalten_Export_Api_Backend_CeskerealityThree $backend,
        Dalten_AddressConverter_Ceskereality_Interface $adressConverter,
        Serenity_Config_Config $entities
    )
    {
        $this->_export = $export;
        $this->_backend = $backend;
        $this->_addressConverter = $adressConverter;
        $this->_entities = $entities;
    }


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

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

        return $this;
    }

    /**
     * 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())
    {
        // TODO - CLIENT_ID a CLIENT_SECRET hardkódvané
        $token = $this->_backend->getAccessToken('Irest', 'P?jrt8K');
        if (!$token) {
            return new Dalten_Export_Api_ServerResponse(false, 500, 'Špatné nastavení CLIENT_ID a CLIENT_SECRET.');
        }
        $this->_accessToken = $token;
        $companiesList = $this->_backend->getCompaniesList($token);
        foreach ($companiesList as $company) {
            if ($company['id_firmy']==$login) {
                $this->_idFirmy = $company['id_firmy'];
                return new Dalten_Export_Api_ServerResponse(true);
            }
        }

        return new Dalten_Export_Api_ServerResponse(false, 500, 'Kancelář nemá povolený export na České reality.');
    }

    /**
     * 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 Ú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 addListing(array $listingData, array $userData, array $images = array(), array $additionalParams = array())
    {
	    $idNabidka = $listingData['id'];
        $listingData = $this->_addressConverter->convertAddress($listingData);
        $listingData = $this->_export->convertEntityValues('listing', $listingData, $this->_entities->listing);
        $userDataConverted = $this->_export->convertEntityValues('broker', $userData, $this->_entities->broker);

        if (!empty($additionalParams['listing']['hide_price'])) {
            // Cena dohodou
            $listingData['nemovitost_cena_prodej'] = 0;
            $listingData['nemovitost_cena_pronajem'] = 0;
            $listingData['nemovitost_cena_poznamka'] = 'Informace v RK';
        }

        $uploadedImages = array();
        foreach ($images as $image) {
            $md5 = md5_file($image['soubor']);
            if ($this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $image['soubor'], $md5.'.jpg')) {
                $uploadedImages[] = array('md5'=>$md5, 'popis'=>$image['popis']);
            }
        }
        if (!empty($userData['foto'])) {
            $this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $userData['foto'], 'M' . $userData['id'] . '.jpg');
        }

        $tempnam = tempnam(sys_get_temp_dir(), 'ceskereality');
        $xml = $this->_generateXML($idNabidka, 'U', $listingData + $userDataConverted, $uploadedImages);
        file_put_contents($tempnam, $xml);
        $xmlUploaded = $this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $tempnam, 'nemovitosti.xml');

        if (!$xmlUploaded) return new Dalten_Export_Api_ServerResponse(false, 500, 'Nepodařilo se nahrát XML s nemovitostmi.');

        $xmlImported = $this->_backend->importXml($this->_accessToken, $this->_idFirmy);
        if ($xmlImported===false) {
            return new Dalten_Export_Api_ServerResponse(false, 500, 'Rozhraní serveru nevrátilo žádný výstup!');
        }
        $msg = isset($xmlImported['msg']) ? $xmlImported['msg'] : '';
        if (is_array($msg)) {
            $msg = implode('; ', $msg);
        }
        $response = new Dalten_Export_Api_ServerResponse(
            $xmlImported['status'], $xmlImported['status'] ? 200 : 500, $msg
        );
        if (!empty($xmlImported['url'])) {
        	$response->setData(['detailUrl'=>$xmlImported['url']]);
        }
        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.
     *
     * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
     */
    public function deleteListing(array $listingData, array $additionalParams = array())
    {
        $idNabidka = $listingData['id'];
        $tempnam = tempnam(sys_get_temp_dir(), 'ceskereality');
        $xml = $this->_generateXML($idNabidka, 'D', array(), array());
        file_put_contents($tempnam, $xml);
        $xmlUploaded = $this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $tempnam, 'nemovitosti.xml');

        if (!$xmlUploaded) return new Dalten_Export_Api_ServerResponse(false, 500, 'Nepodařilo se nahrát XML s nemovitostmi.');

        $xmlImported = $this->_backend->importXml($this->_accessToken, $this->_idFirmy);

        return new Dalten_Export_Api_ServerResponse($xmlImported);
    }

    /**
     * Vrátí seznam nabídek, které jsou na vzdáleném serveru.
     *
     * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
     */
    public function getListingsList()
    {
        // TODO: Implement getListingsList() method.
    }

    /** {@inheritDoc} */
    public function addProject(array $projectData, array $userData, array $listingIds = array(), array $images = array(), array $additionalParams = array())
    {
        $idProjekt = $projectData['id'];
        $projectData = $this->_addressConverter->convertAddress($projectData);
        $projectData = $this->_export->convertEntityValues('project', $projectData, $this->_entities->project);
        $userDataConverted = $this->_export->convertEntityValues('broker', $userData, $this->_entities->broker);

        /*
        if (!empty($additionalParams['listing']['hide_price'])) {
            // Cena dohodou
            $listingData['nemovitost_cena_prodej'] = 0;
            $listingData['nemovitost_cena_pronajem'] = 0;
            $listingData['nemovitost_cena_poznamka'] = 'Informace v RK';
        }
        */

        $uploadedImages = array();
        foreach ($images as $image) {
            $md5 = md5_file($image['soubor']);
            if ($this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $image['soubor'], $md5.'.jpg')) {
                $uploadedImages[] = array('md5'=>$md5, 'popis'=>$image['popis']);
            }
        }
        if (!empty($userData['foto'])) {
            $this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $userData['foto'], 'M' . $userData['id'] . '.jpg');
        }

        $tempnam = tempnam(sys_get_temp_dir(), 'ceskereality');
        $xml = $this->_generateXML($idProjekt, 'U', $projectData + $userDataConverted, $uploadedImages, 'projekt');
        file_put_contents($tempnam, $xml);
        $xmlUploaded = $this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $tempnam, 'projekty.xml');

        if (!$xmlUploaded) return new Dalten_Export_Api_ServerResponse(false, 500, 'Nepodařilo se nahrát XML s projektem.');

        $xmlImported = $this->_backend->importXml($this->_accessToken, $this->_idFirmy);
        if ($xmlImported===false) {
            return new Dalten_Export_Api_ServerResponse(false, 500, 'Rozhraní serveru nevrátilo žádný výstup!');
        }
        $msg = isset($xmlImported['msg']) ? $xmlImported['msg'] : '';
        if (is_array($msg)) {
            $msg = implode('; ', $msg);
        }
        $response = new Dalten_Export_Api_ServerResponse(
            $xmlImported['status'], $xmlImported['status'] ? 200 : 500, $msg
        );
        if (!empty($xmlImported['url'])) {
            $response->setData(['detailUrl'=>$xmlImported['url']]);
        }
        return $response;
    }

    /** {@inheritDoc} */
    public function deleteProject(array $projectData, array $additionalParams = array())
    {
        $idProjektu = $projectData['id'];
        $tempnam = tempnam(sys_get_temp_dir(), 'ceskereality');
        $xml = $this->_generateXML($idProjektu, 'D', array(), array(), 'projekt');
        file_put_contents($tempnam, $xml);
        $xmlUploaded = $this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $tempnam, 'projekty.xml');

        if (!$xmlUploaded) return new Dalten_Export_Api_ServerResponse(false, 500, 'Nepodařilo se nahrát XML s projekty.');

        $xmlImported = $this->_backend->importXml($this->_accessToken, $this->_idFirmy);

        return new Dalten_Export_Api_ServerResponse($xmlImported);
    }


    /**
     * Vygeneruje XML soubor pro přidání/odebrání nabídky.
     *
     * @param int    $idNabidka   ID nabídky.
     * @param string $akceExportu Akce - U=přidat D=odebrat.
     * @param array  $pole        Zformátované informace o nabídce a makléři.
     * @param array  $fotos       Pole s fotkami nabídky.
     * @param string $typDat      "nabidka" nebo "projekt"
     *
     * @return string Výsledné XML jako řetězec.
     */
    protected function _generateXML($idNabidka, $akceExportu, array $pole, array $fotos, $typDat='nabidka')
    {
        // TODO - rozlišit mezi nabídkou a projektem
        $xml = new Dalten_Xml_SimpleXml('<?xml version="1.0" encoding="utf-8"?><xreal/>');

        $identifikaceXML = $xml->addChild('identifikace');
        $identifikaceXML->addAttribute('typ', 'CLIENT');
        $identifikaceXML->addChild('datumcas', date('Y-m-d-H-i-s'));
        $autorizaceXML = $identifikaceXML->addChild('autorizace');
        $autorizaceXML->addAttribute('id_firmy', $this->_idFirmy);

        $nabidkyXML = $xml->addChild($typDat=='nabidka' ? 'nabidky' : 'projekty');
        $nabidkaXML = $nabidkyXML->addChild($typDat);
        $nabidkaXML->addAttribute('id', $idNabidka);
        $nabidkaXML->addAttribute('operace', $akceExportu);

        $kategorie = [];
        if (isset($pole['kategorie'])) {
            $kategorie = $pole['kategorie'];
            unset($pole['kategorie']);
        }

        foreach ($pole as $id=>$text) {
            if ($text!=='') {
                if ($id=='popis') {
                    // ořízneme na 3000 znaků plus 20 jako rezerva
                    $text = $this->_cropText($text, 2880);
                } else {
                    $text = $this->_cropText($text, 980);
                }
                $nabidkaXML
                    ->addChild('pole', $this->_preparePoleValue($text))
                    ->addAttribute('id', $id);
            }
        }

        foreach ($kategorie as $idKategorie) {
            $nabidkaXML->addChild('kategorie')->addAttribute('id', $idKategorie);
        }


        foreach ($fotos as $foto) {
            $fotoXML = $nabidkaXML->addChild('foto');
            $fotoXML->addAttribute('id', $foto['md5']);
            $fotoXML->addAttribute('popis', $foto['popis']);
        }

        return $xml->getMultilineXml();
    }

    /**
     * Ořízne text na první mezeře po daném počtu znaků a na konec přidá trojtečku.
     *
     * @param string $text  Text k oříznutí.
     * @param int    $limit Limit počtu znaků.
     *
     * @return string Oříznutý text.
     */
    protected function _cropText($text, $limit)
    {
        $encoding = 'UTF-8';
        if (mb_strlen($text) > $limit) {
            // řežeme jen pokud přesáhne limit
            $prefix = mb_strcut($text, 0, $limit, $encoding);
            $suffix = mb_strcut($text, $limit, null, $encoding);
            if (preg_match('/\s+/u', $suffix) > 0) {
                // pokud část za limitem obsahuje mezeru ořízeneme na této mezeře
                preg_match('/(\S+)/u', $suffix, $matches);
                return $prefix . $matches[1] . '...';
            }
            // pokud za limitem mezera není ořízneme hned
            return $prefix . '...';
        }
        return $text;
    }

    /**
     * Připraví hodnotu pole na export.
     *
     * @param mixed $value Hodnota pole.
     *
     * @return string Hodnota pole připravená na export.
     */
    protected function _preparePoleValue($value)
    {
        if (is_float($value)) {
            return sprintf('%F', $value);
        }
        $value = str_replace('&', '&#38;', $value);
        return $this->_escapeQuotes($value);
    }

    /**
     * Ošetří uvozovky (přidá před ně zpětné lomítko).
     *
     * @param string $text Text na ošetření.
     *
     * @return string Ošetřený text.
     */
    protected function _escapeQuotes($text)
    {
        return str_replace(array('"', "'"), array('\"', "\\'"), $text);
    }

    /**
     * Vrací denní statistiky.
     *
     * POZOR!!! Nejnovější data, která je možné žádat jsou tři dny stará
     *
     * Viz https://import.ceskereality.cz/specifikace/#stat
     *
     * @param DateTime $day Datum ke kterému se statistiky vztahují.
     *
     * @return Dalten_Export_Api_ServerResponse Denní statistiky.
     */
    public function dailyStats(DateTime $day)
    {
        $serverResponse = $this->_backend->dailyStats($this->_accessToken, $this->_idFirmy, $day->format('Y-m-d'));
        return new Dalten_Export_Api_ServerResponse(
            $serverResponse['status'],
            $serverResponse['status'] ? 200 : 500, $serverResponse['msg'],
            isset($serverResponse['data']) ? $serverResponse['data'] : []
        );
    }

    /**
     * Stáhne dotazy k nabídkám.
     *
     * Viz https://import.ceskereality.cz/specifikace/#dotazy
     *
     * @param DateTime $day Den, ke kterým se dotazy vztahují.
     * @return Dalten_Export_Api_ServerResponse
     */
    public function dailyEnquiries(DateTime $day)
    {
        $serverResponse = $this->_backend->dailyEnquiries($this->_accessToken, $this->_idFirmy, $day->format('Y-m-d'));
        return new Dalten_Export_Api_ServerResponse(
            $serverResponse['status'],
            $serverResponse['status'] ? 200 : 500, $serverResponse['msg'],
            isset($serverResponse['data']) ? $serverResponse['data'] : []
        );
    }

    /**
     * {@inheritDoc}
     */
    public function listListings()
    {
        $serverResponse = $this->_backend->listListings($this->_accessToken, $this->_idFirmy);
        $output = [];
        if ($serverResponse['status']) {
            foreach ($serverResponse['data'] as $listing) {
                $output[] = [
                    'id' => $listing['id_inzeratu'],
                    'detailUrl' => $listing['url_inzeratu']
                ];
            }
        }

        return new Dalten_Export_Api_ServerResponse(
            $serverResponse['status'],
            $serverResponse['status'] ? 200 : 500, $serverResponse['msg'],
            $output
        );
    }

    /** {@inheritDoc} */
    public function topListing(array $listingData, array $additionalParams = array())
    {
        $idNabidka = $listingData['id'];

        $tempnam = tempnam(sys_get_temp_dir(), 'ceskereality');
        $xml = $this->_generateXML($idNabidka, 'TOP', [], []);
        file_put_contents($tempnam, $xml);
        $xmlUploaded = $this->_backend->uploadXml($this->_accessToken, $this->_idFirmy, $tempnam, 'nemovitosti.xml');

        if (!$xmlUploaded) return new Dalten_Export_Api_ServerResponse(false, 500, 'Nepodařilo se nahrát XML s nemovitostmi.');

        $xmlImported = $this->_backend->importXml($this->_accessToken, $this->_idFirmy);
        if ($xmlImported===false) {
            return new Dalten_Export_Api_ServerResponse(false, 500, 'Nabídku zatím nelze topovat, zkuste to později.');
        }

        $msg = isset($xmlImported['msg']) ? $xmlImported['msg'] : '';
        if (is_array($msg)) {
            $msg = implode('; ', $msg);
        }
        $response = new Dalten_Export_Api_ServerResponse(
            $xmlImported['status'], $xmlImported['status'] ? 200 : 500, $msg
        );
        return $response;
    }


}
