<?php
	// namespace
	namespace sven\sys;

	/**
	 * core
	 *
	 * This is the core class to connect all classes to a homogeneous system
	 *
	 * @package sven\sys
	 * @copyright 2018 Ruben Meyer
	 * @author Ruben Meyer <contact@rxbn.de>
	 * @version 0.1.0
	 * @TODO Comments
	 */
	class core {

		/**
		 * needLogin
		 *
		 * @access private
		 * @static
		 * @var boolean
		 */
		private static $needLogin = false;

		/**
		 * setLogin
		 *
		 * sets login access
		 *
		 * @access public
		 * @static
		 * @param boolean $boolean boolean to set
		 * @return void
		 */
		public static function setLogin($boolean) {
			self::$needLogin = (boolean) $boolean;
		}

		/**
		 * getLogin
		 *
		 * @access public
		 * @static
		 * @return boolean
		 */
		public static function getLogin() {
			return self::$needLogin;
		}

		/**
		 *  //////  ////////  ////////  //////    //     //  ////////  ////////   ////////
		 *  //  //  //    //  //        //        //     //  //    //  //    //   //
		 *  //////  //    //  ////////  //////     //   //   ////////  ////////   ////////
		 *  //      ////////  //    //  //         //   //   //    //  //     //        //
		 *  //      //    //  ////////  //////       ///     //    //  //     //  ////////
		 */

		/**
		 * exception_categories
		 *
		 * Categories which will get imported when an exception was thrown
		 *
		 * @access private
		 * @static
		 * @var array
		 */
		private static $exception_categories = ['head', 'header', 'footer', 'foot'];

		/**
		 * exceptions
		 *
		 * all thrown exceptions
		 *
		 * @access private
		 * @static
		 * @var array
		 */
		private static $exceptions = [];

		/**
		 * templates
		 *
		 * template array
		 *
		 * [
		 *     'name' => string, ....
		 * ]
		 *
		 * @access private
		 * @static
		 * @var array|null
		 */
		private static $templates = null;

		/**
		 * replacements
		 *
		 * replacements array
		 *
		 * [
		 *     'template' => [
		 *         'key' => 'value',
		 *         ...
		 *     ],
		 *     ...
		 * ]
		 *
		 * @access private
		 * @static
		 * @var array|null
		 */
		private static $replacements = null;

		/**
		 * configurations
		 *
		 * page configuration
		 *
		 * [
		 *     'index' => [ //refers to 'pages/index'
		 *         'key' => 'value',
		 *         ...
		 *     ],
		 *     ...
		 * ]
		 *
		 * @access private
		 * @static
		 * @var array
		 */
		private static $configurations = [];

		/**
		 *     //////  ///////  //    //    //  ////////  //////    //////
		 *    //  //  //   //  //    //    //  //    //  //  //    //
		 *   //////  //////   //    //    //  ////////  //////    //////
		 *  //  //  //       //    //    //  //    //  //    //      //
		 * //  //  //       //     //////  //    //  //    //  //////
		 */

		/**
		 * apiOutput
		 *
		 * api output array (convertable to json and xml)
		 *
		 * @access private
		 * @static
		 * @var array
		 */
		private static $apiOutput = [];

		/**
		 * addException
		 *
		 * adds an Exception
		 *
		 * @access public
		 * @static
		 * @param \Exception $exception Throwable Exception
		 * @return void
		 */
		public static function addException($exception) {
			array_push(self::$exceptions, $exception);
		}

		/**
		 * countExceptions
		 *
		 * counts Exceptions
		 *
		 * @access public
		 * @static
		 * @return int
		 */
		public static function countExceptions() {
			return count(self::$exceptions)||0;
		}

		/**
		 * getExceptions
		 *
		 * gets all Exceptions
		 *
		 * @access public
		 * @static
		 * @return \Exception[]
		 */
		public static function getExceptions() {
			return self::$exceptions;
		}

		/**
		 * getExceptions
		 *
		 * adds an Replacement for $category
		 *
		 * @access public
		 * @static
		 * @param string $category Category
		 * @param string $text Placeholder
		 * @param string $replace Replacement
		 * @return void
		 */
		public static function addReplacement($category, $text, $replace, $replacePrevious = false) {
			$auth = new \sven\sys\security\auth;
			if($auth->loggedIn() || (!$auth->loggedIn() && $category !== 'head')) {
				if(!is_array(self::$replacements)) self::$replacements = [];
				if(!in_array($category, array_keys(self::$replacements))) self::$replacements[$category] = [];
				if(!isset(self::$replacements[$category][$text]) || $replacePrevious) self::$replacements[$category][$text] = $replace;
			}
		}

		/**
		 * getReplacements
		 *
		 * gets all Replacements
		 *
		 * @access public
		 * @static
		 * @return array
		 */
		public static function getReplacements() {
			return self::$replacements;
		}

		/**
		 * addTemplate
		 *
		 * adds a Template
		 *
		 * @access public
		 * @static
		 * @param string $category Name
		 * @param string $string Template
		 * @param boolean $overwrite overwrite (default=false) (Optional)
		 * @return boolean State of adding the template
		 */
		public static function addTemplate($category, $string, $overwrite = false) {
			if(!is_array(self::$templates)) self::$templates = [];
			if( in_array($category, array_keys(self::$templates)) && $overwrite === true
			|| !in_array($category, array_keys(self::$templates))) {
				self::$templates[$category] = $string;
				return true;
			}
			return false;
		}

		/**
		 * getTemplates
		 *
		 * gets all Templates
		 *
		 * @access public
		 * @static
		 * @return array|null
		 */
		public static function getTemplates() {
			return self::$templates;
		}


		/**
		 * getOutput
		 *
		 * gets output for the page
		 *
		 * @access public
		 * @static
		 * @param array $order order or/and templates which get implemented
		 * @return string
		 */
		public static function getOutput($order = ['head', 'header', 'exception', 'main', 'footer', 'foot']) {
			if(is_array(self::$templates)) {
				$auth = new \sven\sys\security\auth;
				if(!$auth->loggedIn()) self::$replacements['head']['TITLE'] = 'Please Login';

				// replacing with variables
				$parsing = "";
				$replacements = self::getReplacements();
				$replaced_templates = [];
				foreach (self::$templates as $key => $value) {
					$temp_output = $value;
					if(is_array($replacements) && in_array($key, array_keys($replacements))) {
						foreach ($replacements[$key] as $item => $data) {
							$placeholder = '%%'.$key.'_'.$item.'%%';
							if(strpos($temp_output, $placeholder) !== false) {
								$temp_output = str_replace($placeholder, $data, $temp_output);
							}
						}
					}
					// checking if key is not exception to prevent default template output of exception
					if($key !== "exception")
						$replaced_templates[$key] = $temp_output;
				}

				// replacing common replacements ($replacement_category = 'all')
				foreach ($replaced_templates as $key => $value) {
					if(isset($replacements["all"]) && is_array($replacements["all"])) foreach ($replacements["all"] as $item => $data) {
						$placeholder = '%%'.$item.'%%';
						if(strpos($value, $placeholder) !== false) {
							$replaced_templates[$key] = str_replace($placeholder, $data, $replaced_templates[$key]);
						}
					}
				}

				for ($i=0; $i < count($order); $i++) {
					if($order[$i] === "main" && !$auth->loggedIn() && self::$needLogin) {
						$replaced_templates["main"] = self::getTemplates()["login_msg"];
					}

					// Exception handling if exceptions were thrown
					if($order[$i] === "exception" && self::getExceptions()) {
						$replaced_templates["exception"] = "";
						$error_template = self::getTemplates()['exception'];

						ob_start();
						$startTag = "%%repeat_START%%";
						$endTag = "%%repeat_END%%";
						$start = strpos($error_template, $startTag);
						$end = strpos($error_template, $endTag);
						$template = \sven\sys\sven\utilities::getBetween($error_template, $startTag, $endTag);
						foreach (self::getExceptions() as $exception) {
							$tempException = $template;
							$tempException = str_replace('%%exception_title%%', trim($exception->getTitle(), "\n\r\t"), $tempException);
							$tempException = str_replace('%%exception_code%%', trim($exception->getCode(), "\n\r\t"), $tempException);
							$tempException = str_replace('%%exception_message%%', trim($exception->getMessage(), "\n\r\t"), $tempException);
							print_r($tempException);
						}
						$data = ob_get_contents();
						ob_end_clean();

						//$data = substr($data, 0, strlen($endTag));

						//replace the normal main part
						$replaced_templates["exception"] .= "\n".substr_replace($error_template, $data, $start, $end-$start+strlen($endTag));
					}

					//adding replaced content to output
					if(in_array($order[$i], array_keys($replaced_templates))) {
						$parsing .= $replaced_templates[$order[$i]]."\n";
					}
				}
				return $parsing;
			}

			//no templates found
			else return "ERROR 500 - \sven\sys\core::getOutput()";
		}

		/**
		 * rawApiOutput
		 *
		 * returns self::$apiOutput
		 *
		 * @access public
		 * @static
		 * @return mixed[]
		 */
		public static function rawApiOutput() {
			return self::$apiOutput;
		}

		/**
		 * replaceApiOutput
		 *
		 * replaces api output with $api
		 *
		 * @access public
		 * @static
		 * @param mixed[] $api api array
		 */
		public static function replaceApiOutput($api) {
			if($api === null || $api === false) {
				$api = (object) [
					"msg" => "Request method not supported. See README.md for supported methods",
					"error" => ["REQUEST_METHOD_NOT_SUPPORTED"]
				];
			}
			self::$apiOutput = $api;
		}

		/**
		 * getApiOutput
		 *
		 * gets output for api usage
		 *
		 * @access public
		 * @static
		 * @param string $type "json" or "xml"
		 * @return string
		 */
		public static function getApiOutput($type='json') {
			if(!isset(self::$apiOutput->state)) self::$apiOutput->state = "failed";

			if(self::getExceptions()) {
				self::$apiOutput->state = "failed";
				self::$apiOutput->exceptions = [];
				foreach (self::getExceptions() as $exception) {
					$arr = [
						"title" => $exception->getTitle(),
						"message" => $exception->getMessage(),
						"code" => $exception->getCode()
					];
					self::$apiOutput->exceptions[] = $arr;
				}
			}

			if(self::$apiOutput->access === "denied" && self::$apiOutput->state === "failed") http_response_code(401);
			elseif(self::$apiOutput->state === "failed") http_response_code(400);

			if($type == "json") {
				header("Content-Type: application/json");
				return json_encode(self::$apiOutput, JSON_PRETTY_PRINT);
			}
		}
	}

?>
