<?php
///////////////////////////////////////////////////////////////////////////////////////////
///Script PHP/MYSQL of management of classifieds ads developed by Script PAG
///Script PAG all rights reserved. Use under license. http://www.script-pag.com
///////////////////////////////////////////////////////////////////////////////////////////

############################################################ 

use \loader as loader;
use \pool as pool;

require_once('fns_modules.php');

class modules {
	/*** @var _mode string*/
	private $_mode;
	/*** @var _language array*/
	private $_language = [];
	/*** @var _cache array*/
	private $_cache = [];
	/*** @var _routes array*/
	private $_routes = [];
	/*** @var _heads array*/
	private $_heads = [];
	/*** @var _modules array*/
	private $_modules = [];
	/*** @var _data array*/
	private $_data = [];
	/*** @var _instance self*/
	private static $_instance;
	
	//// Class constructor
	public function __construct($mode = null) {
		global $language, $language_adm;
		$this->_mode = isset($mode) && $mode === 'SP' ? 'SP' : 'front';
		require_once __DIR__.'/cache/cache_modules.php';
		if(!empty($cache_modules)) {
			$this->_cache['cache_modules'] = $cache_modules;
			foreach($cache_modules as $module) {
				$namespace = $module.'\\'.$module;
				if(method_exists($namespace, 'routes')) {
					$obj = new $namespace();
					$obj = $obj->loadCache();
					$this->_routes = array_merge($this->_routes, $obj->loadRoutes());
				}
			}
		}
	}
	
	//// Return self instance after create it if not exists
	public static function load($mode = null) {
		if (self::$_instance == NULL) self::$_instance = new self($mode);
		return self::$_instance;
	}
	
	//// Load modules environment
	public static function init() {
		global $language, $language_adm;
		if(isset(self::$_instance->_cache['cache_modules'])) {
			$hooks = pool::hooks();
			if(!empty($hooks)) {
				foreach(self::$_instance->_cache['cache_modules'] as $module) {
					$namespace = $module.'\\'.$module;
					foreach($hooks as $hook) {
						if(method_exists($namespace, (is_array($hook) ? $hook[0] : $hook))) self::$_instance->_modules[] = [(is_array($hook) ? $hook[0] : $hook), $namespace, (is_array($hook) ? $hook[0] : $hook)];
					}
				}
			}
		}
		if(sizeof(self::$_instance->_modules) > 0) {
			$loaded = [];
			foreach(self::$_instance->_modules as $key => $action) {
				if(!is_object($action)) {
					$hook = $action[0];
					$namespace = $action[1];
					$method = $action[2];
					if(method_exists($namespace, $method)) {
						$initmethod = 'init'.(self::$_instance->_mode === 'SP' ? 'SP' : '');
						$obj = new $namespace();
						$obj = $obj->loadLanguage()->loadCache()->$initmethod($method);
						if(is_object($obj)) {
							pool::add($hook, [$obj, $method]);
							$loaded[] = $obj;
						}
					}
				}
			}
			self::$_instance->_modules = $loaded;
		}
		if(sizeof(self::$_instance->_modules) > 0) {
			if(self::$_instance->_mode === 'SP') {
				pool::add('spDisplayModuleScriptTag', [self::$_instance, 'displayHead', 'script']);
				pool::add('spDisplayModuleLinkTag', [self::$_instance, 'displayHead', 'link']);
				pool::add('spDisplayModuleMetaTag', [self::$_instance, 'displayHead', 'meta']);
			} else  {
				pool::add('displayModuleScriptTag', [self::$_instance, 'displayHead', 'script']);
				pool::add('displayModuleLinkTag', [self::$_instance, 'displayHead', 'link']);
				pool::add('displayModuleMetaTag', [self::$_instance, 'displayHead', 'meta']);
			}
		}
		return self::$_instance;
	}

	//// Return mode value
	public static function mode() {
		return self::$_instance->_mode;
	}
	
	//// Add entry to modules list for module hook
	public static function module($namespace, $method) {
		self::$_instance->_modules[] = [(self::$_instance->_mode === 'SP' ? 'spModule' : 'module'), $namespace, $method];
	}
	
	//// Return loaded asked module instance
	public static function getModule($namespace) {
		$module = null;
		if(sizeof(self::$_instance->_modules) > 0) {
			foreach(self::$_instance->_modules as $element) {
				if(strtolower($element->name()) == $namespace) {
					$module = $element;
					break;
				}
			}
		}
		return $module;
	}
	
	//// Return language value
	public static function language() {
		$context = func_num_args() === 2 ? func_get_arg(0) : null;
		$name = func_num_args() === 1 ? func_get_arg(0) : (func_num_args() === 2 ? func_get_arg(1) : null);
		return isset($context) ? (isset($name) ? (isset(self::$_instance->_language[$context][$name]) ? self::$_instance->_language[$context][$name] : null) : (isset(self::$_instance->_language[$context]) ? self::$_instance->_language[$context] : null)) : (isset($name) ? (isset(self::$_instance->_language[$name]) ? self::$_instance->_language[$name] : null) : self::$_instance->_language);
	}
	
