<?php 

namespace System;

class Response{

    /**
     * The final output
     *
     * @var string
     */
    public $output;

    /**
     * The response status
     *
     * @var int
     */
    public $status = 200;

    /**
     * Array of headers to be sent
     *
     * @var array
     */
    public $headers = array();

    /**
     * Create a new instance of the Response class for chaining
     *
     * @param string
     * @param int
     * @param array
     * @return object
     */
    public static function create($output, $status = 200, $headers = array())
    {
        return new static($output, $status, $headers);
    }

    /**
     * Creates a response with a header to redirect
     *
     * @param string
     * @param int
     * @return object
     */
    public static function redirect($uri, $status = 302)
    {
        // Scrub all output buffer before we redirect.
        // @see http://www.mombu.com/php/php/t-output-buffering-and-zlib-compression-issue-3554315-last.html
        while (ob_get_level() > 1) {
            ob_end_clean();
        }

        return static::create('', $status, array('Location' => Uri::to($uri)));
    }

    /**
     * Creates a response with the output as error view from the app
     * along with the status code
     *
     * @param int
     * @return object
     */
    public static function error($status, $vars = array())
    {
        ob_start();
         require PATH.'views/error/'.$status.EXT;
        $data = ob_get_clean();

        return static::create($data, $status);
    }

    /**
     * Creates a response with the output as JSON
     *
     * @param string
     * @param int
     * @return object
     */
    public static function json($output, $status = 200)
    {
        return static::create(json_encode($output), $status,
            array('content-type' => 'application/json; charset=' . Config::app('encoding')));
    }

    /**
     * Create a new instance of the Response class
     *
     * @param string
     * @param int
     * @param array
     */
    public function __construct($output, $status = 200, $headers = array())
    {
        $this->status = $status;
        $this->output = $output;

        foreach ($headers as $name => $value) {

            $this->headers[strtolower($name)] = $value;
        }

        // output data
        $this->send();

        die();
    }

    /**
     * Sends the final headers cookies and output
     */
    public function send() {
        // create a status header
        $this->header();

        // always make sure we send the content type
        if( ! array_key_exists('content-type', $this->headers)) {
            $this->headers['content-type'] = 'text/html; charset=' . Config::app('encoding');
        }

        // output headers
        foreach($this->headers as $name => $value) {
            header($name . ': ' . $value);
        }
        // output final content
        echo $this->output;
    }

    /**
     * Array or possible server status responses
     *
     * @var array
     */
    public $messages = array(
        100 => 'Continue',
        101 => 'Switching Protocols',
        200 => 'OK',
        201 => 'Created',
        202 => 'Accepted',
        203 => 'Non-Authoritative Information',
        204 => 'No Content',
        205 => 'Reset Content',
        206 => 'Partial Content',
        207 => 'Multi-Status',
        300 => 'Multiple Choices',
        301 => 'Moved Permanently',
        302 => 'Found',
        303 => 'See Other',
        304 => 'Not Modified',
        305 => 'Use Proxy',
        307 => 'Temporary Redirect',
        400 => 'Bad Request',
        401 => 'Unauthorized',
        402 => 'Payment Required',
        403 => 'Forbidden',
        404 => 'Not Found',
        405 => 'Method Not Allowed',
        406 => 'Not Acceptable',
        407 => 'Proxy Authentication Required',
        408 => 'Request Timeout',
        409 => 'Conflict',
        410 => 'Gone',
        411 => 'Length Required',
        412 => 'Precondition Failed',
        413 => 'Request Entity Too Large',
        414 => 'Request-URI Too Long',
        415 => 'Unsupported Media Type',
        416 => 'Requested Range Not Satisfiable',
        417 => 'Expectation Failed',
        422 => 'Unprocessable Entity',
        423 => 'Locked',
        424 => 'Failed Dependency',
        500 => 'Internal Server Error',
        501 => 'Not Implemented',
        502 => 'Bad Gateway',
        503 => 'Service Unavailable',
        504 => 'Gateway Timeout',
        505 => 'HTTP Version Not Supported',
        507 => 'Insufficient Storage',
        509 => 'Bandwidth Limit Exceeded'
    );

    /**
     * Send the status header
     */
    public function header() {
        // status message
        $message = $this->messages[$this->status];

        // for fastcgi we have to send a status header like so:
        // http://php.net/manual/en/function.header.php
        if(strpos(PHP_SAPI, 'cgi') !== false) {
            header('Status: ' . $this->status . ' ' . $message);
        }
        // overwise we just send a normal status header
        else {
            header($_SERVER['SERVER_PROTOCOL'] . ' ' . $this->status .  ' ' . $message);
        }
    }

}
