/**
 *
 *  @provides event-extensions
 */

/**
 *  Chain two or more event handlers together, returning a function that calls
 *  them in sequence. Note that these functions are treated like event
 *  functions: if one of them returns a strict `false', execution will abort and
 *  subsequent functions WILL NOT be called.
 *
 *  The common use case is making sure you don't overwrite existing event
 *  handlers:
 *
 *  <js>
 *    button.onclick = chain(button.onclick, additionalHandler);
 *  </js>
 *
 *  It is safe to pass `null' values to chain, so it's probably not a bad idea
 *  to use this idiom generally when performing event assignments.
 *
 *  @params Zero or more functions to chain together
 *
 *  @return A function which executes the arguments in order, aborting if any
 *          return a strict `false'. This function will return `false' to
 *          indicate that some component function aborted event bubbling, or
 *          `true' to indicate that all functions executed.
 *
 *  @author epriestley
 */
function chain( u, v /*, w, x ... */ ) {

  var calls = [];
  for (var ii = 0; ii < arguments.length; ii++) {
    calls.push(arguments[ii]);
  }

  return function( ) {
    for (var ii = 0; ii < calls.length; ii++) {
      if ( calls[ii] && calls[ii].apply( this, arguments ) === false ) {
        return false;
      }
    }
    return true;
  }

}


// === Event Attaching ===
// (see: http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html)

// why name_hash? So you can use the same function and pass different name_hashes and ie won't get confused
function addEventBase(obj, type, fn, name_hash)
{
  if (obj.addEventListener) {
    obj.addEventListener( type, fn, false );
  }
  else if (obj.attachEvent)
  {
    var fn_name = type+fn+name_hash;
    obj["e"+fn_name] = fn;
    obj[fn_name] = function() { obj["e"+fn_name]( window.event ); }
    obj.attachEvent( "on"+type, obj[fn_name] );
  }

  return fn;

}

function removeEventBase(obj, type, fn, name_hash)
{
  if (obj.removeEventListener) {
    obj.removeEventListener( type, fn, false );
  }
  else if (obj.detachEvent)
  {
    var fn_name = type+fn+name_hash;
    if (obj[fn_name]) {
      obj.detachEvent( "on"+type, obj[fn_name]);
      obj[fn_name] = null;
      obj["e"+fn_name] = null;
    }
  }
}



// for IE
function event_get(e) {
  return e || window.event;
}

/**
 *  @browser Safari, Firefox
 *    Event target is in `target'.
 *
 *  @browser IE
 *    Event target is in `srcElement'.
 */
function event_get_target(e) {
  return (e = event_get(e)) && (e['target'] || e['srcElement']);
}

function event_abort(e) {
  (e = event_get(e)) && (e.cancelBubble = true) &&
    e.stopPropagation && e.stopPropagation();
  return false;
}

function event_prevent(e) {
  (e = event_get(e)) && !(e.returnValue = false) &&
    e.preventDefault && e.preventDefault();
  return false;
}

function event_kill(e) {
  return event_abort(e) || event_prevent(e);
}

function event_get_keypress_keycode(event) {
  event = event_get(event);
  if (!event) {
    return false;
  }
  switch (event.keyCode) {
    case 63232: // up
      return 38;
    case 63233: // down
      return 40;
    case 63234: // left
      return 37;
    case 63235: // right
      return 39;
    case 63272: // delete
    case 63273: // home
    case 63275: // end
      return null; // IE doesn't support these so they shouldn't be used
    case 63276: // page up
      return 33;
    case 63277: // page down
      return 34;
  }
  if (event.shiftKey) {
    switch (event.keyCode) {
      case 33: // page up
      case 34: // page down
      case 37: // left
      case 38: // up
      case 39: // right
      case 40: // down
        return null; // "!" (and others) can not be detected with this abstraction,
                     // but there will never be a false position on arrow keys
    }
  } else {
    return event.keyCode;
  }
}

function stopPropagation(e) {
    if (!e) var e = window.event;
    e.cancelBubble = true;
    if (e.stopPropagation) {
        e.stopPropagation();
    }
}


function DevSiteMenuBar (core_id){
  this.TIMEOUT = 250;
  this.core_div = document.getElementById(core_id);
  this.dropdowns = [];
  this.last_out = (new Date()).getTime();
}


  DevSiteMenuBar.prototype.show_dropdown_func = function (dropdown){
    return function(){
      if (dropdown['over']){
        dropdown['menu'].className = 'fb_menu_dropdown';
        dropdown['link'].className = 'fbmenuhover';
      }
    };
  };

  DevSiteMenuBar.prototype.hide_dropdown_func = function (dropdown){
    return function(){
      if (!dropdown['over']){
        dropdown['menu'].className = "fb_menu_dropdown hidden_elem";
        dropdown['link'].className = "";
      }
    };
  };
  
  DevSiteMenuBar.prototype.over_listener = function (dropdown){
    var mThis = this;
    var f = function(event){
      dropdown['over'] = true;
      if (((new Date()).getTime() - mThis.last_out) < mThis.TIMEOUT){
        mThis.hide_dropdowns();
        mThis.show_dropdown_func(dropdown)();
      } else {
        setTimeout(mThis.show_dropdown_func(dropdown), mThis.TIMEOUT);
      }

    };
    return f;
  };

  DevSiteMenuBar.prototype.out_listener = function (dropdown){
    var mThis = this;
    return function(event){
      dropdown['over'] = false;
      setTimeout(mThis.hide_dropdown_func(dropdown), mThis.TIMEOUT);
      mThis.last_out = (new Date()).getTime();
    };
  };

  /**
    * Digs through the dom starting at core_div and updates
    * the dropdowns array
    */
  DevSiteMenuBar.prototype.update_dropdowns = function(){
    this.dropdowns = [];
    var divs = this.core_div.getElementsByTagName('div');
    for (var i = 0; i<divs.length; i++){
      if (divs[i].className.indexOf('fb_menu_dropdown') != -1){
        var dropdown_menu = divs[i];
        var dropdown_link = divs[i].parentNode.getElementsByTagName('a')[0];
        this.dropdowns.push({'menu': dropdown_menu, 'link': dropdown_link, 'over': false});
      }
    }
  };

  DevSiteMenuBar.prototype.add_dropdown_listeners = function(){
    for(var i=0; i<this.dropdowns.length; i++){
      addEventBase(this.dropdowns[i]['link'],'mouseover',this.over_listener(this.dropdowns[i]), false);
      addEventBase(this.dropdowns[i]['link'],'mouseout',this.out_listener(this.dropdowns[i]), false);
      addEventBase(this.dropdowns[i]['menu'],'mouseover',this.over_listener(this.dropdowns[i]), false);
      addEventBase(this.dropdowns[i]['menu'],'mouseout',this.out_listener(this.dropdowns[i]), false);
    }
  };
 
  DevSiteMenuBar.prototype.hide_dropdowns = function(){
    for(var i = 0; i<this.dropdowns.length; i++){
      this.dropdowns[i]['menu'].className = 'fb_menu_dropdown hidden_elem';
      this.dropdowns[i]['link'].className = '';
    }
  };

  DevSiteMenuBar.prototype.init = function(){
    this.update_dropdowns();
    this.hide_dropdowns();
    this.add_dropdown_listeners();
  };
