<?php

namespace EesyPHP;

use Exception;

class Hook {

  /**
   * Registered hooks
   * @var array
   */
  protected static $hooks = array();

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

  /**
   * Run triggered actions on specific event
   *
   * @param $event string Hook event name
   * @param $event_data mixed Hook event data (optional, default: null)
   *
   * @return boolean True if all triggered actions succefully runned, false otherwise
   */
  public static function trigger($event_name, $event_data=null) {
    $return = true;

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

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

    return $return;
  }
}

# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab