<?php

namespace modules\input;

trait traits {

	public $__INPUT;

	protected function __construct() {
		if (!isset($this->__INPUT)) {
			if (!isset($GLOBALS['input_trait_info'])) {
				$GLOBALS['input_trait_info'] = new trait_info();
			}
			$this->__INPUT = $GLOBALS['input_trait_info'];
		}
	}
	
	protected function param($key = '', $default = NULL) {
		if (array_key_exists($key, $_GET)) {
			return trim($_GET[$key]);
		} else {
			return $default;
		}
	}
	
	protected function cookie($key, $default = NULL) {
	}

	protected function env($key, $default = NULL) {
	}

	protected function post(/* [$key [, $default] */) {
		$c = func_num_args();
		if (!$c) return $_POST;
		$default = ($c > 1) ? func_get_arg(1) : NULL;
		$key = func_get_arg(0);
		if (array_key_exists($key, $_POST)) {
			if (is_string($_POST[$key])) {
				return trim($_POST[$key]);
			} else {
				return $_POST[$key];
			}
		} else {
			return $default;
		}
	}
	
	protected function hostname($full = FALSE) {
		return $this->__INPUT->hostname($full);
	}

	protected function current_url() {
		return $this->__INPUT->CurrentUrl();
	}

	protected function method() {
		return $this->__INPUT->RequestMethod();
	}

	public function uri() {
		if (func_num_args()) {
			$this->__INPUT->BaseUri(func_get_arg(0));
			return $this;
		}
		return $this->__INPUT->BaseUri();
	}
	
	public function getClientIP() {
		return $this->__INPUT->getClientIP();
	}
	
	protected function request_uri() {
		return $this->__INPUT->request_uri();
	}
	
	protected function RetrieveSegments($uri = FALSE) {
		return $this->__INPUT->RetrieveSegments($uri);
	}
	
	protected function link() {
		$n = func_num_args();
		$res = call_user_func_array([$this->__INPUT, 'link'], func_get_args());
		return $n ? $this : $res;
	}
	
	public function BaseUrl() {
		if (func_num_args()) {
			$this->__INPUT->BaseUrl(func_get_arg(0));
			return $this;
		}
		return $this->__INPUT->BaseUrl();
	}
}


class trait_info {

	private $routes = [];
    private $hostname;
    private $FROM_SHELL;
    private $base_uri;
    private $base_url;
    private $current_url;
    private $request_method;
	public $accept_type;
	public $accept_lang;
	public $requested;

	public function __construct() {
		$this->hostname = @getenv('COMPUTERNAME');
		if (!empty($this->hostname)) {
			$this->hostname = strtolower(trim($this->hostname));		// Windows
		} else {
			$this->hostname = @getenv('HOSTNAME');
			if ($this->hostname === FALSE) {
				if (file_exists('/etc/hostname')) {
					$this->hostname = trim(file_get_contents('/etc/hostname'));
				} elseif (file_exists('/bin/uname')) {
					$this->hostname = trim(`/bin/uname -n`);
				} else {
					$this->hostname = trim(`/usr/bin/uname -n`);
				}
			}
		}

		$this->FROM_SHELL = isset($_SERVER['argc']);
		$this->base_uri = $this->_getURI();		// without querystring
		$scheme = isset($_SERVER['HTTPS']) ? strtolower($_SERVER['HTTPS']) : '';
		$scheme = ($scheme == 'on') ? 'https://' : 'http://';
		$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
		$this->base_url = $host;
        $host = $scheme . $host;
		$this->current_url = $host . $this->base_uri;
		$this->request_method = empty($_SERVER['REQUEST_METHOD']) ? 'GET' : $_SERVER['REQUEST_METHOD'];

		if ($this->FROM_SHELL) {		// not for php cgi
			for($i = 1; $i < $_SERVER['argc']; $i++) {
				$entry = $_SERVER['argv'][$i];
				if (($p = strpos($entry, '=')) !== FALSE) {
					$temp = trim(substr($entry, 0, $p));
                    if ($temp == 'PHPSESSID') {
						session_write_close();
                        @session_id(trim(substr($entry, $p + 1)));
                    } else {
                        $_GET[$temp] = trim(substr($entry, $p + 1));
                    }
				}
			}
		} elseif (!empty($_SERVER['QUERY_STRING'])) {
            parse_str($_SERVER['QUERY_STRING'], $temp);
            if (isset($temp['PHPSESSID']) && session_id() != $temp['PHPSESSID']) {
				session_write_close();
                session_id($temp['PHPSESSID']);
            }
        }

		$content_type = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '';
		if ($this->hasPostData() && strpos($content_type, '/json') !== FALSE) {		// Content-Type: application/json
			$inputJSON = file_get_contents('php://input');
			$_POST = json_decode( $inputJSON, TRUE );
		}
		$this->accept_type = empty($_SERVER['HTTP_ACCEPT']) ? 'text/html' : $_SERVER['HTTP_ACCEPT'];
		$this->accept_lang = empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? 'en;q=0.5' : $_SERVER['HTTP_ACCEPT_LANGUAGE'];
		$this->requested = empty($_SERVER['HTTP_X_REQUESTED_WITH']) ? '' : strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
	}

