<?php
require_once "./Controller/Database.php";

class API {
    private $BD;
	public $uri = null;
	public $module = null;
	public $userid = null;
	public $method = null;
    public $request = null;
    public $token = null;
    public $id = 0;
    public $input = array();
    public $httpHeaders = array();

    function __construct() {
        $this->BD = new BD();
        $this->URI();
        $this->Version();
        $this->View();
        $this->Module();
        $this->Method();
        $this->Input();
        $this->Token();
    }
  
    private function URI() {
        $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
		$uri = explode( '/', $uri);
        if(array_search($this->BD->api_url, $uri)){
            $this->uri = (array_slice($uri, array_search($this->BD->api_url, $uri)+1));
            if(count($this->uri)<1 || count($this->uri)>3){
                $this->sendOutput(404,array('error 1' => 'Unprocessable Entity'));
            }
        } else {
            $this->sendOutput(404,array('error 1' => 'Unprocessable Entity'));
        }
        if(count($this->uri)<1 || count($this->uri)>3){
            $this->sendOutput(404,array('error 0' => 'Unprocessable Entity'));
        }
    }

    private function Module() {
        $module = ucwords($this->uri[0]);
        $file = PROJECT_ROOT_PATH . "/Model/".$module.".php";
        if(!file_exists($file)){
            $this->sendOutput(404,array('error 4' => 'Unprocessable Entity'));
        }
        require_once $file;
        if(!is_string($module) || !class_exists($module)){
            $this->sendOutput(404,array('error 5' => 'Unprocessable Entity'));
        }       
        $this->module = $module;
    }

    private function Method() {
        $this->request = $_SERVER["REQUEST_METHOD"];
        if(count($this->uri)==1){
            $this->method = $_SERVER["REQUEST_METHOD"];
            $this->ID();
        } else if(method_exists($this->module,ucwords($this->uri[1]))){
            $this->method = ucwords($this->uri[1]);
        } else if(method_exists($this->module,$_SERVER["REQUEST_METHOD"])){
            $this->method = $_SERVER["REQUEST_METHOD"];
            $this->ID();
        } else {
            $this->sendOutput(404,array('error 6' => 'Unprocessable Entity'));
        }
    }

    private function ID() {
        if(count($this->uri)==2){
            $this->id = $this->Clear($this->uri[1]);
        }        
    }

    private function Clear($id) {
        $id = str_replace("--","",$id);
        $id = str_replace("^","",$id);
        $id = str_replace("&","",$id);
        $id = str_replace(";","",$id);
        $id = str_replace("\\","",$id);
        $id = str_replace("'","`",$id);
        return $id;
    }

    public function Input() {
        $data = json_decode(file_get_contents("php://input"));
        $this->input = $data;
    }

	public function Token() {
        $token = null;
        $headers = getallheaders();
        if(isset($headers['Authorization'])){
            $authorizationHeader = $headers['Authorization'];
            $matches = array();
            if (preg_match('/Bearer (.+)/', $authorizationHeader, $matches)) {
                if (isset($matches[1])) {
                    $token = $matches[1];
                }
            }   
        }
		$this->token = $token;
	}

    /*
    private function UserID($token) {
        $result = $this->BD->UserID($token);
        if($result){
			$this->userid = $result;
		} else {       
            $this->sendOutput(401,array('error' => 'Error Token'));
        }
	}
    */

    private function View() {
        $module = ucwords($this->uri[0]);
        if($module=='View'){
            require_once "./Model/Upload.php";
            $Upload = new Upload();
            $Upload->Imagen($this->uri[1],$this->uri[2]);
            exit;
        }
    }

    private function Version() {
        $module = ucwords($this->uri[0]);
        if($module=='Version'){
            require_once "./version.php";
            exit;
        }
    }

