<?php

namespace EesyPHP;

/**
 * URL request abstraction
 *
 * @author Benjamin Renard <brenard@easter-eggs.com>
 * @property-read string|null $current_url;
 * @property-read string|null $current_full_url;
 * @property-read array|null $handler;
 * @property-read bool|null $authenticated;
 * @property-read bool $api_mode;
 */
class UrlRequest {

  /**
   * The URL requested handler
   * @var string
   */
  private $current_url;

  /**
   * The URL requested handler
   * @var callable
   */
  private $handler;

  /**
   * Request need authentication ?
   * @var bool|null
   */
  private $authenticated = null;

  /**
   * API mode enabled ?
   * @var bool
   */
  private $api_mode;

  /**
   * Parameters detected on requested URL
   * @var array<string,mixed>
   */
  private $url_params = array();

  /**
   * Additional info pass when the URL handler was registered
   * @var array<string,mixed>
   */
  private $additional_info = array();

  public function __construct($current_url, $handler_info, $url_params=array()) {
    $this -> current_url = $current_url;
    $this -> handler = $handler_info['handler'];
    $this -> authenticated = (
      isset($handler_info['authenticated'])?
      $handler_info['authenticated']:null);
    $this -> api_mode = (
      isset($handler_info['api_mode'])?
      boolval($handler_info['api_mode']):false);
    $this -> url_params = $url_params;
    $this -> additional_info = (
        isset($handler_info['additional_info']) && is_array($handler_info['additional_info'])?
        $handler_info['additional_info']:array()
    );
  }

  /**
   * Get request info
   *
   * @param string $key The name of the info
   *
   * @return mixed The value
   **/
  public function __get($key) {
    if ($key == 'current_url')
      return $this -> current_url;
    if ($key == 'current_full_url')
      return Url::add_url_parameters($this -> current_url, $_GET, false);
    if ($key == 'handler')
      return $this -> handler;
    if ($key == 'authenticated')
      return (
        is_null($this -> authenticated)?
        Auth::enabled():
        (bool)$this -> authenticated
      );
    if ($key == 'api_mode')
      return $this -> api_mode;
    if ($key == 'referer')
      return $this -> get_referer();
    if ($key == 'http_method')
      return $_SERVER['REQUEST_METHOD'];
    if (array_key_exists($key, $this->url_params))
      return urldecode($this->url_params[$key]);
    if (array_key_exists($key, $this->additional_info))
      return urldecode($this->additional_info[$key]);
    // Unknown key, log warning
    Log :: warning(
      "__get($key): invalid property requested\n%s",
      Log :: get_debug_backtrace_context());
  }

  /**
   * Set request info
   *
   * @param string $key The name of the info
   * @param mixed $value The value of the info
   *
   * @return void
   **/
  public function __set($key, $value) {
    if ($key == 'referer')
      $_SERVER['HTTP_REFERER'] = $value;
    elseif ($key == 'http_method')
      $_SERVER['REQUEST_METHOD'] = $value;
    else
      $this->url_params[$key] = $value;
  }



  /**
   * Check is request info is set
   *
   * @param string $key The name of the info
   *
   * @return bool True is info is set, False otherwise
   **/
  public function __isset($key) {
    if (
      in_array(
        $key, array('current_url', 'handler', 'authenticated',
       'api_mode', 'referer', 'http_method')
      )
    )
      return True;
    return (
        array_key_exists($key, $this->url_params)
        || array_key_exists($key, $this->additional_info)
    );
  }

  /**
   * Get request parameter
   *
   * @param string $parameter The name of the parameter
   * @param bool $decode If true, the parameter value will be urldecoded
   *                     (optional, default: true)
   *
   * @return mixed The value or false if parameter does not exists
   **/
  public function get_param($parameter, $decode=true) {
    if (array_key_exists($parameter, $this->url_params)) {
      if ($decode)
        return urldecode($this->url_params[$parameter]);
      return $this->url_params[$parameter];
    }
    return false;
  }

  /**
   * Get request referer (if known)
   *
   * @return string|null The request referer URL if known, null otherwise
   */
  public function get_referer() {
    if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'])
      return $_SERVER['HTTP_REFERER'];
    return null;
  }

  /**
   * Check if current URL starts with the provided pattern
   * @param string $pattern  The lookuped pattern
   * @return boolean
   */
  public function current_url_starts_with($pattern) {
    if (!function_exists('str_starts_with'))
      return strpos($this->current_url, $pattern) === 0;
    return str_starts_with($this->current_url, $pattern);
  }

  /**
   * Check if current URL ends with the provided pattern
   * @param string $pattern  The lookuped pattern
   * @return boolean
   */
  public function current_url_ends_with($pattern) {
    if (!function_exists('str_ends_with'))
      return strpos($this->current_url, $pattern) === (strlen($this->current_url) - strlen($pattern));
    return str_ends_with($this->current_url, $pattern);
  }

  /**
   * Check if current URL matched with the provided pattern
   * @param string $pattern  A valid PREG pattern
   * @return boolean
   */
  public function current_url_match($pattern) {
    return boolval(preg_match($pattern, $this->current_url));
  }

}

# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