	private function _getURI() {
		$this_uri = $this->request_uri();
		if (($p = strpos($this_uri, '?')) !== FALSE) $this_uri = substr($this_uri, 0, $p);
		if (empty($this_uri)) $this_uri = $_SERVER['PHP_SELF'];	
		return str_replace('/index.php', '/', $this_uri);
	}
	
	public function isPost() {
		return $this->request_method == 'POST';
	}
	public function hasPostData() {
		return $this->request_method == 'POST' || $this->request_method == 'PUT'  || $this->request_method == 'PATCH';
	}
	
	public function getClientIP() {
		if (!empty($_SERVER['HTTP_CLIENT_IP'])){
			$x = $_SERVER['HTTP_CLIENT_IP'];
		} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
			$x =  $_SERVER['HTTP_X_FORWARDED_FOR'];
		} elseif (!empty($_SERVER['HTTP_X_FORWARDED'])){
			$x =  $_SERVER['HTTP_X_FORWARDED'];
		} elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])){
			$x =  $_SERVER['HTTP_FORWARDED_FOR'];
		} elseif (!empty($_SERVER['HTTP_FORWARDED'])){
			$x =  $_SERVER['HTTP_FORWARDED'];
		} elseif (!empty($_SERVER['REMOTE_ADDR'])){
			return $_SERVER['REMOTE_ADDR'];
		} else {
			return 'UNKNOWN';
		}
		// prevent injection attacks on text contained in http headers
		return str_replace(array('<', '|', '>', '&', ';', '`', '\\', '/'), '.', $x);
	}
	
	public function request_uri() {
		$request_url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';		// /controller/model
		if ($this->FROM_SHELL && isset($_GET['uri'])) {			// php index.php "uri=controller/function"
			$request_url = $_GET['uri'];
			if (substr($request_url, 0, 1) != '/') $request_url = '/' . $request_url;
		}
		return defined('URI') ? URI : $request_url;
	}
	
	public function retrieveSegments($request_url = FALSE) {
		// Get request url and script url
		if ($request_url === FALSE) $request_url = $this->request_uri();
		$script_url  = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '';			// /index.php

		// Get our url path and trim the / of the left and the right
		$url = '';
		if($request_url != $script_url) {
			$temp =  str_replace('index.php', '', $script_url);
			$url = trim(preg_replace('/'. str_replace('/', '\/', $temp) .'/', '', $request_url, 1), '/');
		}
		if (($p = strpos($url, '?')) !== FALSE) {			// drop Query_string, if present
			$url = substr($url, 0, $p);
		}
		return  explode('/', $url);
	}

	public function hostname($full = FALSE) {
        $url = $this->base_url;
        if ($full) {
            $host = isset($_SERVER['HTTPS']) ? strtolower($_SERVER['HTTPS']) : '';
            $host = ($host == 'on') ? 'https://' : 'http://';
            $url = $host . $url;
        }
		return $url;
	}

	public function BaseUrl() {
		if (func_num_args()) {
			$this->base_url = func_get_arg(0);
			return $this;
		}
		return $this->base_url;
	}

	public function BaseUri() {
		if (func_num_args()) {
			$this->base_uri = func_get_arg(0);
			return $this;
		}
		return $this->base_uri;
	}
    public function RequestMethod() {
		return $this->request_method;
    }
    public function CurrentUrl() {
		return $this->current_url;
    }
	
	protected function byPriority($list) {
		$optionlist = explode(',', $list);
		$output = [];
		foreach($optionlist as $langitem) {		// nl,en-us;q=0.7,en;q=0.3		// qualifier
			$elements = explode(';', $langitem);
			$langid = array_shift($elements);
			$langid = strtolower(trim($langid));
			$qualifier = '';
			$value = '1.0';
			foreach($elements as $element) {
				list($type, $x) = explode('=', trim($element), 2);
				if ($type == 'q') {
					$value = $x;
				}
			}
			if (!isset($output[$langid])) $output[$langid] = intval($value * 100);
		}
// sort by the qualifier
		asort($output, SORT_NUMERIC);
		$output = array_reverse($output);
		return $output;
	}
	
	// based on  accept_type
	public function GetPreferedDocType() {
		$v = $this->byPriority($this->accept_type);
		reset($v);
		$key = key($v);
		return $key;
	}

	public function getPreferedLanguage() {
		$v = $this->byPriority($this->accept_lang);
		reset($v);
		$key = key($v);
		return $key;
	}

    // convert {} into a pattern
    private function _link_macro($uri, $link) {
        $pattern = '';
        $fields = [];       // index => fieldname
        $x = preg_split('/(\{.*?\})/i', $uri, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
        foreach($x as $element) {
            if ($element[0] == '{') {
                $pattern .= '(.+?)';
                $fields[] = substr($element, 1, -1);
            } else {
                $pattern .= preg_quote($element);
            }
        }
        return [
            'uri' => $uri,
            'pattern' => $pattern,
            'mapping' => $fields,
            'callback' => $link,
        ];
    }
    
	// does not yet handle "/{variable}/" in uri
	public function link() {
		if (func_num_args()) {
			$uri = ltrim(strtolower(func_get_arg(0)), '/');
			$link = func_get_arg(1);
            $payload = $this->_link_macro($uri, $link);
			$this->routes[$uri] = $payload;
		}
		return $this->routes;
	}
	
}
