<?php

spl_autoload_register(function ($class) {
	$classparts = explode("\\", $class);
	$classname = array_pop($classparts);
	$controllers_dirpaths = \FApp::get_controllers_dirpaths();
	foreach ($controllers_dirpaths as $controllers_dirpath)
		{
		$controller_filepath = $controllers_dirpath.'/'.$classname.'.php';
		if (!file_exists($controller_filepath)) continue;
		include_once($controller_filepath);
		break;
		};
});

class FApp {

	private static $mGlobals = null;
	private static $mRoutes = null;
	private static $mDefaultRoute = null;
	private static $mRouteMatches = null;
	private static $mControllersDirs = null;
	private static $mTemplatesDirs = null;

 	public static function clrlog () {
 		@unlink(__DIR__.'/Logs/'.date('Ymd').'.log');
 	}
 	public static function log ($theLogLine) {
 		$line = date('Y-m-d H:i:s').' | '.$theLogLine."\n";
 		file_put_contents(__DIR__.'/Logs/'.date('Ymd').'.log', $line, FILE_APPEND);
 	}

 	public static function get_global ($theGlobalKey) {
 		if (!isset(self::$mGlobals)) return null;
 		return isset(self::$mGlobals[$theGlobalKey]) ? self::$mGlobals[$theGlobalKey] : null;
 	}
 	public static function set_global ($theGlobalKey, $theGlobalVal) {
 		if (!isset(self::$mGlobals)) self::$mGlobals = array();
 		self::$mGlobals[$theGlobalKey] = $theGlobalVal;
 	}

 	public static function get_controllers_dirpaths () {
		$controllers_dirpaths = array();
		$controllers_dirpaths[] = __DIR__;
		if (isset(self::$mControllersDirs))
			{
			$controllers_dirpaths = array_merge($controllers_dirpaths, self::$mControllersDirs);
			$controllers_dirpaths = array_reverse($controllers_dirpaths);
			};
		$controllers_dirpaths[] = dirname($_SERVER['SCRIPT_FILENAME']);
		return $controllers_dirpaths;
 	}
 	public static function get_templates_dirpaths () {
		$templates_dirpaths = array();
		$templates_dirpaths[] = __DIR__;
		if (isset(self::$mTemplatesDirs))
			{
			$templates_dirpaths = array_merge($templates_dirpaths, self::$mTemplatesDirs);
			$templates_dirpaths = array_reverse($templates_dirpaths);
			};
		$templates_dirpaths[] = dirname($_SERVER['SCRIPT_FILENAME']);
		return $templates_dirpaths;
 	}
 	public static function register_controllers_dir ($theControllersDirPath) {
		if (!isset(self::$mControllersDirs)) self::$mControllersDirs = array();
		self::$mControllersDirs[] = $theControllersDirPath;
 	}
 	public static function register_templates_dir ($theTemplatesDirPath) {
		if (!isset(self::$mTemplatesDirs)) self::$mTemplatesDirs = array();
		self::$mTemplatesDirs[] = $theTemplatesDirPath;
 	}

 	public static function get_controller_filepath ($theControllerFileName) {
		$controllers_dirpaths = self::get_controllers_dirpaths();
		foreach ($controllers_dirpaths as $controllers_dirpath)
			{
			$controller_filepath = $controllers_dirpath.'/'.$theControllerFileName;
			if (!file_exists($controller_filepath)) continue;
			return $controller_filepath;
			};
		return null;
 	}
 	public static function get_template_filepath ($theTemplateFileName) {
		$templates_dirpaths = self::get_templates_dirpaths();
		foreach ($templates_dirpaths as $templates_dirpath)
			{
			$template_filepath = $templates_dirpath.'/'.$theTemplateFileName;
			if (!file_exists($template_filepath)) continue;
			return $template_filepath;
			};
		return null;
 	}

	public static function route ($theRoutePattern, $theControllerMethodSpec) {
		list($controller, $method) = explode(':', $theControllerMethodSpec);
		if (!isset($theRoutePattern))
			{
			self::$mDefaultRoute = array('controller' => $controller, 'method' => $method);
			return;
			};
		if (!isset(self::$mRoutes)) self::$mRoutes = array();
		self::$mRoutes[] = array('pattern' => $theRoutePattern,
			'controller' => $controller, 'method' => $method);
	}

	public static function route_params () {
		$params = array();
		foreach (self::$mRouteMatches as $matchnum => $match)
			{
			if ($matchnum == 0) continue;
			$params[$matchnum - 1] = $match[0];
			};
		return $params;
	}

