<?php
class Router
{
    public $routes = [];

    public function new($method, $route, $controller)
    {
        $r = [
            'method' => $method,
            'route'  => $route,
        ];

        if (is_callable($controller))
        {
            $r['controller']    = $controller;
            $this->routes[]     = $r;
        }
        else if (strpos($controller, '@'))
        {
            $split      = explode('@', $controller);
            $class      = $split[0];
            $function   = $split[1];

            $r['controller'] = [
                'class'     => $class,
                'function'  => $function
            ];

            $this->routes[] = $r;
        }
        else
        {
            throw new Exception('Invalid controller');
        }
    }

    public function match()
    {
        foreach($this->routes as $route)
        {
            if ($this->_match_route($route['route']))
            {
                if ($route['method'] != $_SERVER['REQUEST_METHOD'])
                {
                    $this->abort(405);
                }
                $params = $this->getRouteParameters($route['route']);

                if (is_array($route['controller']))
                {
                    $controller = $route['controller'];
                    $class      = $controller['class'];
                    $function   = $controller['function'];

                    return (new $class)->$function($this,$params);
                }
                return $route['controller']($this,$params);
            }
        }

        $this->abort(404);
    }

    public function _match_route($route)
    {
        $uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
        $route = explode('/', $route);

        if (count($uri) != count($route)) return false;

        foreach ($route as $key => $value)
        {
            if ($uri[$key] != $value && $value != '{param}') return false;
        }

        return true;
    }

    public function getRouteParameters($route)
    {
        $params = [];
        $uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
        $route = explode('/', $route);

        foreach ($route as $key => $value)
        {
            if ($uri[$key] == $value) continue;
            if ($value == '{param}')
            {
                if ($uri[$key] == '')
                {
                    $this->abort(404);
                }
                $params[] = $uri[$key];
            }
        }

        return $params;
    }

    public function abort($code)
    {
        http_response_code($code);
        exit;
    }

    public function view($view, $data = [])
    {
        extract($data);
        include __DIR__."/views/${view}.php";
        exit;
    }

    public function jsonify($body, $code = null)
    {
        if ($code) {
            http_response_code($code);
        }

        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($body);

        exit;
    }
}