	//// Add new entry to language
	public static function addLanguage($name, $value) {
		self::$_instance->_language[$name] = $value;
		return self::$_instance;
	}
	
	//// Return cache value
	public static function cache() {
		$context = func_num_args() === 2 ? func_get_arg(0) : null;
		$name = func_num_args() === 1 ? func_get_arg(0) : (func_num_args() === 2 ? func_get_arg(1) : null);
		return isset($context) ? (isset($name) ? (isset(self::$_instance->_cache[$context][$name]) ? self::$_instance->_cache[$context][$name] : null) : (isset(self::$_instance->_cache[$context]) ? self::$_instance->_cache[$context] : null)) : (isset($name) ? (isset(self::$_instance->_cache[$name]) ? self::$_instance->_cache[$name] : null) : self::$_instance->_cache);
	}
	
	//// Return routes value
	public static function routes() {
		return self::$_instance->_routes;
	}
	
	//// Add new entry to cache
	public static function addCache($name, $value) {
		self::$_instance->_cache[$name] = $value;
		return self::$_instance;
	}
	
	//// Return data value
	public static function data() {
		$context = func_num_args() === 2 ? func_get_arg(0) : null;
		$name = func_num_args() === 1 ? func_get_arg(0) : (func_num_args() === 2 ? func_get_arg(1) : null);
		return isset($context) ? (isset($name) ? (isset(self::$_instance->_data[$context][$name]) ? self::$_instance->_data[$context][$name] : null) : (isset(self::$_instance->_data[$context]) ? self::$_instance->_data[$context] : null)) : (isset($name) ? (isset(self::$_instance->_data[$name]) ? self::$_instance->_data[$name] : null) : self::$_instance->_data);
	}
	
	//// Add new entry to data
	public static function addData($name, $value = null, $context = null) {
		if(isset($context) && is_string($context) && strlen($context) > 0) self::$_instance->_data[$context][$name] = $value;
		else self::$_instance->_data[$name] = $value;
		return self::$_instance;
	}
	
	//// Test id the module manager has been instancied
	public static function ready() {
		return is_object(self::$_instance);
	}
	
	//// Return head tag to display
	public static function displayHead($index = null) {
		$index = is_string($index) && strlen($index) > 0 ? $index : (func_num_args() > 0 ? func_get_arg(0) : null); 
		if($index && isset(self::$_instance->_heads[$index])) {
			foreach(self::$_instance->_heads[$index] as $value) echo $value;
		}
	}
	
	//// Add new entry to script tag head value
	public static function scriptTag($script, $data = null) {
		if(!isset(self::$_instance->_heads['script'])) self::$_instance->_heads['script'] = [];
		$attributs = arrayToString($data);
		if(filter_var($script, FILTER_VALIDATE_URL)) self::$_instance->_heads['script'][md5('<script src="'.$script.'"'.$attributs.'></script>')] = '<script src="'.$script.'"'.$attributs.'></script>'; 
		else if(is_string($script) && strlen($script) > 0 && loader::exists($script)) self::$_instance->_heads['script'][md5('<script src="'.URL.'/includes/functions/'.$script.'"'.$attributs.'></script>')] = '<script src="'.URL.'/includes/functions/'.$script.'"'.$attributs.'></script>'; 
		else if(!preg_match('#(<script)#ui', $script)) self::$_instance->_heads['script'][md5($script)] = $script;
		return self::$_instance;
	}
	
	//// Add new entry to link tag head value
	public static function linkTag($link, $data = null) {
		if(!isset(self::$_instance->_heads['link'])) self::$_instance->_heads['link'] = [];
		$attributs = arrayToString($data);
		if(filter_var($link, FILTER_VALIDATE_URL)) self::$_instance->_heads['link'][md5('<link rel="stylesheet" type="text/css" href="'.$link.'"'.$attributs.'/>')] = '<link rel="stylesheet" type="text/css" href="'.$link.'"'.$attributs.'/>'; 
		else if(is_string($link) && strlen($link) > 0 && loader::exists($link)) self::$_instance->_heads['link'][md5('<link rel="stylesheet" type="text/css" href="'.URL.'/includes/functions/'.$link.'"'.$attributs.'/>')] = '<link rel="stylesheet" type="text/css" href="'.URL.'/includes/functions/'.$link.'"'.$attributs.'/>'; 
		else if(!preg_match('#(<link)#ui', $link)) self::$_instance->_heads['link'][md5($link)] = $link;
		return self::$_instance;
	}
	
	//// Add new entry to head value
	public static function metaTag($meta, $data = null) {
		if(!isset(self::$_instance->_heads['meta'])) self::$_instance->_heads['meta'] = [];
		if(!preg_match('#(<meta)#ui', $meta)) self::$_instance->_heads['meta'][md5($meta)] = $meta;
		return self::$_instance;
	}
}