<?php namespace Intellex\Curly;

/**
 * A single cookie.
 */
class Cookie {

	/** @var string The name of the cookie, converted to lowercase. */
	private $name;

	/** @var string Value of the cookie. */
	private $value;

	/** @var string Domain for which this cookie is valid. */
	private $domain;

	/** @var string Path for which this cookie is valid. */
	private $path;

	/** @var int The timestamp when this cookie expires. */
	private $expires;

	/** @var boolean True if the cookie must be secured (sent only over HTTPS). */
	private $secureOnly = false;

	/** @var boolean True if the the browser should not allow reading cookie from the javascript. */
	private $httpOnly = false;

	/** @var string String that separates elements from each other in raw the cookie string. */
	const ELEMENT_SEPARATOR = ';';

	/** @var string String that separates key from value in raw the cookie string. */
	const KEY_VALUE_SEPARATOR = '=';

	/**
	 * Initialize from the raw string.
	 *
	 * @param string $raw The raw cookie string, as received in the header.
	 */
	public function __construct($raw) {

		// Get elements
		$elements = static::extractElements($raw);

		// Set
		foreach ($elements as $i => $element) {
			list($name, $value) = static::splitElement($element);

			// Name
			if ($i === 0) {
				$this->name = $name;
				$this->value = $value;
				continue;
			}

			// Other
			$name = strtolower($name);
			switch ($name) {
				case 'domain':
					$this->domain = $value;
					break;

				case 'path':
					$this->path = $value;
					break;

				case 'expires':
					$this->expires = strtotime($value);
					break;

				case 'secure':
					$this->secureOnly = true;
					break;

				case 'httponly':
					$this->httpOnly = true;
					break;
			}
		}
	}

	/**
	 * Split the input by the cookie elements (using ';' character);
	 *
	 * @param string $input The raw cookie string, as received in the header.
	 *
	 * @return array The list of the elements.
	 */
	private static function extractElements($input) {
		$elements = explode(static::ELEMENT_SEPARATOR, $input);
		foreach ($elements as $i => $item) {
			$elements[$i] = trim($item);
		}

		return $elements;
	}

	/**
	 * Split the element to its key and value (using '=' character);
	 *
	 * @param string $element The element to split.
	 *
	 * @return array First element is the key, second is the value.
	 */
	private static function splitElement($element) {
		$value = null;

		// Has the value
		if (strstr($element, static::KEY_VALUE_SEPARATOR) !== false) {
			list($key, $value) = explode(static::KEY_VALUE_SEPARATOR, $element, 2);

			// No value
		} else {
			$key = $element;
		}

		return [ trim($key), trim($value) ];
	}

	/** @return string The name of the cookie, converted to lowercase. */
	public function getName() {
		return $this->name;
	}

	/** @return string Value of the cookie. */
	public function getValue() {
		return $this->value;
	}

	/** @return string Domain for which this cookie is valid. */
	public function getDomain() {
		return $this->domain;
	}

	/** @return string Path for which this cookie is valid. */
	public function getPath() {
		return $this->path;
	}

	/** @return int The timestamp when this cookie expires. */
	public function getExpiration() {
		return $this->expires;
	}

	/** @return boolean True if the cookie must be secured (sent only over HTTPS). */
	public function isSecureOnly() {
		return $this->secureOnly;
	}

	/** @return boolean True if the the browser should not allow reading cookie from the javascript. */
	public function isHttpOnly() {
		return $this->httpOnly;
	}

}
