<?php
/**
 * Models for creating factory for hookable
 * system.
 *
 * @author jason.xie@victheme.com
 */
class VTCore_Wordpress_Models_Hooks
implements VTCore_Wordpress_Interfaces_Factory {


  protected $classes = array();
  protected $registry = array();
  protected $overloaderPrefix = array();
  protected $loaded = array();
  protected $hookFunction;




  /**
   * Construct method
   */
  public function __construct() {

    // Check if we should bypass cache
    $this->maybeByPassCache();

    // Load cache
    $this->loadCache();

  }



  /**
   * Method for checking if class should bypass cache
   * @return VTCore_Wordpress_Factory_Layout
   */
  public function maybeByPassCache() {
    // Wordpress on debug mode
    if ((defined('WP_DEBUG') && WP_DEBUG)
        || (defined('VTCORE_CLEAR_CACHE') && VTCORE_CLEAR_CACHE)) {

      $this->clearCache();
    }

    return $this;
  }


  /**
   * Method for loading from cache
   * @return VTCore_Wordpress_Factory_Layout
   */
  public function loadCache() {
    $this->classes = get_transient('vtcore_hook_classes_registry_' . $this->hookFunction);
    return $this;
  }



  /**
   * Method for clearing cached elements
   * @return VTCore_Wordpress_Factory_Layout
   */
  public function clearCache() {
    delete_transient('vtcore_hook_classes_registry_' . $this->hookFunction);
    return $this;
  }



  public function register() {

    foreach ($this->registry as $registered) {

      foreach ($this->overloaderPrefix as $prefix) {

        $class = $prefix . str_replace('_', '__', ucfirst($registered));
        $name = '';

        if (isset($this->classes[$class])) {
          if ($this->classes[$class]) {
            $name = $class;
          }
        }
        else {

          if (class_exists($class, true)) {
            $this->classes[$class] = true;
            $name = $class;
          }
          else {
            //$this->classes[$class] = false;
          }
        }

        // Prevent double loading
        if (empty($name) || $this->checkLoaded($name)) {
          continue;
        }

        $object = new $name();
        $function = $this->hookFunction;

        if ($object instanceof VTCore_Wordpress_Models_Hook && is_callable($function)) {

          $hash = _wp_filter_build_unique_id($registered, array($object, 'hook'), $object->getWeight());
          $function($registered, array($object, 'hook'), $object->getWeight(), $object->getArgument());

          $this->addLoaded($name, array(
            'name' => $name,
            'hash' => $hash,
            'hook' => $registered,
            'weight' => $object->getWeight(),
          ));
        }

        unset($object);
      }
    }

    set_transient('vtcore_hook_classes_registry', $this->classes, 12 * HOUR_IN_SECONDS);

  }


  /**
   * Method for checking if the action is already
   * loaded into Wordpress or not.
   */
  public function checkLoaded($name) {
    return isset($this->loaded[$name]);
  }



  /**
   * Method for adding action class name
   * into loaded array database
   */
  protected function addLoaded($name, array $context) {
    if (!isset($this->loaded[$name])) {
      $this->loaded[$name] = $context;
    }

    return $this;
  }


  /**
   * Method for adding a new action into the
   * action array database.
   */
  public function addHook($hook) {

    if (!in_array($hook, $this->registry)) {
      $this->registry[] = $hook;
    }

    return $this;
  }


  /**
   * Registering multiple actions at once
   */
  public function addHooks(array $hooks) {
    $this->registry = array_merge($this->registry, $hooks);
    return $this;
  }


  /**
   * Method for removing action
   * This method must be invoked after register()
   * and valid child action class name must be
   * passed as the argument
   *
   * @param string $name
   */
  public function removeHook($name) {
    if (isset($this->loaded[$name])) {

      extract($this->loaded[$name]);

      if (isset($GLOBALS['wp_filter'][$hook][$weight][$hash])) {
        unset($GLOBALS['wp_filter'][$hook][$weight][$hash]);

        if (empty($GLOBALS['wp_filter'][$hook][$weight])) {
          unset($GLOBALS['wp_filter'][$hook][$weight]);
        }

        if (empty($GLOBALS['wp_filter'][$hook])) {
          $GLOBALS['wp_filter'][$hook] = array();
        }

        unset($GLOBALS['merged_filters'][$hook]);
      }
    }

    return $this;
  }


  /**
   * Method for adding a new class prefix so
   * the autoloader can pickup and invoke the
   * class when this class is trying to add
   * the action into wordpress
   */
  public function addPrefix($prefix) {
    if (!in_array($prefix, $this->overloaderPrefix)) {
      $this->overloaderPrefix[] = $prefix;
    }
    return $this;
  }
}