<?php

spl_autoload_register(function($class){
	if (file_exists("Interfaces/$class.php")){
		include("Interfaces/$class.php");
		return;
	}
	
	if (file_exists("Model/$class.php")){
		include("Model/$class.php");
		return;
	}
	
	if (file_exists("Database/$class.php"))
		include("Database/$class.php");
});

$files=glob("base/*.php");
foreach ($files as $file)
	require_once $file;

class Application{
	protected $_view, $_controller, $_url, $_dependencyInjector;
	
	private function LoadMethodCallArguments($methodParams,$params){
		$callArgs=array();
		foreach ($methodParams as $methodParam){
			$index=$methodParam->getPosition();
			$name=$methodParam->getName();
			$type=$methodParam->getClass();
			$default=null;
			try {
				$default=$methodParam->getDefaultValue();
			}catch(Exception $e){}
			
			if(isset($params[$name]))
				$callArgs[$index]=$params[$name];
			elseif (isset($params[$index]))
				$callArgs[$index]=$params[$index];
			elseif ($type!=null)
				$callArgs[$index]=$this->_dependencyInjector->Resolve($type->getName());
			else
				$callArgs[$index]=$default;
		}
		return $callArgs;
	}
	
	private function SetupController(Controller $controller){
		$controller->DependencyInjector=$this->_dependencyInjector;
	}
	
	private function LoadController($page) {
		$controller=self::FindControllerPath($page);
		if ($controller===false) {
			$page="E404";
			$controller="Controller/E404.php";
			//$params=array($this->_url);
			http_response_code(404);
		}

		include_once $controller;
		
		$controllerObject=new $page();
		$this->SetupController($controllerObject);
		
		return $controllerObject;
	}
	
	private function ActualLoadPage($page,$action,$params){
		$this->_controller=$this->LoadController($page);
		$controller=get_class($this->_controller);
		if (!method_exists($this->_controller, $action))
			$action="Index";
		
		$rm=new ReflectionMethod($controller, $action);
		$methodParams=$rm->getParameters();
		
		//Old behaviour detection, please seek to remove
		if (count($methodParams)==1 && $methodParams[0]->getName()=="params"){
			$this->_view=$this->_controller->$action($params);
			return;
		}
		
		$callArgs=$this->LoadMethodCallArguments($methodParams, $params);
		
		$this->_view=call_user_func_array(array($this->_controller,$action), $callArgs);
	}
	
	protected function LoadPage($page,$action,$params){
		$this->ActualLoadPage($page, $action ,$params);
	}
	
	private function PopulateParamsFromGetPost() {
		$params=array();
		foreach ($_GET as $key=>$_)
			$params[$key]=filter_input(INPUT_GET, $key);
		foreach ($_POST as $key=>$_)
			if (!is_array($_))
				$params[$key]=filter_input(INPUT_POST, $key);
			else
				$params[$key]=filter_input(INPUT_POST,$key, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
		//$params['cookies']=array();;
		//foreach ($_COOKIE as $key=>$_)
		//	$params['cookies'][$key]=filter_input(INPUT_COOKIE, $key);
		
		return $params;
	}
	
	function __construct($url) {
		$this->_url=$url;
		
		$this->RegisterDependencies();
		
		$page=ApplicationSettings::GetSetting("general", "default_page");
		$action="Index";
		$params=array();
		
		$parts=explode("/", $url, 3);
		switch (count($parts)){
			case 3:
				if ($parts[2]!='')
					$params=explode("/",$parts[2]);
			case 2:
				//$action=ucfirst($parts[1]);
				$action=$parts[1];
			case 1:
				if ($parts[0]!="")
					$page=$parts[0];
				break;
		}
		
		$params=array_merge($params,$this->PopulateParamsFromGetPost());
		
		try {
			$this->LoadPage($page, $action, $params);
		} catch (Exception $e){
			Utils::var_dump_email($e);
			$this->ActualLoadPage("E500", "Index", array());
			http_response_code(500);
		}
	}
	
	public function GetOutput(){
		if (gettype($this->_view)=="object")
			return $this->_view->GetHTMLFromTemplate(ApplicationSettings::GetSetting("general", "template"));
		switch (gettype($this->_view)){
			case "string":
			case "integer":
				return $this->_view;
		}
		return "";
	}
	
	private function RegisterDependencies() {
		$this->_dependencyInjector=new DependencyInjector();
		$dependencies=ApplicationSettings::GetSettings("dependencies");
		foreach ($dependencies as $key=>$value)
			$this->_dependencyInjector->Register($key,$value);
	}


	public static function FindControllerPath($controller){
		$controllerLower=strtolower($controller);
		$files=glob("Controller/*.php");
		foreach ($files as $file)
			if (strtolower(basename($file,".php"))==$controllerLower)
				return $file;
		return false;
	}
}