<?php

namespace Routes;

/**************************************************/
/********************* Route **********************/
/**************************************************/

abstract class Route {
	protected $resourceClass;
	
  public function __construct() {
  	$this->resourceClass = ("\\Resources\\".(get_called_class()::$resource));
  }
  
  public function Answer() {
  	try {
	  	$subroute = \Request::Subroute();
	  	if (is_null($subroute)) {
	  		switch (\Request::Method()) {
		      case "OPTIONS":
		      	return $this->info();
		    	case "HEAD":
		    		$id = \Request::ID();
		    		return $this->restrictFilter($id) && $this->head($id);
		      case "GET":
		      	$id = \Request::ID();
		      	if (is_null($id)) {
		      		return $this->restrictFilter() && $this->getAll() && $this->head();
		      	} else {
		      		$json = [];
		    			return $this->head($id) &&  $this->getOne($id, $json) && $this->checkOutput($id, $json);
		      	}
		    	case "POST":
		    		$json = \Request::Input("content");
		    		return $this->checkInput("insert", null, $json) && $this->insert($json) && $this->head();
		    	case "PATCH":
		    		$json = \Request::Input("content");
		    		$id = \Request::ID();
		    		return $this->checkInput("update", $id, $json) && $this->update($id, $json) && $this->head();
		      case "DELETE":
		      	$id = \Request::ID();
		    		return $this->checkInput("remove", $id) && $this->remove($id) && $this->head();
		    	default:
		    		\Response::Get()->NotImplemented();
		    		return false;
		    }
	  	} else {
	  		$id = \Request::ID();
	  		$json = [];
	  		return $this->answerSub($subroute, $id) && $this->getOne($id, $json) && $this->head($id) && $this->checkOutput($id, $json);
  	} }
  	catch (ResponseException $e) {
  		\Response::Get()->HandleException($e);
  		return;
  	}
  	\Response::Get()->Good();
  }
  
  abstract public static function Rights();

  protected function info() {
  	\Response::Get()->Good()->Json("rights", get_called_class()::Rights());
  	return true;
  }
  
  protected function answerSub($subroute, $id) {
  	$answerFnc = "answer_".$this->resourceClass::Get()->Table()."_".$subroute;
  	if (method_exists($this, $answerFnc)) {
  		$subid = \Request::SubID();
  		return $this->$answerFnc($id, $subid);
  	} else if (method_exists($this, "answer_Files") && $this->resourceClass::Get()->HasFile($subroute)) {
  		return $this->answer_Files(get_called_class()::$resource, $id, $subroute);
  	}
  	\Response::Get()->SubRouteNotExisting($subroute);
  	return false;
  }
  
  protected function head($id = null) {
  	\Response::Get()->Good()->Etag($this->resourceClass::Get()->Checksum($id));
  	return true; // Needed for &&-chain-call
  }
  
  protected function getOne($id, &$json) {
		$resource = $this->resourceClass::Get()->Ref($id);
		if ($resource->Load()) {
			$json = $resource->Json();
			return true;
		}

  	\Response::Get()->NotFound();
  	return false;
  }
  
  protected function getAll() {
		$list = $this->resourceClass::Get()->RefAll();
		$json = [];
		foreach ($list as $resource) {
			$json[] = $resource->Json();
		}
		\Response::Get()->Good()->Content($json);
		return true;
  	\Response::Get()->NotFound();
  	return false;
  }
  
  protected function insert($json) {
  	$newid = null;
  	if ($this->resourceClass::Get()->Insert($json, $newid)) {
  		\Response::Get()->Inserted(get_called_class()::$resource)->Content($this->resourceClass::Get()->Ref($newid)->Json());
  		return true;
  	}
  	return false;
  }
  
  protected function update($id, $json) {
  	$resource = $this->resourceClass::Get()->Ref($id);
  	if ($resource->Load()) {
	  	$resource->Patch($json);
	  	if ($resource->Store()) {
	  		\Response::Get()->Updated(get_called_class()::$resource)->Content($resource->Json());
	  		return true;
	  } }
  	return false;
  }
    
  protected function remove($id) {
  	if ($this->resourceClass::Get()->Remove($id)) {
      \Response::Get()->Deleted(get_called_class()::$resource);
       return true;
    }
    return false;
  }
  
  protected function restrictFilter() {
  	if ($this->resourceClass::Rights()->RestrictFilter()) {
  		return true;
  	}
  	\Response::Get()->IllegalQuery();
  	return false;
  }
  
  protected function checkOutput($id, $json) {
  	if (($this->resourceClass)::Rights()->CheckInput("get", $id, $json)) {
			\Response::Get()->Good()->Content($json);
  		return true;
  	}
  	\Response::Get()->IllegalQuery();
  	return false;
  }
  
  protected function checkInput($action, $id = null, $json = []) {
  	if (is_null($id) && in_array($action, ["update", "remove"])) {
  		\Response::Get()->MissingID();
  		return false;
  	} else if ((is_null($json) || empty($json)) && in_array($action, ["insert", "update"])) {
  		\Response::Get()->MissingContent();
  		return false;
  	} else if (!($this->resourceClass)::Rights()->CheckInput($action, $id, $json)) {
  		\Response::Get()->IllegalInput();
  		return false;
  	}
  	return true;
  }
}
