<?php

$hooks = array();

/**
 * Registered a hook on a specific event
 *
 * @param[in] $event string The event name
 * @param[in] $callable callable The callable to run on event
 * @param[in] $param mixed Paremeter that will be pass to the callable
 *                         Use an array if you have multiple parameters to pass
 *
 * @retval void
 */
function register_hook($event, $callable, $param=NULL) {
	global $hooks;
	if (!array_key_exists($event, $hooks))
		$hooks[$event] = array();
	$hooks[$event][] = array (
		'callable' => $callable,
		'param'    => $param,
	);
}

/**
 * Run triggered actions on specific event
 *
 * @param[in] $event string Event name
 *
 * @retval boolean True if all triggered actions succefully runned, false otherwise
 */
function trigger_hook($event_name, $event_data=null) {
	global $hooks;
	$return = true;

	if (isset($hooks[$event_name]) && is_array($hooks[$event_name])) {
		if ($event_name == 'all')
			$event = new Event($event_data['event_name'], $event_data['event_data']);
		else
			$event = new Event($event_name, $event_data);
		foreach ($hooks[$event_name] as $e) {
			if (is_callable($e['callable'])) {
				try {
					call_user_func_array($e['callable'],array($event, &$e['param']));
				}
				catch(Exception $e) {
					logException($e, "An exception occured running hook ".format_callable($e['callable'])." on event $event_name");
					$return = false;
				}
			}
			else {
				logging('ERROR', "The hook ".format_callable($e['callable'])." on event $event_name is not callable.");
				$return = false;
			}
		}
	}
	else
		logging('DEBUG', "No hook registered for event $event_name.");

	// Handle 'all' event
	if ($event_name != 'all') {
		trigger_hook (
			'all',
			array (
				'event_name' => $event_name,
				'event_data' => $event_data,
			)
		);
	}

	return $return;
}

class Event implements JsonSerializable {
	private $name;
	private $data;

	function __construct($name, $data) {
		$this -> name = $name;
		$this -> data = $data;
	}

	function __get($key) {
		if ($key == 'name')
			return $this -> name;
		elseif ($key == 'data')
			return $this -> data;
		elseif (is_array($this -> data) && array_key_exists($key, $this -> data))
			return $this -> data[$key];
		return null;
	}

	public function jsonSerialize() {
		return array (
			'name' => $this -> name,
			'data' => $this -> data,
		);
	}
}