<?php
/**
* @version	$Id: hook_manager.php 15130 2012-03-03 18:38:32Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2010 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

defined('FULL_PATH') or die('restricted access!');

class kHookManager extends kBase implements kiCacheable {

	/**
	 * Holds before hooks
	 * key - prefix.event (to link to)
	 * value - hooked event info
	 *
	 * @var Array
	 * @access protected
	 */
	protected $beforeHooks = Array ();

	/**
	 * Holds after hooks
	 * key - prefix.event (to link to)
	 * value - hooked event info
	 *
	 * @var Array
	 * @access protected
	 */
	protected $afterHooks = Array ();

	/**
	 * Sets data from cache to object
	 *
	 * @param Array $data
	 * @access public
	 */
	public function setFromCache(&$data)
	{
		$this->beforeHooks = $data['EventManager.beforeHooks'];
		$this->afterHooks = $data['EventManager.afterHooks'];
	}

	/**
	 * Gets object data for caching
	 *
	 * @return Array
	 * @access public
	 */
	public function getToCache()
	{
		return Array (
			'EventManager.beforeHooks' => $this->beforeHooks,
			'EventManager.afterHooks' => $this->afterHooks
		);
	}

	/**
	 * Returns hooks by mode
	 *
	 * @param int $mode
	 * @return Array
	 * @access protected
	 */
	protected function &getHooksByMode($mode)
	{
		if ($mode == hBEFORE) {
			return $this->beforeHooks;
		}

		return $this->afterHooks;
	}

	/**
	 * Registers Hook from subprefix event to master prefix event
	 *
	 * @param string $hook_event
	 * @param string $do_event
	 * @param int $mode
	 * @param bool $conditional
	 * @access public
	 */
	public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false)
	{
		$hook_event = new kEvent($hook_event);
		$do_event = new kEvent($do_event);

		if ( ($hook_event->Prefix != '*') && !$this->Application->prefixRegistred($hook_event->Prefix) ) {
			if ($this->Application->isDebugMode()) {
				trigger_error('Prefix <strong>' . $hook_event->Prefix . '</strong> doesn\'t exist when trying to hook from <strong>' . (string)$do_event . '</strong>', E_USER_WARNING);
			}

			return;
		}

		$hooks =& $this->getHooksByMode($mode);
		$hook_key = str_replace(':', '.', (string)$hook_event);

		$hooks[ strtolower($hook_key) ][] = Array (
			'DoPrefix' => $do_event->Prefix,
			'DoSpecial' => $do_event->Special,
			'DoEvent' => $do_event->Name,
			'Conditional' => $conditional,
		);
	}

	/**
	 * Runs hooks for given event
	 *
	 * @param kEvent $event
	 * @param int $mode hBEFORE or hAFTER
	 * @access public
	 */
	public function runHooks($event, $mode)
	{
		// * - get hooks that are valid with any special of given prefix
		$hooks = array_merge(
			// given prefix, any special
			$this->_getHooks($event, $mode, $event->Prefix.'.*'),

			// given special, given special
			$this->_getHooks($event, $mode),

			// any prefix, any special
			$this->_getHooks($event, $mode, '*.*'),

			// any prefix, given special
			$this->_getHooks($event, $mode, rtrim('*.' . $event->Special, '.'))
		);

		if (!$hooks) {
			return ;
		}

		foreach ($hooks as $hook) {
			if ($hook['DoSpecial'] == '*') {
				// use same special as master event
				$hook['DoSpecial'] = $event->Special;
			}

			$prefix_special = rtrim($hook['DoPrefix'].'_'.$hook['DoSpecial'], '_');

			if ( $hook['Conditional'] && !$this->Application->GetVar($prefix_special) ) {
				continue;
			}

			if ( $this->Application->prefixRegistred($hook['DoPrefix']) ) {
				// run hook only, when it's config is found
				$hook_event = new kEvent($hook['DoPrefix'] . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent']);
				$hook_event->MasterEvent =& $event;
				$this->Application->HandleEvent($hook_event);
			}
		}
	}

	/**
	 * Returns hooks for given event
	 *
	 * @param kEvent $event
	 * @param int $mode hBEFORE or hAFTER
	 * @param string $event_key
	 * @return Array
	 * @access protected
	 */
	protected function &_getHooks($event, $mode, $event_key = null)
	{
		$hooks =& $this->getHooksByMode($mode);
		$event_key = isset($event_key) ? $event_key : $event->getPrefixSpecial();

		if (!isset($hooks[strtolower($event_key.'.'.$event->Name)])) {
			$ret = Array ();

			return $ret;
		}

		return $hooks[ strtolower($event_key.'.'.$event->Name) ];
	}
}