<?php 
// namespace core;
/*
* Router - routing URL's to closures and controllers
* FUCK but should work... i love myself :)
*/

//namespace core;
/**
* Router - routing URL's to closures and controllers
*/

class Router extends Language{

	public static $halts = true;
	public static $routes = array();
	public static $methods = array();
	public static $callbacks = array();
	public static $language = array('en','he');
	public static $patterns = array(
		':any' => '[^/]+',
		':num' => '[0-9]+',
		':all' => '.*'
	);
	public static $error_callback;

	/**
	 * Defines a route w/ callback and method
	 */
	public static function __callstatic($method, $params){
		$uri = dirname($_SERVER['PHP_SELF']).'/'.$params[0];
		$callback = $params[1];
		// error_log(' __callstatic the URI : '.$uri);
		// error_log(' __callstatic the callback : '.$callback);
		// error_log(' __callstatic the method : '.$method);
		array_push(self::$routes, $uri);
		array_push(self::$methods, strtoupper($method));
		array_push(self::$callbacks, $callback);
	}

	/**
	 * Defines callback if route is not found
	*/
	public static function error($callback){
		self::$error_callback = $callback;
	}

	public static function haltOnMatch($flag = true){
		self::$halts = $flag;
	}

	/**
	 * Runs the callback for the given request
	 */
	public static function dispatch(){
		//Language::set();
		$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
		//error_log(' request lang uri : '.$_SERVER['REQUEST_URI']);
		$lang = explode("/",$uri);
		
		// error_log(print_r( $lang, true ));
		if(in_array($lang[1],self::$language)){
			// error_log('found language');
			Language::set($lang[1]);
			$uri = str_replace($lang[1],"",$uri);
		}else{
			Language::set(self::$language[0]);
			$uri = str_replace("/".self::$language[0],"",$uri);
		}
			$uri = str_replace('//','/',$uri);
		//error_log(' request uri : '.$uri);
		// error_log(' pHP_URL_PATH : '.PHP_URL_PATH);
		// error_log(' parse url : '.$uri);
		$method = $_SERVER['REQUEST_METHOD'];
		//error_log(' server request method : '.$method);  
		$searches = array_keys(static::$patterns);
		$replaces = array_values(static::$patterns);
		self::$routes = str_replace('//','/',self::$routes);
		$found_route = false;
		// check if route is defined without regex
		if (in_array($uri, self::$routes)){
			$route_pos = array_keys(self::$routes, $uri);
			foreach ($route_pos as $route){
				if (self::$methods[$route] == $method || self::$methods[$route] == 'ANY') {
					$found_route = true;
					//if route is not an object 
					if(!is_object(self::$callbacks[$route])){
						$parts = explode('@',self::$callbacks[$route]);
						$file = strtolower(CONTROLLER_PATH.$parts[0].'.php'); 
						//try to load and instantiate model
						if(file_exists($file)){
							require $file;
						}
						//grab all parts based on a / separator 
						$parts = explode('/',self::$callbacks[$route]);
						//error_log(' dispatch static ');
						// error_log(var_dump($parts));
						//collect the last index of the array
						$last = end($parts);
						//grab the controller name and method call
						$segments = explode('@',$last);
						//instanitate controller
						$controller = new $segments[0]();
						//call method
						$controller->$segments[1]();
						if(self::$halts) return;
					}else{
						//call closure
						call_user_func(self::$callbacks[$route]);
						if(self::$halts) return;
					}
				}
			}
		} else {
			// check if defined with regex
			$pos = 0;
			foreach (self::$routes as $route) {
				$route = str_replace('//','/',$route);
			//error_log(' the route : '.$route);
				if(strpos($route, ':') !== false){
					$route = str_replace($searches, $replaces, $route);
				}
				if(preg_match('#^' . $route . '$#', $uri, $matched)){
					if(self::$methods[$pos] == $method || self::$methods[$pos] == 'ANY') {
						$found_route = true; 
						array_shift($matched); //remove $matched[0] as [1] is the first parameter.
						if(!is_object(self::$callbacks[$pos])){
							$parts = explode('@',self::$callbacks[$pos]);
							
						// error_log(' dispatch regex ');
						// error_log(' parts  0 :'.$parts[0].' parts 1 : '.$parts[1]);
							$file = strtolower(CONTROLLER_PATH.$parts[0].'.php');
							//try to load and instantiate model
							if(file_exists($file)){
								require $file;
							}
							//grab all parts based on a / separator 
							$parts = explode('/',self::$callbacks[$pos]);
							//collect the last index of the array
							$last = end($parts);
							//grab the controller name and method call
							$segments = explode('@',$last); 
							//instanitate controller
							$controller = new $segments[0]();
							$params = count($matched);
							//call method and pass any extra parameters to the method
							//$controller->$segments[1](implode(",", $matched));
							//call method and pass in array keys as params
							//call_user_func_array(array($controller, $segments[1]), $matched);
							switch ($params) {
								case '0':
									$controller->$segments[1]();
									break;
								case '1':
									$controller->$segments[1]($matched[0]);
									break;
								case '2':
									$controller->$segments[1]($matched[0],$matched[1]);
									break;
								case '3':
									$controller->$segments[1]($matched[0],$matched[1],$matched[2]);
									break;
								case '4':
									$controller->$segments[1]($matched[0],$matched[1],$matched[2],$matched[3]);
									break;
								case '5':
									$controller->$segments[1]($matched[0],$matched[1],$matched[2],$matched[3],$matched[4]);
									break;
								case '6':
									$controller->$segments[1]($matched[0],$matched[1],$matched[2],$matched[3],$matched[4],$matched[5]);
									break;
								case '7':
									$controller->$segments[1]($matched[0],$matched[1],$matched[2],$matched[3],$matched[4],$matched[5],$matched[6]);
									break;
							}
							if (self::$halts) return;
						} else {
							call_user_func_array(self::$callbacks[$pos], $matched);
							if (self::$halts) return;
						}
					}
				}
			$pos++;
			}
		}
		// run the error callback if the route was not found
		if ($found_route == false) {
			if (!self::$error_callback) {
				self::$error_callback = function() {
					header($_SERVER['SERVER_PROTOCOL']." 404 Not Found");
					echo '404';
				};
			}
			$parts = explode('@',self::$error_callback);
			$file = strtolower(CONTROLLER_PATH.$parts[0].'.php');
			//try to load and instantiate model     
			if(file_exists($file)){
				require $file;
			}
			if(!is_object(self::$error_callback)){
				//grab all parts based on a / separator 
				$parts = explode('/',self::$error_callback);
				//collect the last index of the array
				$last = end($parts);
				//grab the controller name and method call
				$segments = explode('@',$last);
				//instanitate controller
				$controller = new $segments[0]('No routes found.');
				//call method
				$controller->$segments[1]();
				if (self::$halts) return;
			} else {
			   call_user_func(self::$error_callback);
			   if (self::$halts) return;
			}
		}
	}
}

