/*global Element, Event, $, $$, window */

/* namespace for scup wrapper scripts */
var ScupWrapper = {};

ScupWrapper.focusSearchBox = function () {
   var searchbox = $("scup-search-box");
   if (searchbox.hasClassName("masked")) {
      searchbox.removeClassName("masked");
      searchbox.value = "";
   }
};

/* handles a single submenu */
ScupWrapper.SubMenu = function () {
   this.constructor.apply(this, arguments);
};

ScupWrapper.SubMenu.prototype = {
   menu_out_delay: 400,
   parent: null,
   children: null,
   el: null,
   offset: null,
   in_menu_flag: false,
   
   constructor: function (menu_id, parent, is_root, parent_el) {
      this.children = [];
      this.parent = parent;
      this.is_root = is_root;
      if (!this.is_root) {
         this.parent.children.push(this);
      }
      if (this.is_root) {
         this.parent_el = parent;
      }
      else {
         this.parent_el = parent_el;
      }
      this.build(menu_id);
      this.position();
   },
   
   build: function (menu_id) {
      this.el = document.getElementById("scup-wrapper-submenu-" + menu_id);
      Element.down(this.el, 0).childElements().each(function (li) {
         var child_id = li.id.replace(/[a-zA-Z\-]+/, '');
         // strip out links from menu items because they make
         // mouseout tracking a real pain
         if (Element.down(li, 'a')) {
            var href = Element.down(li, 'a').href;
            li.innerHTML = Element.down(li, 0).innerHTML;
            li.observe("click", this.click_item.bind(this, href));
         }
         li.observe("mouseover", this.mouseover_item.bind(this, child_id, li));
         li.observe("mouseout", this.mouseout_item.bind(this, child_id, li));
      }, this);
   },
      
   position: function () {
      var offset = Element.cumulativeOffset(this.parent_el);
      var left = null;
      var top = null;
      
      // position the menu properly
      if (this.is_root) {
         top = offset.top + this.parent_el.offsetHeight;
         left = offset.left;
      }
      else {
         top = offset.top + 4;
         left = offset.left + this.parent_el.offsetWidth - 20;
      }
      
      // if the menu hangs off the right side of the page, move it
      var right_edge = ScupWrapper.menu.offsets.left + ScupWrapper.menu.offsets.width;
      if (left + ScupWrapper.menu.menu_width > right_edge) {
         // I'm not sure why I need the 8; trial and error...but why?
         left = right_edge - ScupWrapper.menu.menu_width - 8;
      }
      
      // if the menu overlaps the parent too much, switch to the other side
      if (!this.is_root && left - offset.left < 120) {
         left = offset.left + 20 - ScupWrapper.menu.menu_width;
      }

      this.el.style.top = top + "px";
      this.el.style.left = left + "px";
   },
   
   show: function () {
      this.el.style.display = "block";
      if (this.offset === null) {
         this.offset = this.el.cumulativeOffset();
         this.offset.right = this.offset.left + ScupWrapper.menu.menu_width;
         this.offset.bottom = this.offset.top + this.el.offsetHeight;
      }
   },
   
   hide: function () {
      this.el.style.display = "none";
   },
   
   visible: function () {
      return this.el.style.display === "block";
   },

   in_menu: function () {
      return this.in_menu_flag;
   },
   
   in_menu_or_child: function () {
      var in_child = false;
      
      this.children.each(function (x) {
         if (x.in_menu_or_child()) {
            in_child = true;
         }
      }, this);
      
      var in_root_parent = false;
      if (this.is_root && ScupWrapper.menu.in_root_menu(this.parent)) {
         in_root_parent = true;
      }
      
      return in_child || in_root_parent || this.in_menu();
   },
   
   show_or_hide: function () {
      if (this.in_menu_or_child()) {
         this.show();
      }
      else {
         this.hide();
         if (!this.is_root) {
            this.parent.show_or_hide();
         }
      }
   },
   
   show_or_hide_soon: function () {
      setTimeout(this.show_or_hide.bind(this), 100);
   },
   
   mouseover_item: function (menu_id, parent_el, e) {
      ScupWrapper.menu.must_be_out();
      
      this.in_menu_flag = true;
      Element.addClassName(this.el, "in");

      for (var i = 0; i < this.children.length; i++) {
         this.children[i].show_or_hide();
      }

      var menu = ScupWrapper.menu.menu_for_item(menu_id, this, false, parent_el);
      if (menu) {
         ScupWrapper.menu.clearTimeout();
         menu.show();
      }
      Event.stop(e);
   },
   
   mouseout_item: function (item, parent_el, e) {
      this.in_menu_flag = false;
      Element.removeClassName(this.el, "in");

      ScupWrapper.menu.setTimeout(function () {
         for (var i = 0; i < this.children.length; i++) {
            this.children[i].show_or_hide();
         }
   
         this.show_or_hide();
         if (!this.is_root) {
            this.parent.show_or_hide();
         }
      }.bind(this), ScupWrapper.menu.hide_delay);
      Event.stop(e);
   },
   
   click_item: function (href, e) {
      if (href) {
         location.href = href;
      }
   }
};

