<?php
 
namespace elanpl\L3;
 
define('_L3_ROUTE_404_NAME', '_L3_404');
class Router{
 
    protected $routes; // The defined routes collection
    protected $routeNameIndex; // An array with elements that reference to the routes ordered by a route names
    public $parsedParameters; // Parameters parsed from Request Path
    public $depth; // Number of nested nodes in Request Path
    public $routeInfo; // The RouteInfo object if the route was matched
 
    public function __construct($routing)
    {
        $this->routes = array(); 
        $this->routeNameIndex = array();
        //Set the routing from configuration object
        $routing->set($this);
    }
 
    public function add($method, $path, $result, $name = ''){
        $this->routes[] = new RouteInfo($method, $path, $result, $name);
        if(isset($name)&&$name!='') $this->routeNameIndex[$name] = &$this->routes[count($this->routes)-1];
        return $this;
    }
 
    public function add404($result){
        return $this->add('404', '', $result, _L3_ROUTE_404_NAME);
    }
 
    public function get($path, $result, $name = ''){
        return $this->add('GET', $path, $result, $name);
    }
 
    public function post($path, $result, $name = ''){
        return $this->add('POST', $path, $result, $name);
    }
 
    public function put($path, $result, $name = ''){
        return $this->add('PUT', $path, $result, $name);
    }
 
    public function patch($path, $result, $name = ''){
        return $this->add('PATCH', $path, $result, $name);
    }
 
    public function delete($path, $result, $name = ''){
        return $this->add('DELETE', $path, $result, $name);
    }
 
    public function any($path, $result, $name = ''){
        return $this->add('ANY', $path, $result, $name);
    }
 
    public function addBeforeAction($event_handler){
        $this->routes[count($this->routes)-1]->addBeforeAction($event_handler);
        return $this;
    }
 
    public function addAfterAction($event_handler){
        $this->routes[count($this->routes)-1]->addAfterAction($event_handler);
        return $this;
    }
 
    public function addAfterResult($event_handler){
        $this->routes[count($this->routes)-1]->addAfterAction($event_handler);
        return $this;
    }
 
    public function match($request){
 
        $auri = explode('/', trim($request->path, "/ \t\n\r\0\x0B"));
        $curi = count($auri);
            
        foreach ($this->routes as $routeInfo) {
            
            $route = $routeInfo->path;
            $method = $routeInfo->method;
            if($method=='ANY' || strpos($request->method,$method)!==false){
                $aroute = explode('/', trim($route, "/ \t\n\r\0\x0B"));
                //print_r($aroute);
                if($curi==count($aroute)){ //compare path element count
                    //optimistic assumption :)
                    $matchResult = true;
                    for($i = 0; $i<$curi; $i++){
                        $pathPartName = trim($aroute[$i],'{}');
                        if($aroute[$i]==$pathPartName){
                            if($auri[$i]!=$pathPartName){
                                //echo "diffrence found";
                                $matchResult = false;
                                break;
                            }
                        }
                        else{ // {...} found -> catch $uri variable
                            $value = $auri[$i];
                            $valueKey = explode(':', $pathPartName);
                            //validation
                            if(isset($valueKey[1]) && $valueKey[1]=='int'){
                                $value = intval($value);
                            }
                            //value store...
                            $this->parsedParameters[$valueKey[0]] = $value;