/**
 * @file A WordPress-like hook system for JavaScript.
 *
 * This file demonstrates a simple hook system for JavaScript based on the hook
 * system in WordPress. The purpose of this is to make your code extensible and
 * allowing other developers to hook into your code with their own callbacks.
 *
 * There are other ways to do this, but this will feel right at home for
 * WordPress developers.
 *
 * @author Rheinard Korf
 * @license GPL2 (https://www.gnu.org/licenses/gpl-2.0.html)
 *
 * @requires underscore.js (http://underscorejs.org/)
 */

/**
 * Hooks object
 *
 * This object needs to be declared early so that it can be used in code.
 * Preferably at a global scope.
 */
 var Hooks = Hooks || {}; // Extend Hooks if exists or create new Hooks object.

 Hooks.actions = Hooks.actions || {}; // Registered actions
 Hooks.filters = Hooks.filters || {}; // Registered filters
 
 /**
  * Add a new Action callback to Hooks.actions
  *
  * @param tag The tag specified by do_action()
  * @param callback The callback function to call when do_action() is called
  * @param priority The order in which to call the callbacks. Default: 10 (like WordPress)
  */
 Hooks.add_action = function( tag, callback, priority ) {
 
     if( typeof priority === "undefined" ) {
         priority = 10;
     }
 
     // If the tag doesn't exist, create it.
     Hooks.actions[ tag ] = Hooks.actions[ tag ] || [];
     Hooks.actions[ tag ].push( { priority: priority, callback: callback } );
 
 }
 
 /**
  * Add a new Filter callback to Hooks.filters
  *
  * @param tag The tag specified by apply_filters()
  * @param callback The callback function to call when apply_filters() is called
  * @param priority Priority of filter to apply. Default: 10 (like WordPress)
  */
 Hooks.add_filter = function( tag, callback, priority ) {
 
     if( typeof priority === "undefined" ) {
         priority = 10;
     }
 
     // If the tag doesn't exist, create it.
     Hooks.filters[ tag ] = Hooks.filters[ tag ] || [];
     Hooks.filters[ tag ].push( { priority: priority, callback: callback } );
 
 }
 
 /**
  * Remove an Anction callback from Hooks.actions
  *
  * Must be the exact same callback signature.
  * Warning: Anonymous functions can not be removed.
  * @param tag The tag specified by do_action()
  * @param callback The callback function to remove
  */
 Hooks.remove_action = function( tag, callback ) {
 
     Hooks.actions[ tag ] = Hooks.actions[ tag ] || [];
 
     Hooks.actions[ tag ].forEach( function( filter, i ) {
         if( filter.callback === callback ) {
             Hooks.actions[ tag ].splice(i, 1);
         }
     } );
 }
 
 /**
  * Remove a Filter callback from Hooks.filters
  *
  * Must be the exact same callback signature.
  * Warning: Anonymous functions can not be removed.
  * @param tag The tag specified by apply_filters()
  * @param callback The callback function to remove
  */
 Hooks.remove_filter = function( tag, callback ) {
 
     Hooks.filters[ tag ] = Hooks.filters[ tag ] || [];
 
     Hooks.filters[ tag ].forEach( function( filter, i ) {
         if( filter.callback === callback ) {
             Hooks.filters[ tag ].splice(i, 1);
         }
     } );
 }
 
 /**
  * Calls actions that are stored in Hooks.actions for a specific tag or nothing
  * if there are no actions to call.
  *
  * @param tag A registered tag in Hook.actions
  * @options Optional JavaScript object to pass to the callbacks
  */
 Hooks.do_action = function( tag, options ) {
 
     var actions = [];
 
     if( typeof Hooks.actions[ tag ] !== "undefined" && Hooks.actions[ tag ].length > 0 ) {
 
         Hooks.actions[ tag ].forEach( function( hook ) {
 
             actions[ hook.priority ] = actions[ hook.priority ] || [];
             actions[ hook.priority ].push( hook.callback );
 
         } );
 
         actions.forEach( function( hooks ) {
 
             hooks.forEach( function( callback ) {
                 callback( options );
             } );
 
         } );
     }
 
 }
 
 /**
  * Calls filters that are stored in Hooks.filters for a specific tag or return
  * original value if no filters exist.
  *
  * @param tag A registered tag in Hook.filters
  * @options Optional JavaScript object to pass to the callbacks
  */
 Hooks.apply_filters = function( tag, value, options ) {
 
     var filters = [];
 
     if( typeof Hooks.filters[ tag ] !== "undefined" && Hooks.filters[ tag ].length > 0 ) {
 
         Hooks.filters[ tag ].forEach( function( hook ) {
 
             filters[ hook.priority ] = filters[ hook.priority ] || [];
             filters[ hook.priority ].push( hook.callback );
         } );
 
         filters.forEach( function( hooks ) {
 
             hooks.forEach( function( callback ) {
                 value = callback( value, options );
             } );
 
         } );
     }
 
     return value;
 }

 
export default Hooks