<?php
/**
 * A class for representing the http response information.
 *
 * This class acts as a gatherer for the headers, cookies and body meant for
 * output.
 */
class response
{
    /**
     * @var array The headers.
     */
    protected $header;
    
    /**
     * @var array The cookies.
     */
    protected $cookie;
    
    /**
     * @var string The body.
     */
    protected $body;

    ////////////////////////////////////////////////////////////////////////////
    // Construct and destruct functions.

    public function __construct()
    {
        $this->clear_header()
             ->clear_cookie();
    }

    ////////////////////////////////////////////////////////////////////////////
    // Overload functions.

    /**
     * Transforms the response into an associative array.
     *
     * @return array The array.
     */
    public function __toarray()
    {
        return get_object_vars($this);
    }
    
    /**
     * Gets the response body.
     *
     * @return string The body.
     */
    public function __tostring()
    {
        return (string) $this->body;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Interface functions.

    /**
     * Sends the response.
     *
     * @return response A fluent interface.
     */
    public function send()
    {
        foreach ($this->header as $h)
        {
            call_user_func_array('header', $h);
        }
        
        foreach ($this->cookie as $c)
        {
            call_user_func_array('setcookie', $c);
        }
        
        if ($this->body !== null)
        {
            echo $this->body;
        }
        
        return $this;
    }

    /**
     * Merges a response to itself.
     * 
     * @param response $response The response.
     * @return response A fluent interface.
     */
    public function merge(response $response)
    {
        $response = $response->__toarray();
        $this->header = array_merge($this->header, $response['header']);
        $this->cookie = array_merge($this->cookie, $response['cookie']);
        
        if ($response['body'] !== null)
        {
            $this->append($response['body']);
        }
        
        return $this;
    }

    /**
     * Sets the body.
     * 
     * @param string $body The body.
     * @return response A fluent interface.
     */
    public function set($body)
    {
        $this->body = $body;
        return $this;
    }
    
    /**
     * Prepends a part to the body.
     * 
     * @param string $part The part.
     * @return response A fluent interface.
     */
    public function prepend($part)
    {
        $this->body = $part . $this->body;
        return $this;
    }
    
    /**
     * Appends a part to the body.
     * 
     * @param string $part The part.
     * @return response A fluent interface.
     */
    public function append($part)
    {
        $this->body .= $part;
        return $this;
    }

    /**
     * Clears the body.
     * 
     * @return response A fluent interface.
     */
    public function clear()
    {
        $this->body = null;
        return $this;
    }

    /**
     * Sets a header.
     * 
     * @param string $header The header.
     * @param boolean (optional) $replace Whether it should replace a previous
     * similar header or not.
     * @param integer (optional) $code The http code.
     * @param string (optional) $name The header name.
     * @return response A fluent interface.
     */
    public function set_header($header, $replace = true, $code = null, $name = null)
    {
        $header = array($header, $replace);
        
        if ($code !== null)
        {
            $header[] = $code;
        }
        
        if ($name === null)
        {
            $this->header[] = $header;
        }
        else
        {
            $this->header[$name] = $header;
        }
        
        return $this;
    }

    /**
     * Clears a header.
     *
     * @param string (optional) $name The header name.
     * @return response A fluent interface.
     */
    public function clear_header($name = null)
    {
        if ($name === null)
        {
            $this->header = array();
        }
        else
        {
            unset($this->header[$name]);
        }
        
        return $this;
    }

    /**
     * Sets a cookie.
     * 
     * @param string $name The cookie name.
     * @param mixed $value The value.
     * @param integer (optional) $expire The lifespan in seconds.
     * @param string (optional) $path The path on the server in which the
     * it will be available on.
     * @param string (optional) $domain The domain that it is available on.
     * @param boolean (optional) $secure Whether it should only be transmitted
     * over a secure connection from the client or not.
     * @return response A fluent interface.
     */
    public function set_cookie($name, $value = null, $expire = 0, $path = '/', $domain = '', $secure = false)
    {
        $this->cookie[$name] = array($name, $value, $expire, $path, $domain, $secure);
        return $this;
    }

    /**
     * Clear a cookie.
     *
     * @param string (optional) $name The cookie name.
     * @return response A fluent interface.
     */
    public function clear_cookie($name = null)
    {
        if ($name === null)
        {
            $this->cookie = array();
        }
        else
        {
            unset($this->cookie[$name]);
        }
        
        return $this;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Internal functions.
}