	public static function start ()
		{
		try {
			if (isset(self::$mRoutes))
				{
				foreach (self::$mRoutes as $route)
					{
					$request_uri = $_SERVER['REQUEST_URI'];
					$request_uri = $request_uri == '/' ? $request_uri : rtrim($request_uri, '/');
					if (preg_match_all('|^'.$route['pattern'].'$|',
						$request_uri, self::$mRouteMatches)) {
						$class = "\\".$route['controller'];
						$instance = new $class();
						call_user_func(array($instance, $route['method']));
						exit;
						};
					};
				};
			if (isset(self::$mDefaultRoute))
				{
				$class = "\\".self::$mDefaultRoute['controller'];
				$instance = new $class();
				call_user_func(array($instance, self::$mDefaultRoute['method']));
				exit;
				};
			}
		catch (Throwable $t) // PHP7
			{
			echo $t->getMessage(), "\n";
			echo "<pre>\n".print_r($t, true)."</pre>\n";
			}
		catch (Exception $e) // PHP5
			{
			echo $e->getMessage(), "\n";
			echo "<pre>\n".print_r($e, true)."</pre>\n";
			};
		}

};

<?php

class FAppController {

	private static $mRenderParams = null;

	private static function renderlib_eval_varname ($theVarName) {
		$varname_parts = explode('.', $theVarName);
		$varname_nbofparts = count($varname_parts);
		$varname_lastpartnum = $varname_nbofparts - 1;

		$result = self::$mRenderParams;
		// $result['env'] = \Fapp::env();

		foreach ($varname_parts as $varname_partnum => $varname_part)
			{
			if ($varname_partnum == 0)
				{
				$result = self::$mRenderParams[$varname_part] ?? null;
				continue;
				};
			if (is_array($result))
				{
				$result = $result[$varname_part] ?? null;
				continue;
				};
			$result = null;
			break;
			};
		if (is_array($result))
			{
			if (isset($result['_val'])) $result = $result['_val'];
			};
		return $result;
	}

	private static function renderlib_load_template ($theTemplateFileName)
		{
		$template_filepath = \FApp::get_template_filepath($theTemplateFileName);
		if (isset($template_filepath))
			{
			$template_text = file_get_contents($template_filepath);
			$template_text = preg_replace_callback('|<:include\s+(.*?):>|U', function ($matches)
				{
				$template_filename = $matches[1];
				return self::renderlib_load_template($template_filename);
				}, $template_text);
			};
		return $template_text ?? "";
		}

	public static function render ($theTemplateFileName, $theVarsList = null) {

		self::$mRenderParams = $theVarsList;
		$VARS = self::$mRenderParams;

		$template_text = self::renderlib_load_template($theTemplateFileName);

/*
		$template_text = preg_replace('|<:(.*?)\$:(.+?)\s+(.*):>|',
			"<:$1 \$VARS['$2'] $3:>",
			$template_text);
*/
		$template_text = preg_replace_callback('|<:(.*?)\$:(.+?)\s+(.*):>|',
			function ($matches)
				{
				$varname = $matches[2];
				$varname_parts = explode('.', $varname);
				$result = '<:'.$matches[1].' $VARS';
				foreach ($varname_parts as $varname_part)
					{
					$result .= "['".$varname_part."']";
					};
				$result .= ' '.$matches[3].':>';
				return $result;
				},
			$template_text);

		$template_text = preg_replace('|<:\s*foreach\s+\(*(.*?)\)*\s*:>|',
			'<?php foreach ($1) { ?>',
			$template_text);
		$template_text = preg_replace('|<:\s*/foreach\s*:>|',
			'<?php }; ?>',
			$template_text);

		$template_text = preg_replace('|<:\s*if\s+(.*?)\s*:>|',
			'<?php foreach ($1) { ?>',
			$template_text);
		$template_text = preg_replace('|<:\s*else\s*:>|',
			'<?php } else { ?>',
			$template_text);
		$template_text = preg_replace('|<:\s*/if\s*:>|',
			'<?php }; ?>',
			$template_text);

		$template_text = preg_replace('|<:\s*(.*?)\s*:>|',
			'<?php $1 ?>',
			$template_text);


		$template_text = preg_replace_callback('|\{\{\s*(.*?)\s*\}\}|', function ($matches)
			{
			$varname = $matches[1];
			return (substr($varname, 0, 1) == '$')
				? '<?='.$varname.'?>'
				: self::renderlib_eval_varname($varname);
			}, $template_text);

		return eval('?>'.$template_text);
	}

	public static function redirect ($theRedirectURL) {
		header('Location: '.$theRedirectURL);
		exit;
	}

}