<?php
/**
 * Implementace HTTP klienta.
 *
 * @category Dalten
 * @package  Http
 */
class Dalten_Http_Client implements Dalten_Http_ClientInterface, Dalten_Export_Api_Backend_LoggableBackendInterface
{
	/** @var Dalten_Export_Api_Backend_Logger_LoggerInterface */
	private $_logger;

	private $_usename = null;
	private $_password = null;

	private $_headers = array();

	// zapsány jen ty co potřebujeme
	private $_mimeTypesExtensions = array(
		'xml' => 'text/xml',
		'jpg' => 'image/jpeg',
		'jpeg' => 'image/jpeg'
	);

	/**
	 * Stáhne obsah z URL metodou GET.
	 *
	 * @param string $url URL kterou chceme stáhnout.
	 *
	 * @return string Stažený obsah.
	 */
	public function get($url)
	{
		$headers = $this->_getHeaders();

		$afterPart = '';
		$urlParts = explode('?', $url);
		if (isset($urlParts[1])) {
			$afterPart = $urlParts[1];
		}


		if ($this->_logger) {
			$this->_logger->logRemoteCall(
				'GET ' . $urlParts[0],
				'?' . $afterPart . PHP_EOL . PHP_EOL . implode(PHP_EOL, $headers)
			);
		}
		$connection = curl_init((string) $url);
		curl_setopt($connection, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($connection, CURLOPT_HTTPHEADER, $headers);
		if (class_exists('Composer\CaBundle\CaBundle')) {
            curl_setopt($connection, CURLOPT_CAINFO, \Composer\CaBundle\CaBundle::getBundledCaBundlePath());
        }
		curl_setopt($connection, CURLOPT_TIMEOUT, 60);
		$response = curl_exec($connection);
		$error = curl_error($connection);
		curl_close($connection);
		if ($this->_logger) {
            if ($error) {
                $this->_logger->logRemoteResponse('GET ' . $urlParts[0], 'CURL ERROR: ' . $error);
            } else {
                $this->_logger->logRemoteResponse('GET ' . $urlParts[0], $response);
            }
		}
		return $response;
	}

	/**
	 * Pošle data na URL metodou POST, jako kdyby se posílal formulář.
	 *
	 * @param string $url   URL kam chceme posílat.
	 * @param array  $data  Pole dat která chceme poslat.
	 * @param array  $files Pole absolutních cest k souborům na odeslání. Nemusí být vyplněno.
	 *
	 * @return string Co vrátil server.
	 */
	public function post($url, array $data, $files = array())
	{
		$headers = $this->_getHeaders();
		$connection = curl_init((string) $url);
		curl_setopt($connection, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($connection, CURLOPT_HTTPHEADER, $headers);
        if (class_exists('Composer\CaBundle\CaBundle')) {
            curl_setopt($connection, CURLOPT_CAINFO, \Composer\CaBundle\CaBundle::getBundledCaBundlePath());
        }
        curl_setopt($connection, CURLOPT_TIMEOUT, 60);

		if (count($files) > 0) {
			// pokud posíláme soubory, použijeme multipart/form-data
			$postData = $data;
			foreach ($files as $fileKey => $fileName) {
			    if (is_object($fileName) && $fileName instanceof CURLFile) {
                    $postData[$fileKey] = $fileName;
                } elseif (file_exists($fileName)) {
					$mime = '';
					// pokud najdeme MIME type posíláme ho, jinak nic neposíláme, protože to je tak správně
					$ext = pathinfo($fileName, PATHINFO_EXTENSION);
					if (isset($ext) && isset($this->_mimeTypesExtensions[$ext])) {
						$mime = $this->_mimeTypesExtensions[$ext];
					}
					if (class_exists('CURLFile', false)) {
					    $postData[$fileKey] = new CURLFile($fileName, $mime ?: null);
                    } else {
					    if ($mime) {
					        $mime = ';type=' . $mime;
                        }
					    $postData[$fileKey] = '@' . $fileName . $mime;
                    }

				}
			}
		} else {
			//jinak se použije application/x-www-form-urlencoded
			$postData = http_build_query($data);
		}
		curl_setopt($connection, CURLOPT_POSTFIELDS, $postData);
		if ($this->_logger) {
			$this->_logger->logRemoteCall(
				'POST '.$url,
				implode(PHP_EOL, $headers) . PHP_EOL . PHP_EOL . var_export($postData, true)
			);
		}
		$response = curl_exec($connection);
		$error = curl_error($connection);
		curl_close($connection);
		if ($this->_logger) {
		    if ($error) {
                $this->_logger->logRemoteResponse('POST '. $url, 'CURL ERROR: ' . $error);
            } else {
                $this->_logger->logRemoteResponse('POST '. $url, $response);
            }
		}
		return $response;
	}


	/**
	 * Nastaví uživatelské jméno a heslo pro zaheslované stránky.
	 *
	 * @param string $login    Uživatelské jméno.
	 * @param string $password Heslo.
	 *
	 * @return Dalten_Http_ClientInterface Fluent interface.
	 */
	public function setAuth($login, $password)
	{
		$this->_usename = $login;
		$this->_password = $password;
		return $this;
	}

	/**
	 * Nastaví HTTP hlavičku posílanou tímto HTTP klientem.
	 *
	 * POZOR! Pokud se používá autorizace, přidává vlastní hlavičku.
	 *
	 * @param string      $name  Jméno HTTP hlavičky.
	 * @param string|null $value Obsah HTTP hlavičky. Pokud není vyplněno, klient hlavičku odnastaví.
	 *
	 * @return Dalten_Http_ClientInterface Fluent interface.
	 */
	public function setHeader($name, $value = null)
	{
		if (is_null($value)) {
			unset($this->_headers[$name]);
		} else {
			$this->_headers[$name] = $value;
		}
		return $this;
	}


	/**
	 * 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)
	{
		$this->_logger = $logger;
		return true;
	}

	/**
	 * Odstraní nastavený logger pro backend.
	 *
	 * @return Dalten_Export_Api_LoggableApiInterface Fluent interface.
	 */
	public function removeLogger()
	{
		$this->_logger = null;
		return $this;
	}

	/**
	 * Vrátí hlavičky pro request.
	 *
	 * @return array
	 */
	private function _getHeaders()
	{
		$headers = array();
		foreach ($this->_headers as $name=>$value) {
			$headers[] = sprintf('%s: %s', $name, $value);
		}

		if ($this->_usename && $this->_password) {
			$headers[] = 'Authorization: Basic ' . base64_encode($this->_usename.':'.$this->_password);
		}

		return $headers;
	}

}
