<?php
/**
 * core.framework
 *
 * @category  Core
 * @package   Core_Storage
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */

/**
 * @category  Core
 * @package   Core_Storage
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */
abstract class Core_Storage_Strategy_Abstract implements Core_Storage_Strategy_Interface
{
    /**
     * @var string
     */
    protected $_root;

    /**
     * @var string
     */
    protected $_urlRoot;

    /**
     * @var string
     */
    protected $_domain;

    /**
     * @var int
     */
    protected $_directoryMode = 0755;

    /**
     * @var string
     */
    protected $_fileMode = 0644;

    abstract protected function _has(Core_Storage_File $file);
    abstract protected function _fetch(Core_Storage_File $file);
    abstract protected function _store(Core_Storage_File $file);
    abstract protected function _remove(Core_Storage_File $file);

    /**
     * @param array|Zend_Config $options
     */
    public function __construct($options = null)
    {
        if (is_array($options)) {
            $this->setOptions($options);
        } elseif ($options instanceof Zend_Config) {
            $this->setConfig($options);
        }
    }

    /**
     * @return string
     */
    public function getRoot()
    {
        if (null === $this->_root) {
            throw new InvalidArgumentException('Unable to get storage root folder, root not set!');
        }
        return $this->_root;
    }

    /**
     * @param string $root
     *
     * @return Core_Storage_Strategy_Abstract
     */
    public function setRoot($root)
    {
        $this->_root = rtrim($root, '/');
        return $this;
    }

    /**
     * @return string
     * @throws InvalidArgumentException
     */
    public function getUrlRoot()
    {
        if (null === $this->_urlRoot) {
            throw new InvalidArgumentException('URL root not set');
        }

        return $this->_urlRoot;
    }

    /**
     * @param string $urlRoot
     *
     * @return Core_Storage_Strategy_Abstract
     */
    public function setUrlRoot($urlRoot)
    {
        $this->_urlRoot = rtrim($urlRoot, '/');
        return $this;
    }

    /**
     * Set domain
     *
     * - required to create Url to stored file
     * - examples for input: 'http://www.domain.com', 'https://cdn.microsoft.com'
     *
     * @param   string  $domain
     * @return \Core_Storage_Strategy_Abstract
     */
    public function setDomain($domain)
    {
        if (!preg_match('#//#', $domain)) {
            throw new InvalidArgumentException('Invalid domain specified: '. $domain);
        }
        $this->_domain = rtrim($domain, '/');
        return $this;
    }

    /**
     * Get domain
     *
     * @return string
     */
    public function getDomain()
    {
        if (null === $this->_domain) {
            throw new InvalidArgumentException('Error getting Storage domain, domain not set!');
        }
        return $this->_domain;
    }

    /**
     * Get directory mode
     *
     * @return int
     */
    public function getDirectoryMode()
    {
        return $this->_directoryMode;
    }

    /**
     * Set directory mode
     *
     * @param int $directoryMode
     *
     * @return Core_Storage_Strategy_Abstract
     */
    public function setDirectoryMode($directoryMode)
    {
        $this->_directoryMode = $directoryMode;
        return $this;
    }

    /**
     * Get file mode
     *
     * @return int
     */
    public function getFileMode()
    {
        return $this->_fileMode;
    }

    /**
     * Set file mode
     *
     * @param int $fileMode
     *
     * @return Core_Storage_Strategy_Abstract
     */
    public function setFileMode($fileMode)
    {
        $this->_fileMode = $fileMode;
        return $this;
    }

    /**
     * Set router options. Will skip "request", "pluginLoader", "currentRoute"
     * and "options".
     *
     * @param array $options
     *
     * @return Core_Storage_Strategy_Abstract
     * @throws InvalidArgumentException if an invalid option passed.
     */
    public function setOptions(Array $options)
    {
        $forbidden = array('Options', 'Config');

        foreach ($options as $key => $value) {
            $normalized = ucfirst($key);
            if (in_array($normalized, $forbidden)) {
                continue;
            }

            $method   = 'set' . $normalized;
            $callable = array($this, $method);
            if (is_callable($callable)) {
                call_user_func($callable, $value);
            } else {
                throw new InvalidArgumentException(sprintf('Invalid option "%s" passed', $key));
            }
        }
        return $this;
    }

    /**
     * @param Zend_Config $config
     *
     * @return Core_Storage_Strategy_Abstract
     */
    public function setConfig(Zend_Config $config)
    {
        return $this->setOptions($config->toArray());
    }

    /**
     * @param \Core_Storage_File|Core_File|$string $file
     *
     * @returns boolean
     */
    public function has($file)
    {
        return $this->_has($this->_normalize($file));
    }

    /**
     * @param \Core_Storage_File|Core_File|$string $file
     *
     * @returns \Core_Storage_File
     */
    public function fetch($file)
    {
        return $this->_fetch($this->_normalize($file));
    }

    /**
     * @param \Core_Storage_File|Core_File|$string $file
     *
     * @returns \Core_Storage_File
     */
    public function store($file)
    {
        return $this->_store($this->_normalize($file));
    }

    /**
     * @param \Core_Storage_File|Core_File|$string $file
     *
     * @returns boolean
     */
    public function remove($file)
    {
        return $this->_remove($this->_normalize($file));
    }

    /**
     * @param \Core_Storage_File|Core_File|$string $file
     *
     * @returns Core_Storage_File
     * @throws InvalidArgumentException
     */
    protected function _normalize($file)
    {
        if ($file instanceof Core_Storage_File) {
            return $file;
        } elseif (is_string($file)) {
            return new Core_Storage_File($file);
        } elseif ($file instanceof Core_File) {
            return new Core_Storage_File($file->getPath());
        }

        throw new InvalidArgumentException('Invalid file');
    }
}