// class Router{
	// // Fall-back for auto dispatching feature.
	// public static $fallback = false;
	// // If true - do not process other routes when match is found
	// public static $halts = true;
	// // Set routes, methods and etc.
	// public static $routes = array();
	// public static $methods = array();
	// public static $callbacks = array();
	// public static $error_callback;
	// // Set route patterns
	// public static $patterns = array(
		// ':any' => '[^/]+',
		// ':num' => '[0-9]+',
		// ':all' => '.*'
	// );

	// /**
	// * Defines a route with / callback and method
	// * @param string $method
	// * @param array @params
	// */
	// public static function __callstatic($method, $params){
		// $uri = dirname($_SERVER['PHP_SELF']).'/'.$params[0];
		// $callback = $params[1];
		// array_push(self::$routes, $uri);
		// array_push(self::$methods, strtoupper($method));
		// array_push(self::$callbacks, $callback);
	// }

	// /**
	// * Defines callback if route is not found
	// * @param string $callback
	// */
	// public static function error($callback){
		// self::$error_callback = $callback;
	// }

	// /**
	// * Don't load any further routes on match
	// * @param boolean $flag 
	// */
	// public static function haltOnMatch($flag = true){
		// self::$halts = $flag;
	// }

	// /**
	// * Call object and instantiate it
	// * @param object $callback 
	// * @param array $matched array of matched parameters
	// * @param string $msg      
	// */
	// public static function invokeObject($callback,$matched = null,$msg = null){
		// //grab all parts based on a / separator and collect the last index of the array
		// $last = explode('/',$callback);
		// $last = end($last);
		// //grab the controller name and method call
		// $segments = explode('@',$last);
		// //instantiate controller with optional msg (used for error_callback)
		// $controller = new $segments[0]($msg);
		// if($matched == null){
			// //call method
			// $controller->$segments[1]();
		// } else {
			// //call method and pass in array keys as parameters
			// call_user_func_array(array($controller, $segments[1]), $matched);
		
		// }
	// }

	// /**
	// * autoDispatch an ability to call controllers in their controller/model/param way
	// */
	// public static function autoDispatch(){
		// $uri = parse_url($_SERVER['QUERY_STRING'], PHP_URL_PATH);
		// $uri = trim($uri, ' /');
		// $parts = explode('/', $uri);
		// $controller = $uri !== ''      && isset($parts[0])  ? $parts[0] : DEFAULT_CONTROLLER;
		// $method     = $uri !== ''      && isset($parts[1])  ? $parts[1] : DEFAULT_METHOD;
		// $args       = is_array($parts) && count($parts) > 2 ? array_slice($parts, 2) : array(); 
		// $char_position = strpos($controller,'&');
		// if ($char_position > 0 ) {
			// $ctp = explode('&', $controller);
			// $controller = $ctp[0];
		// }
		// $char_position2 = strpos($method,'&');
		// if ($char_position2 > 0 ) {
			// $ctp = explode('&', $method);
			// $method = $ctp[0];
		// }
		// if ($args != null) {
			// $char_position3 = strpos($args[0],'&');
			// if ($char_position3 > 0 ) {
				// $ctp = explode('&', $yes);
				// $args[0] = $ctp[0];
			// }
		// }
		// // Check for file
		// if (!file_exists('controllers/' . $controller . '.php')) {
			// return false;
		// }
		// $controller = '\controllers\\' . $controller;
		// $c = new $controller;
		// if (method_exists($c, $method)) {
			
			// $c->$method($args);
			// //found method so stop
			// return true;
		// }
		// return false;
	// }

	// /**
	// * Runs the callback for the given request
	// */
	// public static function dispatch(){
		// $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
		// $method = $_SERVER['REQUEST_METHOD'];  
		// $searches = array_keys(static::$patterns);
		// $replaces = array_values(static::$patterns);
		// self::$routes = str_replace('//','/',self::$routes);   
		// $found_route = false;
		// // check if route is defined without regex
		// if (in_array($uri, self::$routes)) {
			// $route_pos = array_keys(self::$routes, $uri);
			// // foreach route position
			// foreach ($route_pos as $route) {
				// if (self::$methods[$route] == $method || self::$methods[$route] == 'ANY') {
					// $found_route = true;
					// //if route is not an object 
					// if(!is_object(self::$callbacks[$route])){
						// //call object controller and method
						// self::invokeObject(self::$callbacks[$route]);
						// if (self::$halts) return;
					// } else { 
						// //call closure
						// call_user_func(self::$callbacks[$route]);
						// if (self::$halts) return;
					// }
				// }
			// }
			// // end foreach
		// }else{
			// // check if defined with regex
			// $pos = 0;
			// // foreach routes
			// foreach (self::$routes as $route) {
				// $route = str_replace('//','/',$route);
				// if (strpos($route, ':') !== false) {
					// $route = str_replace($searches, $replaces, $route);
				// }
				// if (preg_match('#^' . $route . '$#', $uri, $matched)) {
					// if (self::$methods[$pos] == $method || self::$methods[$pos] == 'ANY') {
						// $found_route = true; 
						// //remove $matched[0] as [1] is the first parameter.
						// array_shift($matched);
						// if(!is_object(self::$callbacks[$pos])){
							// //call object controller and method
							// self::invokeObject(self::$callbacks[$pos],$matched);
							// if (self::$halts) return;
						// } else {
							// //call closure
							// call_user_func_array(self::$callbacks[$pos], $matched);
							// if (self::$halts) return;
						// }
					// }
				// }
				// $pos++;
			// }
			// // end foreach
		// }
		// if (self::$fallback) {
			// //call the auto dispatch method
			// $found_route = self::autoDispatch();
		// }
		// // run the error callback if the route was not found
		// if (!$found_route) {
			// if (!self::$error_callback) {
				// self::$error_callback = function() {
					// header($_SERVER['SERVER_PROTOCOL']." 404 Not Found");
					// echo '404';
				// };
			// } 
			// if(!is_object(self::$error_callback)){
				// //call object controller and method
				// self::invokeObject(self::$error_callback,null,'No routes found.');
				// if (self::$halts) return;
			// } else {
				// call_user_func(self::$error_callback); 
				// if (self::$halts) return;
			// }
		// }
	// }
// }