function Navi() {
  var self = this;
  this.nav = this.root;
  this.nav_items = this.nav.children().children('a');
  this.active = this.nav.children('a.active');
  this.sketcher = new Sketch();
  
  this.start_up = function(e) {
    self.nav_items.bind('mouseover', self.set_hover);
    self.nav_items.parent().bind('mouseleave', self.release_hover);
  }
  
  this.set_hover = function(e) {
    self.active.siblings('ul').hide();
    self.active = $(e.currentTarget);
    self.active.siblings('ul').show();
  }
 this.release_hover = function(e) {
    self.active.siblings('ul').hide();
  }
  
  return this;
}

function Navi_two_level_slide() {
  Navi.call(this);
  var self = this;
  this.nav.append('<li class="helper"><a href="#navi">&nbsp;</a></li>');
  this.navi_help = this.nav.children(':last');
  this.sub_nav = this.nav.next().children('.sub_1');

  this.start_up = function(e) {
    self.active = self.nav_items.filter(self.active_filter);
    self.nav_items.bind('mouseenter', self.set_hover);
    self.nav.parent().bind('mouseleave', self.release_hover);
    if (self.active.length > 0) {
      var temp = self.active;
      self.active = self.active.next();
      temp.trigger('mouseenter');
    } else {
      self.navi_help.stop();
      self.navi_help.hide();
      self.sub_nav.html('');
      self.active = [0,2];
    }
  }
  
  this.active_filter = function(index) {
    return this.className.match(/active/);
  }
  
  this.get_hover = function() {
    self.sketcher.draw(self.navi_help.css({display : 'block'}), {
      left: self.active.position().left, 
      width: self.active.outerWidth()
    }, null, .4);
    self.sub_nav.html(self.active.siblings('ul').clone().children().css({opacity: 0}));
    self.handle_sub_nav();
    self.sketcher.draw(self.sub_nav.children(), {
      opacity : 1
    }, function() {
      this.removeAttribute('style');
    });
  }

  this.handle_sub_nav = function () {
    // nothing in the two-level version
  }
  
  this.set_hover = function(e) {
    e.preventDefault();
    e.stopPropagation();
    if (e.currentTarget == self.active[0]) return false;
    self.active = $(e.currentTarget);
    self.get_hover();
  }

  this.release_hover = function(e) {
    e.preventDefault();
    e.stopPropagation();
    var me = self.nav_items.filter(self.active_filter);
    if (me[0] == self.active[0]) {
      self.sub_nav.html(self.active.siblings('ul').clone().children());
      self.handle_sub_nav();
      return false;
    }
    
    if (me.length > 0) {
      self.active = me;
      self.get_hover();
    } else {
      self.navi_help.stop();
      self.navi_help.hide();
      self.sub_nav.html('');
      self.active = [0,2];
   }
 }

  return this;
}

function Navi_three_level_slide() {
  Navi_two_level_slide.call(this);
  var self = this;
  self.sub_sub_nav = self.sub_nav.next(); 

  // must be dynamically computed, because contents of sub_nav change regularly
  function get_sub_nav_links() {
    return self.sub_nav.children().children('a');
  }

  this.handle_sub_nav = function() {
    get_sub_nav_links().bind("mouseenter", self.select_sub_menu);
    self.sub_sub_nav.parent().bind('mouseleave', self.submenu_release_hover);
  }

  function min(a, b) {
    return (a<b ? a : b);
  }

  function position_sub_sub_menu(menu_header) {
    var sub_sub_widths = self.sub_sub_nav.children().map(function() { return $(this).width(); }).get();
    var column_extra_width = 20;
    var width_sum = 0;
    $.each(sub_sub_widths, function(i, val) { width_sum += val + column_extra_width; });
    width_sum += 5;   // extra fudge factor to account for round-off
    var left_side_of_header = menu_header.position().left;
    var right_side_of_header = left_side_of_header + menu_header.width();
    self.sub_sub_nav.width(width_sum);
    if (right_side_of_header < width_sum) {
      self.sub_sub_nav.css('left', 0);
    } else {
      self.sub_sub_nav.css('left', min(left_side_of_header, self.sub_nav.width() - width_sum) - 2);
    }
  }
 
  this.select_sub_menu = function(e) {
    unselect_all_sub_menu_items();
    clear_sub_sub_menu();

    var menu_header = $(e.currentTarget);
    var potential_sub_sub_menu = menu_header.siblings('ul');

    menu_header.addClass('active');
    if (potential_sub_sub_menu.length > 0) {
      menu_header.addClass('with_sub_sub_menu');
      self.sub_sub_nav.html(potential_sub_sub_menu.clone().children());
      self.sub_sub_nav.css('display', 'block');

      position_sub_sub_menu(menu_header);
    }
  }

  function unselect_all_sub_menu_items() {
    get_sub_nav_links().each(
        function (i, val) {
          val.className = "";
          $(val).parent().removeClass('active');  // take 'active' off the surrounding <li>, too
        }
      );
  }

  var old_release_hover = this.release_hover;
  this.release_hover = function(e) {
    old_release_hover(e);
    clear_sub_sub_menu();
  }

  this.submenu_release_hover = function(e) {
    clear_sub_sub_menu();
  }

  function clear_sub_sub_menu() {
    self.sub_sub_nav.css('display', 'none');
  }

  return this;
}

/* ------------------------- Navi_side_slide ------------------------
/	** Navi_side_slide
  *  controls the behavior of the subnav
  *  subnav needs to be contained in a ul, each li of the ul is given a with of 200px via css
  *  subnav is positioned to the right absolutly and animated in using the Sketch js class
  *  @param element{jquery} variable: root element
  *  @member start_up bindes events (controller)
  *  @member slide_in slides in hidden ul
  *  @member slide_out slides out and hides visible ul
  */
/* --------------------------------------------------------- */

function Navi_side_slide(element) {
  Navi.call(this, element)
  var self = this;
  this.nav_slide_out = this.nav_items.siblings('ul')
  for (var i = 0; i < this.nav_slide_out.length; i++) {
    this.nav_slide_out.eq(i).data('width', this.nav_slide_out.eq(i).outerWidth());
  }
  
  this.set_hover = function(e) {
    var me = $(e.currentTarget);
    self.time_delay = setTimeout( function() {
      self.active.siblings('ul').hide();
      self.active.bind('mouseover', self.set_hover);
      self.active = me;
      self.active.unbind('mouseover', self.set_hover);
      self.sketcher.draw(self.active.siblings('ul').css({display : 'block', opacity: 0, width: 0}), { 
        opacity: 1, 
        width: self.active.siblings('ul').data('width')
      }, null, 0);
    }, 0);
  }
  this.release_hover = function(e) {
    clearTimeout(self.time_delay);
    self.active.bind('mouseover', self.set_hover);
    self.sketcher.draw(self.active.siblings('ul'), { opacity: 0}, function() {this.style.display = 'none';}, 0);
  }
  return this;
}

