<?php

/**
 * Vvveb
 *
 * Copyright (C) 2020  Ziadin Givan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

//require_once 'psttt.php';
//define('THEME_PATH', '/home/store/themes/vvveb/');

namespace Vvveb\System;

include DIR_SYSTEM . VIEW_TEMPLATE_ENGINE . '.php';

class View {
	static private $instance;

	static $templatePath;

	static private $theme;

	static private $htmlPath;

	static private $template;

	static private $psttt;

	static private $compiledTemplate;

	static private $serviceTemplate;

	static private $component;

	static private $componentCount;

	static private $componentContent;

	static private $staging;

	static private $useService;

	static function getInstance() {
		if (self :: $instance === NULL) {
			self :: $instance = new self(); //create class instance

			self :: $theme        = \Vvveb\config(APP . '.theme', 'default');
			self :: $htmlPath     = DIR_THEME . self :: $theme . '/';
			self :: $templatePath = DIR_THEME . self :: $theme . '/'; //\Vvveb\config(APP . '.theme', 'default') . '/';

			if (isset($_REQUEST['_component_ajax'])) {
				self ::$component        = \Vvveb\filter('/[a-z]*/', $_REQUEST['_component_ajax'], 15);
				self ::$componentCount   = \Vvveb\filter('/\d+/', $_REQUEST['_component_id'],  2);
				self ::$componentContent = $_POST['_component_content'] ?? '';
			}
		}

		return self :: $instance;
	}

	function setTheme($theme) {
		$theme            = \Vvveb\filter('/[a-z0-9-]*/', $theme, 15);
		self :: $theme    = $theme;
		self :: $htmlPath = DIR_THEME . $theme . '/';
	}

	function getTheme() {
		return self :: $theme;
	}

	function compiledTemplate() {
		return self :: $compiledTemplate;
	}

	function set($data) {
		foreach ($data as $key => $value) {
			$this->$key = $value;
		}
	}

	static function serviceTemplate() {
		return self :: $serviceTemplate;
	}

	function checkNeedRecompile() {
		if (empty(self::$template)) {
			return false;
		}

		if (! file_exists(self :: $templatePath . self :: $template)) {
			FrontController::notFound();
		}

		$templateMtime = null;
		$template      = self :: $templatePath . self :: $template;

		if (file_exists($template)) {
			$templateMtime = filemtime($template);
		}

		$html = DIR_TEMPLATE . self :: $psttt;

		$htmlMtime = 0;

		if (file_exists($html)) {
			$htmlMtime = filemtime($html);
		}
		$compiledMtime = 0;

		if (file_exists(self :: $compiledTemplate)) {
			$compiledMtime = @filemtime(self :: $compiledTemplate);
		}

		if ((max($templateMtime, $htmlMtime) > $compiledMtime
			 || ! file_exists(self :: $compiledTemplate))
			|| (defined('DEBUG') && DEBUG) || isset($_POST['_component_content'])) {
			self :: recompile(self :: $template, self :: $compiledTemplate);
		}
	}

	private function recompile($filename, $file) {
		touch($file); //if recompiling takes longer avoid avoid other recompile requests
		//regenerate component file
		//if (APP== 'store')
		if (self :: $useService) {
			//regenerate components cache
			$service = service::getInstance(true, self ::$componentContent);
		}

		$selector = $count = null;

		if (isset(self ::$component)) {
			$selector = '[data-v-component-' . self ::$component . ']';
		}

		//$psttt = new psttt($selector, self ::$componentCount);
		$templateEngine = VIEW_TEMPLATE_ENGINE;

		$psttt               = new $templateEngine($selector, self :: $componentCount, self :: $componentContent);
		$psttt->templatePath = DIR_TEMPLATE; // . ((isset($store) && ID_HOST) ? ID_HOST . '/' : '');
		$psttt->htmlPath     =  self :: $htmlPath; //DIR_WEBROOT . \Vvveb\config(APP . '.theme', 'default') . '/';
		//var_dump($psttt->htmlPath);//die();
		//var_dump($filename);die();
		$errors = $psttt->loadHtmlTemplate($filename);
		$psttt->loadTemplateFile(self :: $psttt);
		$psttt->saveCompiledTemplate($file);
	}

	static function psttt($filename) {
		self :: $psttt = $filename;
	}

	static function template($filename = null) {
		if ($filename === false) {
			self :: $template = false;

			return;
		}

		if ($filename) {
			if ($filename !== null) {
				$actionName = strtolower(FrontController :: getActionName());
				/*
				  if ($filename[0] !== '/')
				  {
				  self :: $templatePath .= FrontController :: get_controlller_name() . '/';
				  }*/
				$filename = str_replace('..', '', $filename);

				$compiledFilename = DIR_COMPILED_TEMPLATES
				. APP . '_'
				. ((is_null(self ::$component)) ? '' : self ::$component . self ::$componentCount . '_')
				. self :: $theme . '_'
				. str_replace('/' , '_', $filename);

				self :: $compiledTemplate = $compiledFilename;

				self :: $serviceTemplate = $compiledFilename;

			/*
			DIR_COMPILED_TEMPLATES 
				. APP. '_'
				. str_replace('/' , '_', $filename);
				 */
			} else {
				$filename = FrontController :: get_controlller_name() . '/'
				. $actionName . '.html';
				self :: $compiledTemplate = DIR_COMPILED_TEMPLATES
				. APP . '/' . FrontController :: get_controlller_name()
				. '/' . $actionName
				. ((is_null(self ::$component)) ? '' : self ::$component . self ::$componentCount . '_')
				. self :: $staging . '.html';

				self :: $serviceTemplate = DIR_COMPILED_TEMPLATES
				. APP . '/' . FrontController :: get_controlller_name()
				. '/' . $actionName
				. self :: $staging . '.html';
			}

			//if (!isset(self :: $psttt))
			{
				self :: $psttt = str_replace('.html', '.pst', $filename);
			}
			self :: $template = $filename;
		}

		return self :: $template;
	}

	function fragment($selector, $index = 0) {
		self :: $component      = $selector;
		self :: $componentCount = $index;
	}

	function noJson($value = true) {
		$this->noJson = $value;
	}

	/**
	 * Renders the specified file (html).
	 *
	 * @param string @filename
	 */
	/*	
		function getHtml($template, $html, $idHost = null, $templatePath = '', $component = null, $componentId = null)
		{
			$path = $html[0] !== '/'?self :: $templatePath:'';
			$templateMtime = filemtime($path . $html);

			$compiledTemplate = DIR_COMPILED_TEMPLATES 
				. ((isset($idHost) && $idHost) ? $idHost . '_' : '') 
				. APP. '_getHtml'
				. str_replace('/', '_', $html);		
					
			$htmlMtime = 0;
			if (file_exists($html)) $htmlMtime = filemtime($html);
			$compiledMtime = @filemtime(self :: $compiledTemplate);
			
			//$compiledMtime = 0;
			
			if ((max($templateMtime, $htmlMtime) > $compiledMtime 
				 || !file_exists($compiledTemplate))
				|| @constant('PSTTT_DEBUG'))
			{
				$psttt = new psttt($component, $componentId);
				$psttt->templatePath = $templatePath;'';//PATH . '/templates/' . PROJECT . '/' . APP. '/';// . ((isset($store) && ID_HOST) ? ID_HOST . '/' : '');
				$psttt->htmlPath = $path;
				
				$errors = $psttt->loadHtmlTemplate($html);
		//	    $originalTemplate = view::template();
		//	    view::template($template);
				$psttt->loadTemplateFile($template);
			
				$psttt->saveCompiledTemplate($compiledTemplate);
			}

			if ($component) $service = service::getInstance();
			
			ob_start();

			include_once($compiledTemplate);
		
			return ob_get_clean();
		}
	*/
	function render($useService = true) {
		self :: $useService = $useService;

		if ($useService) {
			$service = service::getInstance(true, self ::$componentContent);
		}
		//json
		if (defined('FORCE_JSON')) {
			var_dump($this);
			//var_dump(array_keys((array)$this));
			return;
		}

		if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' &&
		! isset($this->noJson) && ! isset($_REQUEST['_component_ajax']) && ! IS_MOBILE) {
			unset($this->config);
			ob_start();
			header('Content-type: application/json');
			echo json_encode($this);
			ob_end_flush();
		} else { //html
			if (! self::$template) {
				return true;
			}
			$this->checkNeedRecompile();

			//ob_start();
			try {
//			var_dump($this);
				if (! file_exists(self :: $compiledTemplate)) {
					return FrontController::notFound();
				}

				include_once self :: $compiledTemplate;
			} catch (Throwable $e) {
				$lines = file($e->getFile());
				$line  = 1;

				if (preg_match("@PSTT_MAP:(\d+)@", $lines[$e->getLine() - 1] ,$matches)) {
					$line = $matches[1];
				}

				//$error =  "<html><head><link href='https://fonts.googleapis.com/css?family=Work+Sans' rel='stylesheet' type='text/css'><link href='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.0.0/styles/github.min.css' rel='stylesheet' type='text/css'><style>body {font-family: Arial, Sans-serif;font-size:14px;}body > div {margin:0px auto;display:table;}</style><script src='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.0.0/highlight.min.js'></script></head><body>";
				$error = '';

				if (defined('HOST')) {
					$error .= '<!-- h2>' . HOST . '</h2 -->';
				}

				$lines = file(self :: $templatePath . self :: $template);
				$error .= '<div><h2>Error parsing <strong style="color:red">' . self :: $template . '</strong> on line ' . $line . '</h2>Code on line ' . $line . '<pre><code class="html">' . htmlentities(trim($lines[$line - 1])) . '</code></pre>Context <pre><code class="html">' . htmlentities(trim($lines[$line - 3]) . "\n" . trim($lines[$line - 2]) . "\n" . trim($lines[$line - 1]) . "\n" . trim($lines[$line]) . "\n" . trim($lines[$line + 1])) . '</code></pre><script>var aCodes = document.getElementsByTagName("code");for (var i = 0; i < aCodes.length; i++) {  hljs.highlightBlock(aCodes[i]);console.log(aCodes[i]);}</script></div>';

				echo $error;

				echo "<!--\n", $e->getMessage(), "\n";
				echo basename(self :: $compiledTemplate), ' on line ', $e->getLine(), "-->\n</body></html>";

				//file_put_contents($compiledFile, $error . ' <!-- ' . htmlentities($html) . ' --> ');
			}

			//ob_end_flush();
		}
	}
}
