<?php namespace Intellex\Curly;

/**
 * The request manager.
 */
class Request {

	/** @var Method Method The HTTP method to use. */
	private $method;

	/** @var URL The target URL. */
	private $url;

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

	/** @var Content\Content The received content. */
	private $content;

	/** @var string[] The list of environment variables. */
	private $env = [];

	/** @var Request The singleton instance. */
	static private $instance = null;

	/**
	 * A hidden construct, as the Request should always be accessed as a singleton object.
	 */
	private function __construct() {

		# Get the environment and headers
		foreach ($_SERVER as $key => $value) {
			$this->env[$key] = $value;

			# Add the header
			if (substr($key, 0, 5) === 'HTTP_') {
				$this->headers[substr($key, 5)] = $value;
			}
		}

		# Skip for CLI calls
		if (!$this->isCli()) {

			# Get the method
			$this->method = Method::validate($this->env('REQUEST_METHOD'));

			# Get the URL
			$this->url = URL::create($this->env('SERVER_PROTOCOL'), $this->header('HOST'), $this->env('REQUEST_URI'));
		}

		# Get the content
		$this->content = new Content\Content(file_get_contents('php://input'), $this->env('CONTENT_TYPE'));
	}

	/**
	 * Get the value from the environment.
	 *
	 * @param string $key The requested key, as case-insensitive with space, minus or underline
	 *                    separated.
	 *
	 * @return string The requested value, or null if not found.
	 */
	public function env($key) {
		$key = static::key($key);
		return key_exists($key, $this->env) ? $this->env[$key] : null;
	}

	/**
	 * Get the header value.
	 *
	 * @param string $key The requested key, as case-insensitive  and space, minus or underline
	 *                    separated.
	 *
	 * @return string The requested value, or null if not found.
	 */
	public function header($key) {
		$key = static::key($key);
		return key_exists($key, $this->headers) ? $this->headers[$key] : null;
	}

	/**
	 * Check if the script is executed from cli.
	 *
	 * @return boolean True if we are in console line interface, false otherwise.
	 */
	public static function isCli() {
		return php_sapi_name() === 'cli';
	}

	/**
	 * Check if the current request is AJAX or not.
	 *
	 * @return boolean True if this call is ajax, false otherwise.
	 */
	public static function isAjax() {
		return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
	}

	/**
	 * Get the proper key, for the supplied one.
	 *
	 * @param string $key The requested key, as case-insensitive  and space, minus or underline
	 *                    separated.
	 *
	 * @return string The proper key format, uppercase and underscore separated.
	 */
	public static function key($key) {
		return strtoupper(str_replace([ ' ', '-' ], '_', $key));
	}

	/**
	 * Get the singleton instance.
	 *
	 * @return Request The singleton reference to the instance of the Request.
	 */
	public static function getInstance() {
		if (!static::$instance) {
			static::$instance = new Request();
		}

		return static::$instance;
	}

	/** @return Method Method The HTTP method to use. */
	public function getMethod() {
		return $this->method;
	}

	/** @return URL The target URL. */
	public function getURL() {
		return $this->url;
	}

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

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

	/** @return Content\Content The received content. */
	public function getContent() {
		return $this->content;
	}

	/** @return string[] The list of environment variables. */
	public function getEnvironment() {
		return $this->env;
	}

}
