<?php namespace Intellex\Curly;

use Intellex\Curly\Content\Type;

/**
 * The response from the Curl.
 */
class Response {

	/** @var int The response code. */
	private $code;

	/** @var Type The content type, as sent from the server. */
	private $contentType;

	/** @var string The raw received content. */
	private $content;

	/** @var string[] The list of received HTTP headers. */
	private $headers = [];

	/** @var Cookie[] The received cookies. */
	private $cookies = [];

	/** @var string The raw data, including headers. */
	private $raw;

	/**
	 * Create an instance of the response.
	 *
	 * @param string $response The complete response from the remote.
	 * @param array  $info     The curl info.
	 */
	public function __construct($response, array $info) {
		$this->raw = $response;

		// Get the content
		list($headers, $this->content) = explode("\r\n\r\n", $response, 2);

		// Extract headers and cookies
		list($this->headers, $this->cookies) = static::extractHeadersAndCookies($headers);

		// From info
		$this->code = $info['http_code'];
		$this->contentType = Type::init($info['content_type']);
	}

	/**
	 * Extract the headers and cookies from the supplied raw headers.
	 *
	 * @param string $header The received raw header.
	 *
	 * @return array The associative array of headers.
	 */
	private static function extractHeadersAndCookies($header) {
		$headers = $cookies = [];

		// Extract
		$list = explode("\r\n", $header);
		foreach ($list as $i => $line) {

			// Skip first line (HTTP response code)
			if ($i && strstr($line, ':')) {

				// Split
				list($name, $value) = explode(':', $line, 2);
				$name = static::normalize($name);
				$value = trim($value);

				// Cookie
				if ($name === 'Set-Cookie') {
					$cookie = new Cookie($value);
					$cookies[$cookie->getName()] = $cookie;

					// Header
				} else {
					$headers[$name] = $value;
				}
			}
		}

		return [ $headers, $cookies ];
	}

	/**
	 * Normalize the header name.
	 *
	 * @param string $name The original name.
	 *
	 * @return string The normalized header.
	 */
	private static function normalize($name) {
		return str_replace(' ', '-', ucwords(preg_replace('~[_\s-]+~', ' ', strtolower($name))));
	}

	/** @return int The response code. */
	public function getCode() {
		return $this->code;
	}

	/** @return Type The content type, as sent from the server. */
	public function getContentType() {
		return $this->contentType;
	}

	/** @return mixed The received data. */
	public function getContent() {
		return $this->contentType->parse($this->content);
	}

	/** @return string The received data. */
	public function getRawData() {
		return $this->content;
	}

	/** @return string[] The list of received HTTP headers. */
	public function getHeaders() {
		return $this->headers;
	}

	/**
	 * @param string $name Name of the header to get the value for.
	 *
	 * @return string|null A single header, by its name.
	 */
	public function getHeader($name) {
		return key_exists($name, $this->headers) ? $this->headers[$name] : null;
	}

	/** @return Cookie[] The received cookies. */
	public function getCookies() {
		return $this->cookies;
	}

	/**
	 * @param string $name Name of the cookie to get the value for.
	 *
	 * @return Cookie A single cookie, by its name.
	 */
	public function getCookie($name) {
		return key_exists($name, $this->cookies) ? $this->cookies[$name] : null;
	}

	/** @return string The raw data, including headers. */
	public function getRaw() {
		return $this->raw;
	}

}
