<?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
///////////////////////////////////////////////////////////////////////////////////////////

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

class pool {
	/*** @var _mode string*/
	private $_mode;
	/*** @var _controller string*/
	private $_controller;
	/*** @var _pool array*/
	private $_pool = [];
	/*** @var _hooks array*/
	private $_hooks = [];
	/*** @var _instance self*/
	private static $_instance;
	
	//// Class constructor
	public function __construct($mode = null, $controller = null, $dir = null) {
		$this->_mode = isset($mode) && $mode === 'SP' ? 'SP' : 'front';
		$cachefile = (isset($dir) && strlen($dir) > 0 ? $dir.'/' : '').'cache'.($this->_mode === 'SP' ? '_adm' : '').'/cache_hooks'.($this->_mode === 'SP' ? '_adm' : '').'.php';
		require_once($cachefile);
		if($this->_mode === 'SP') {
			$this->_hooks = ['spBeforestart']; 
			if(!isAjax()) $this->_hooks[] = 'spBeforeend';
		} else {
			$this->_hooks = ['beforestart'];
			if(!isAjax()) $this->_hooks[] = 'beforeend';
		}
		$this->_pool = [
			'beforedispatch' => [],
			'beforestart' => [],
			'beforeend' => [],
			'postdispatch' => [],
		];
		$controller = pathinfo((isset($controller) && strlen($controller) > 0 ? $controller : $_SERVER['SCRIPT_NAME']),  PATHINFO_FILENAME);
		if($controller === 'module') $this->_pool[($this->_mode === 'SP' ? 'spModule' : 'module')] = [];
		if(isset($cache_hooks) && isset($cache_hooks['*'])) {
			$this->_hooks = array_merge($this->_hooks, $cache_hooks['*']);
			foreach($cache_hooks['*'] as $hook) $this->_pool[$hook] = [];
		}
		if(isset($cache_hooks) && isset($cache_hooks[$controller])) {
			$this->_hooks = array_merge($this->_hooks, $cache_hooks[$controller]);
			foreach($cache_hooks[$controller] as $hook) {
				if(is_array($hook)) {
					$this->_pool[$hook[0]] = [];
					foreach($hook[1] as $elt) {
						$callable = self::isCallable($elt);
						if(is_array($callable) && isset($callable['action'])) $this->_pool[$hook[0]][$callable['key']] = $callable;
					}
				} else $this->_pool[$hook] = [];
			}
		}
	}
	
	//// Return self instance after create it if not exists
	public static function init($mode = null, $controller = null, $dir = null) {
		if (self::$_instance == NULL) self::$_instance = new self($mode, $controller, $dir);
		return self::$_instance;
	}
	
	//// Return all hooks who can trigger action
	public static function hooks() {
		return self::$_instance->_hooks;
	}
	
	//// Return all action to execcute
	public static function pool($hook = null) {
		return isset($hook) && strlen($hook) > 0 ? (isset(self::$_instance->_pool[$hook]) ? self::$_instance->_pool[$hook] : null) : self::$_instance->_pool; 
	}
	
	//// Add new entry to script tag head value
	public static function add($hook, $action) {
		$callable = self::isCallable($action);
		if(is_array($callable) && isset($callable['action'])) {
			self::$_instance->_pool[$hook][$callable['key']] = $callable;
		}
		return self::$_instance;
	}
	
	//// REmove entry to script tag head value
	public static function remove($hook, $action = null) {
		$result = false;
		if(isset(self::$_instance->_pool[$hook])) {
			if($action) {
				if(isset(self::$_instance->_pool[$hook][$action])) unset(self::$_instance->_pool[$hook][$action]);
			}
		}
		return $result;
	}
	
	//// Replace entry to script tag head value
	public static function replace($hook, $key, $action) {
		if(isset(self::$_instance->_pool[$hook]) && isset(self::$_instance->_pool[$hook][$key])) self::$_instance::add($hook, $action);
		return self::$_instance;
	}
	
	//// Execute action attached to called hook
	public static function execute($hook) {
		global $language, $language_adm;
		$result = false;
		if(isset($hook) && isset(self::$_instance->_pool[$hook])) {
			$result = [];
			foreach(self::$_instance->_pool[$hook] as $key => $value) {
				$data = func_num_args() > 1 ? array_slice(func_get_args(), 1) : null;
				$action_data = isset($data) ? ($value['data'] + $data) : $value['data'];
				$tmp_result = call_user_func_array($value['action'], $action_data);
				$result[] = $tmp_result;
			}
		}
		return $result;
	}
	
	//// Test if action is callable
	public static function isCallable($action) {
		$callable = false;
		if(is_array($action)) {
			if(is_object($action[0]) || (is_string($action[0]) && isset($action[1]))) {
				$callable['action'] = [$action[0], $action[1]];
				$key = get_class($action[0]) ==  'modules' ? 'default' : $action[0]->name();
				$callable['key'] = strtolower($key.'_'. $action[1]);
			} else {
				$callable['action'] = $action[0];
				$callable['key'] = strtolower($action[0]);
			}
			$callable['data'] = isset($action[2]) ? [$action[2]] : [];
		} else if(is_string($action) && function_exists($action)) {
			$callable['action'] = $action;
			$callable['key'] = strtolower($action);
			$callable['data'] = [];
		}
		return $callable;
	}

	//// Format hook name
	public static function clean($string) {
		return preg_replace('#(\-|_)#ui', '', $string);
	}
}