
// ==== Function.bind ==========================================================

Function.prototype.bind = function(io_object) {
  var method = this;
  return function() { return method.apply(io_object, arguments); };
};



/*---------------------------------------------------------------------------*
 * -- zEvent
 *---------------------------------------------------------------------------*
 *  Custom events that can call functions or methods when fired
 *---------------------------------------------------------------------------*/
 
/**
 * zEvent() -- Creates a new event
 */
function zEvent() {
  this.ma_listeners = new Array();
}

/**
 * zEvent.subscribe() -- subscribes a function or method to the event
 *   if_action   - function to subscribe
 *   io_listener - object to call the function as a method of
 */
zEvent.prototype.subscribe = function( if_action, io_listener ) {
  var lf_bound = null;

  if( io_listener != null ) { lf_bound = if_action.bind( io_listener ); }
  else { lf_bound = if_action; }

  this.ma_listeners.push( { mf_action : if_action,
                            mo_listener : io_listener,
                            mf_bound : lf_bound } );
};

/**
 * zEvent.unsubscribe() -- removes a listener from the event; see subscribe()
 */
zEvent.prototype.unsubscribe = function( if_action, io_listener ) {
  for( var i = this.ma_listeners.length - 1; i >= 0; i-- ) {
    if(    this.ma_listeners[i].mf_action   == if_action
        && this.ma_listeners[i].mo_listener == io_listener ) {
      this.ma_listeners[i].mf_action = null;
      this.ma_listeners[i].mo_listener = null;
      this.ma_listeners.splice(i,1);
    }
  }
};

/**
 * zEvent.fire() -- fires the event, passing arguments to listeners
 */
zEvent.prototype.fire = function( io_args, io_sender ) {
  for( var i = 0; i < this.ma_listeners.length; i++ ) {
    this.ma_listeners[i].mf_bound( io_args, io_sender );
  }
};

/**
 * zEvent.hasListeners() -- returns true if anything is listening for the event
 */
zEvent.prototype.hasListeners = function() {
  return ( this.ma_listeners.length != 0 );
};


/**
 * zEvent.destroy() -- call to ensure the event isn't keeping any objects
 *                       in memory by accident
 */
zEvent.prototype.destroy = function() {
  this.ma_listeners = null;
};
