<?php
/**
 * Burrow
 *
 * PHP version 5
 *
 * @category   PHP
 * @package    Burrow
 * @subpackage Core
 * @author     Agriya <info@agriya.com>
 * @copyright  2018 Agriya Infoway Private Ltd
 * @license    http://www.agriya.com/ Agriya Infoway Licence
 * @link       http://www.agriya.com
 */
App::uses('CakeEventManager', 'Event');
/**
 * Cms Event Manager class
 *
 * Descendant of CakeEventManager, customized to map event listener objects
 *
 * @since 1.4
 * @see CakeEventManager
 */
class CmsEventManager extends CakeEventManager
{
    /**
     * A map of registered event listeners
     */
    protected $_listenersMap = array();
    /**
     * Returns the globally available instance of a CmsEventManager
     * @return CmsEventManager the global event manager
     */
    public static function instance($manager = null)
    {
        if (empty(self::$_generalManager)) {
            return parent::instance(new CmsEventManager());
        }
        return parent::instance($manager);
    }
    /**
     * Load Event Handlers during bootstrap.
     *
     * Plugins can add their own custom EventHandler in Config/events.php
     * with the following format:
     *
     * $config = array(
     *     'EventHandlers' => array(
     *         'Example.ExampleEventHandler' => array(
     *             'eventKey' => null,
     *             'options' => array(
     *                 'priority' => 1,
     *                 'passParams' => false,
     *      )));
     *
     * @return void
     */
    public static function loadListeners()
    {
        $eventManager = CmsEventManager::instance();
        $cached = Cache::read('EventHandlers', 'setting_write_configuration');
        if ($cached === false) {
            $eventHandlers = Configure::read('EventHandlers');
            $validKeys = array(
                'eventKey' => null,
                'options' => array()
            );
            $cached = array();
            if (!empty($eventHandlers) && is_array($eventHandlers)) {
                foreach($eventHandlers as $eventHandler => $eventOptions) {
                    $eventKey = null;
                    if (is_numeric($eventHandler)) {
                        $eventHandler = $eventOptions;
                        $eventOptions = array();
                    }
                    list($plugin, $class) = pluginSplit($eventHandler);
                    if (!empty($eventOptions)) {
                        extract(array_intersect_key($validKeys, $eventOptions));
                    }
                    App::uses($class, $plugin . '.Event');
                    if (class_exists($class)) {
                        $cached[] = compact('plugin', 'class', 'eventKey', 'eventOptions');
                    } else {
                        logError(sprintf(__l('EventHandler %s not found in plugin %s'), $class, $plugin));
                    }
                }
            }
        }
        foreach($cached as $cache) {
            extract($cache);
            if (CakePlugin::loaded($plugin)) {
                App::uses($class, $plugin . '.Event');
                $listener = new $class();
                $eventManager->attach($listener, $eventKey, $eventOptions);
            }
        }
    }
    /**
     * Adds a new listener to an event.
     * @see CakeEventManager::attach()
     * @return void
     */
    public function attach($callable, $eventKey = null, $options = array())
    {
        parent::attach($callable, $eventKey, $options);
        if (is_object($callable)) {
            $key = get_class($callable);
            $this->_listenersMap[$key] = $callable;
        }
    }
    /**
     * Removes a listener from the active listeners.
     * @see CakeEventManager::detach()
     * @return void
     */
    public function detach($callable, $eventKey = null)
    {
        if (is_object($callable)) {
            $key = get_class($callable);
            unset($this->_listenersMap[$key]);
        }
        parent::detach($callable, $eventKey);
    }
    /**
     * Detach all listener objects belonging to a plugin
     * @param $plugin string
     * @return void
     */
    public function detachPluginSubscribers($plugin)
    {
        $eventHandlers = Configure::read('EventHandlers');
        if (empty($eventHandlers)) {
            return;
        }
        $eventHandlers = array_keys($eventHandlers);
        $eventHandlers = preg_grep('/^' . $plugin . '/', $eventHandlers);
        foreach($eventHandlers as $eventHandler) {
            list(, $class) = pluginSplit($eventHandler);
            if (isset($this->_listenersMap[$class])) {
                $this->detach($this->_listenersMap[$class]);
            }
        }
    }
}
