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

/**
 * @category  Core
 * @package   Core_Embed
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */
class Core_Embed_Response
{
    const PROPERTY_TYPE = 'type';
    
    const TYPE_LINK     = 'link';
    const TYPE_IMAGE    = 'image';
    const TYPE_AUDIO    = 'audio';
    const TYPE_VIDEO    = 'video';
        
    /**
     * @var array
     */
    protected $_headers = array(
        Core_Embed::FORMAT_JSON => 'application/json',
        Core_Embed::FORMAT_XML  => 'text/xml',
    );

    /**
     * @var array
     */
    protected $_data = array();

    /**
     * @var string
     */
    protected $_format = Core_Embed::FORMAT_JSON;
    
    /**
     * @var string
     */
    protected $_canonical;

    /**
     * @param Zend_Http_Response|array $response
     */
    public function __construct($response)
    {
        if ($response instanceof Zend_Http_Response) {
            $data = $this->_parseResponse($response);
            if (is_array($data)) {
                $this->setData($data);
            }
        } else if (is_array($response)) {
            $this->setData($response);
        } else {
            // TODO
            // throw new InvalidArgumentException here
        }
    }

    /**
     * @param string $format
     *
     * @return \Core_Embed_Response
     */
    public function setFormat($format)
    {
        $this->_format = $format;
        return $this;
    }

    /**
     * @return string
     */
    public function getFormat()
    {
        return $this->_format;
    }

    /**
     * @param array $data
     *
     * @return \Core_Embed_Response
     */
    public function setData(array $data)
    {
        foreach ($data as $key => $value) {
            $this->set($key, $value);
        }
        return $this;
    }

    /**
     * @param type $key   Property name
     * @param type $value Property value
     *
     * @return \Core_Embed_Response
     */
    public function set($key, $value)
    {
        $key = strtolower($key);
        
        $this->_data[$key] = $this->_normalize($key, $value);
        return $this;
    }

    /**
     * @param type $key   Property name
     * @param type $value Property value
     * 
     * @return type
     */
    public function __set($key, $value)
    {
        return $this->set($key, $value);
    }

    /**
     * @param type $key
     *
     * @return mixed|null
     */
    public function get($key)
    {
        $key = strtolower($key);
        if (array_key_exists($key, $this->_data)) {
            return $this->_data[$key];
        }
        return null;
    }

    /**
     * @param type $key
     *
     * @return mixed|null
     */
    public function __get($key)
    {
        return $this->get($key);
    }
    
    /**
     * @param string $format
     * 
     * @return string
     */
    public function render($format = null)
    {
        if (null === $format) {
            $format = $this->getFormat();
        }
        
        switch ($format) {
            case Core_Embed::FORMAT_XML:
                $xml = new XMLWriter;
                $xml->openMemory();
                $xml->startDocument('1.0', 'UTF-8');
                $xml->startElement('embed');
                foreach($this->_data as $key => $value) {
                    $xml->startElement($key);
                    $xml->text($value);
                    $xml->endElement();
                }
                $xml->endElement();
                $xml->endDocument();
                
                return $xml->outputMemory();
                break;
            default:
            case Core_Embed::FORMAT_JSON:
                return json_encode($this->_data);
        }
    }
    
    /**
     * @return string
     */
    public function __toString()
    {
        try {
            $format = $this->getFormat();
            header(sprintf('Content-Type: %1$s; charset=UTF-8', $this->_headers[$format]));
            
            return $this->render($format);
        } catch (Exception $e) {
            $message = "Exception caught: " . $e->getMessage()
                     . "\nStack Trace:\n" . $e->getTraceAsString();
            trigger_error($message, E_USER_WARNING);
            return '';
        }
    }

    /**
     * @return array
     */
    public function toArray()
    {
        return $this->_data;
    }

    /**
     * @param Zend_Http_Response $response
     *
     * @return boolean(false)|array
     */
    protected function _parseResponse(Zend_Http_Response $response)
    {
        $parsed = false;
        if ($response->isSuccessful()) {
            $type = strtolower($response->getHeader('Content-Type'));
            if (false !== ($idx = strpos($type, ';'))) {
                $type = substr($type, 0, $idx);
            }
            $body = $response->getBody();
            switch (trim($type)) {
                case $this->_headers[Core_Embed::FORMAT_JSON]:
                    $parsed = json_decode($body, true);
                    break;
                case $this->_headers[Core_Embed::FORMAT_XML]:
                    // will try to parse this XML
                    $parsed = simplexml_load_string($body, 'SimpleXMLElement', LIBXML_NOERROR);
                    break;
            }

            // cast to array if not false (as in, failed to parse)
            if (false !== $parsed) {
                $parsed = (array) $parsed;
            }
        }
        return $parsed;
    }
    
    /**
     * @param string $name
     * @param string $value
     * 
     * @return string
     */
    protected function _normalize($name, $value)
    {
        switch($name) {
            case self::PROPERTY_TYPE:
                $value = $this->_normalizeType($value);
                break;
        }
        return $value;
    }

    /**
     * @param string $value
     * 
     * @return string
     */
    protected function _normalizeType($value)
    {
        $value = strtolower($value);
        if (preg_match('/([^:]+:)?(?P<type>[^.]+)/', $value, $matches)) {
            $value = $matches['type'];
        }
        switch ($value) {
            case 'video':
            case 'media':
                $value = self::TYPE_VIDEO;
                break;
            case 'sound':
            case 'audio':
                $value = self::TYPE_AUDIO;
                break;
            case 'image':
            case 'photo':
                $value = self::TYPE_IMAGE;
                break;
            default:
            case 'link':
                $value = self::TYPE_LINK;

        }
        return $value;
    }
}
