<?php
/**
 * Knihovna pro nahrávání souborů pomocí FTP protokolu.
 *
 * @category Dalten
 * @package  Ftp
 */
class Dalten_Ftp_Connector implements Dalten_Ftp_ConnectorInterface
{
	/**
	 * Pouzit zabezpecene spojeni.
	 *
	 * @var bool
	 */
	private $_useSecureConnection = false;

	/**
	 * Login uzivatele.
	 *
	 * @var string
	 */
	private $_username = '';

	/**
	 * Heslo uzivatele.
	 *
	 * @var string
	 */
	private $_password = '';

	/**
	 * IP nebo hostname.
	 *
	 * @var string
	 */
	private $_host = '';

	/**
	 * Cisloi portu.
	 *
	 * @var int
	 */
	private $_port = 21;

	/**
	 * Zdroj pripojeni.
	 *
	 * @var null|resource
	 */
	private $_connnection = null;

	/**
	 * Timeout.
	 *
	 * @var int
	 */
	private $_timeout = 30;

	/**
	 * Nastavit pasivní spojení?
	 *
	 * @var bool
	 */
	private $_pasiveConnection = true;

	/**
	 * Instance loggeru komunikace se serverem.
	 *
	 * @var Dalten_Export_Api_Backend_Logger_LoggerInterface
	 */
	private $_logger;


	/**
	 * Nastavi do objektu  prislusna data.
	 *
	 * @param string  $username            Login pro uzivatele.
	 * @param string  $password            Heslo uzivatel pod kterym se pripojujeme.
	 * @param string  $host                IP nebo host name kam se budeme pripojovat.
	 * @param integer $port                Port na kterem bezi ftp ci ftps servis.
	 * @param bool    $useSecureConnection Pouzivat zabezpecen spojeni? Pozor toto nastaveni musi host podporovat!!!
	 */
	public function __construct($username, $password, $host, $port = 21, $useSecureConnection = false)
	{
		$this->_username = (string) $username;
		$this->_password = (string) $password;
		$this->_host = (string) $host;
		$this->_useSecureConnection = (boolean) $useSecureConnection;
		$this->_port = (integer) $port;
	}

	/**
	 * Uzavre spojeni s ftp serverem.
	 */
	public function __destruct()
	{
		$connection = $this->_connnection; //aby se zbytečně při destruktu nepokoušel znova přihlásit
		if (is_resource($connection)) {
			ftp_close($connection);
		}
	}

	/**
	 * Vrati resource s pripojenim na ftp server.
	 *
	 * Pri prvni pozadavku, se spojeni vytvori s aktualnim nastavenim, takze na pozdejsi
	 * zmeny jiz nebude bran ohled.
	 *
	 * @return resource
	 *
	 * @throws Dalten_Ftp_Exception_Connect            Pokud se nepovede spojit se serverem.
	 * @throws Dalten_Ftp_Exception_BadLoginOrPassword Pokud se nepovede prihlasit pomoci loginu a hesla.
	 *
	 */
	public function getConnection()
	{
		if ($this->_connnection == null) {

			if ($this->_useSecureConnection) {
				$connection = ftp_ssl_connect($this->_host, $this->_port, $this->_timeout);
			} else {
				$connection = ftp_connect($this->_host, $this->_port, $this->_timeout);
			}

			if (!is_resource($connection)) {
				throw new Dalten_Ftp_Exception_Connect(
					sprintf('Spojeni na server %s se nezdarilo', $this->_host)
				);
			}
			if (!ftp_login($connection, $this->_username, $this->_password)) {
				throw new Dalten_Ftp_Exception_BadLoginOrPassword(
					sprintf('Neplatne prihlasovaci udaje na server %s', $this->_host)
				);
			}

			// Nastavíme/vypneme pasivní spojení.
			ftp_pasv($connection, $this->_pasiveConnection);

			$this->_connnection = $connection;
		}
		return $this->_connnection;
	}

	/**
	 * Nahraje soubor na ftp.
	 *
	 * @param mixed  $file        Cesta k lokalnimu souboru.
	 * @param string $destination Nazev souboru na serveru.
	 * @param int    $mode        Transfer mod.
	 * @param int    $startpos    Pozice v nahravanem souboru.
	 *
	 * @return bool
	 */
	public function put($file, $destination, $mode = FTP_ASCII, $startpos = 0)
	{
		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteCall($destination, $file);
		}

		$result = ftp_put(
			$this->getConnection(), (string) $destination, (string) $file, (integer) $mode, (integer) $startpos
		);

		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteResponse($destination, $result);
		}

		return $result;
	}

	/**
	 * Nahraje na server obsah do souboru.
	 *
	 * @param string $content     Obsah souboru.
	 * @param string $destination Nazev souboru na serveru.
	 * @param int    $mode        Transfer mod.
	 * @param int    $startpos    Pozice v nahravanem souboru.
	 *
	 * @return bool
	 */
	public function putContent($content, $destination, $mode = FTP_ASCII, $startpos = 0)
	{
		$file = new Dalten_File();
		$file->open()->write((string) $content);
		$file->rewind();

		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteCall($destination, $content);
		}

		$result = ftp_fput(
			$this->getConnection(), $destination, $file->getResource(), $mode, $startpos
		);

		if ($this->_logger instanceof Dalten_Export_Api_Backend_Logger_LoggerInterface) {
			$this->_logger->logRemoteResponse($destination, $result);
		}

		return $result;
	}

	/**
	 * Vrati hodnotu casu pro vyprseni spojeni.
	 *
	 * @return int
	 */
	public function getTimeout()
	{
		return $this->_timeout;
	}

	/**
	 * Nastavi cas vyprseni spojeni se serverem.
	 *
	 * @param int $timeout Cas pro vyprseni spojeni.
	 *
	 * @return Dalten_Ftp_Connector
	 */
	public function setTimeout($timeout)
	{
		$this->_timeout = (integer) $timeout;
		return $this;
	}

	/**
	 * Nastaví příznak, zda-li se má/nemá použít pasivní spojení se serverem.
	 *
	 * @param boolean $flag Má se použít pasivní spojení?
	 *
	 * @return Dalten_Ftp_Connector
	 */
	public function usePasiveConnection($flag)
	{
		$this->_pasiveConnection = (boolean) $flag;
		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 $this;
	}

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

		return $this;
	}
}