    private function Logs($obj) {
        $input = $this->input;
        if($this->method=='Login'){ 
            $input->passw = '-------'; 
            $input->password = '-------'; 
        }
        $input = json_encode($input);   
        $ip = $this->BD->getRealIP();       
        $query = $this->BD->consult("INSERT INTO auth.log (date,userid,module,method,request,detail,ip,code) VALUES (now(),?,?,?,?,?,?,?)");
        $query->execute(array($obj->userid,$this->module,$this->method,$this->request,$input,$ip,$this->id));
	}

	public function action() {
        try {
            $module = $this->module;
            $obj = new $module();
            $obj->module = $this->module;
            $obj->id = $this->id;
            $obj->token = $this->token;
            $obj->input = $this->input;  
            $obj->request = $this->request;
            $obj->userid = null;
            $obj->data = null;
            $obj->httpHeaders = 401;
            $method = $this->method;
            $obj->$method();
            $httpHeaders = $obj->httpHeaders;
            $data = $obj->data;
            $this->Logs($obj);
            $this->sendOutput($httpHeaders,$data);
        } catch (Error $e) {
            $this->sendOutput(500,array('error' => $e->getMessage().'Something went wrong! Please contact support.'));
        }
    }

    protected function sendOutput($case,$data=null) {   
        $status = null;
        switch ($case) {
            case 200:
                $status = "OK";
                //La acción solicitada fue exitosa.
                break;
            case 201:
                $status = "Created";
                //Se creó un nuevo recurso.
                break;
            case 202:
                $status = "Accepted";
                //La solicitud fue recibida, pero aún no se ha realizado ninguna modificación.
                break;
            case 204:
                $status = "No Content";
                //La solicitud fue exitosa, pero la respuesta no tiene contenido
                break;
            case 400:
                $status = "Bad Request";
                //La solicitud fue mal formulada.
                break;
            case 401:
                $status = "Unauthorized";
                //El cliente no está autorizado para realizar la acción solicitada.
                break;
            case 403:
                $status = "FORBIDDEN";
                //Indica que el cliente ha intentado acceder a un recurso al que no tiene acceso. 
                break;
            case 404:
                $status = "Not Found";
                //No se encontró el recurso solicitado.
                break;
            case 405:
                $status = "METHOD NOT ALLOWED";
                //El recurso de destino no admite el método HTTP solicitado.
                break;
            case 406:
                $status = "NOT ACCEPTABLE";
                //El recurso de destino no admite el formato de datos solicitado en la cabecera de Accept o el parámetro accept.
                break;
            case 409:
                $status = "CONFLICT";
                //Se ha detectado un cambio conflictivo durante un intento de modificación de un recurso.
                break;
            case 415:
                $status = "Unsupported Media Type";
                //El formato de datos de la solicitud no es compatible con el servidor.
                break;
            case 422:
                $status = "Unprocessable Entity";
                //Los datos de la solicitud tenían el formato correcto pero no eran válidos o faltaban datos.
                break;
            case 500:
                $status = "Internal Server Error";
                //El servidor arrojó un error al procesar la solicitud.
                break;
            default:
                $status = null;
                $data = null;
        }
        $result = array(
            'status' =>$case,
            'message' =>$status,
            'data' => $data,
        );
        //
        //header('HTTP/1.0 '.$case.' '.$status);
        //json_encode($data);      
        //http_response_code($case);


        //$this->httpHeaders = 'HTTP/1.1 '.$case.' '.$status;
        //$this->httpHeaders = array('HTTP/1.1 '.$case.' '.$status);
        //header_remove('Set-Cookie');
        /*
        if (is_array($this->httpHeaders) && count($this->httpHeaders)) {
            foreach ($this->httpHeaders as $httpHeader) {
                header($httpHeader);
            }
        }
        
        //header('HTTP/2 '.$case.' '.$status);
        if ($case>=200 && $case<300 && $data){
            echo json_encode($data);
        }
            */
        //$httpHeaders = 'HTTP/1.0 '.$case.' '.$status;
        //header($httpHeaders);
        //echo json_encode($result,http_response_code($case));

        echo json_encode($result);
        
        //http_response_code($case)
        exit;
    }
}