ScupWrapper.menu = {
   show_delay: 200,
   hide_delay: 400,
   menu_width: 200, // this needs to be changed in the CSS as well
   
   pop_timer: null,
   
   timer: null,
   in_out_timer: null,
   
   menu_cache: {},
   root_menu_element: null,
   
   in_menu_flag: false,
   
   setTimeout: function (fn, delay) {
      if (this.timer !== null) {
         clearTimeout(this.timer);
      }
      this.timer = setTimeout(function () {
         fn();
         this.timer = null;
      }.bind(this), delay);
   },
   
   clearTimeout: function () {
      if (this.timer !== null) {
         clearTimeout(this.timer);
      }
      this.timer = null;
   },
   
   setInOutTimeout: function (fn, delay) {
      if (this.in_out_timer !== null) {
         clearTimeout(this.in_out_timer);
      }
      this.in_out_timer = setTimeout(function () {
         fn();
         this.in_out_timer = null;
      }.bind(this), delay);
   },
   
   clearInOutTimer: function () {
      if (this.in_out_timer !== null) {
         clearTimeout(this.in_out_timer);
      }
      this.in_out_timer = null;
   },
   
   menu_for_item: function (menu_id, parent, is_root, parent_el) {
      var menu = this.menu_cache[menu_id];
      if (!menu) {
         if (document.getElementById("scup-wrapper-submenu-" + menu_id)) {
            menu = new ScupWrapper.SubMenu(menu_id, parent, is_root, parent_el);
            this.menu_cache[menu_id] = menu;
         }
      }
      return menu;
   },

   hover: function (idx, from_element, e) {
      // abort if this event is not because we left the menu
      var tg = (window.event) ? e.srcElement : e.target;
      var reltg = (e.relatedTarget) ? e.relatedTarget : e.fromElement;
      while (reltg !== null && reltg !== tg && reltg.nodeName !== 'BODY') {
         reltg= reltg.parentNode;
      }
      if (reltg === tg) {
         return;
      }
      this.root_menu_element = from_element;

      this.clearTimeout();
      if (this.menu_showing()) {
         this.show_or_hide_all();
      }
      else {
         this.show_or_hide_all_soon();
      }
            
      var submenu = document.getElementById("scup-wrapper-submenu-" + idx);
      if (submenu)
      {
         // once we're in the menu system, we don't delay poping new menus
         if (this.menu_showing()) {
            ScupWrapper.menu.show_sub_menu(idx, from_element);
         }
         else
         {
            this.setTimeout(function () {
               ScupWrapper.menu.show_sub_menu(idx, from_element);
            }, this.show_delay);
         }
      }
      Event.stop(e);
   },
   
   out: function (e) {
      if (e !== true) {
         // abort if this event is not because we left the menu
         var tg = (window.event) ? e.srcElement : e.target;
         var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
         while (reltg !== null && reltg !== tg && reltg.nodeName !== 'BODY') {
            reltg = reltg.parentNode;
         }
         if (reltg === tg) {
            return;
         }
      }

      // delay this just a moment for cross-border problems
      this.root_menu_element = null;
      this.show_or_hide_all_soon();
      Event.stop(e);
   },
   
   must_be_out: function () {
      this.root_menu_element = null;   
   },
   
   show_or_hide_all: function () {
      for (var id in this.menu_cache) {
         this.menu_cache[id].show_or_hide();
      }
   },
   
   show_or_hide_all_soon: function () {
      this.setTimeout(this.show_or_hide_all.bind(this), this.hide_delay);
   },
   
   in_root_menu: function (element) {
      return this.root_menu_element === element;
   },
   
   in_menu: function () {
      var in_menu = false;
      for (var id in this.menu_cache) {
         if (this.menu_cache[id].in_menu()) {
            in_menu = true;
         }
      }
      return in_menu;
   },
   
   menu_showing: function () {
      var showing = false;
      for (var id in this.menu_cache) {
         if (this.menu_cache[id].visible()) {
            showing = true;
            break;
         }
      }
      return showing;
   },

   show_sub_menu: function (idx, from_element) {
      var menu = ScupWrapper.menu.menu_for_item(idx, from_element, true);
      menu.show();
   },
   
   stop_listener: function (e) {
      e.stop();
   }
};

Event.observe(window, "load", function () {
   if ($("scup-wrapper-menu")) {
      ScupWrapper.menu.offsets = Element.cumulativeOffset($("scup-wrapper-menu"));
      ScupWrapper.menu.offsets.width = $("scup-wrapper-menu").offsetWidth;
   
      // stop events inside menu elements
      $$("#scup-wrapper-menu UL *").each(function (element) {
         if (element.tagName.toLowerCase() !== "li") {
            element.observe("mouseout", ScupWrapper.menu.stop_listener);
            element.observe("mouseover", ScupWrapper.menu.stop_listener);
         }
      });
   }
});

