/**
* Copyright (c) 2008 Svein Arild Bergset (sab@bergset.com)
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* $Id$
*
* Version: 0.1
*
* Requires: $ 1.2.2+
**/
;(function($) {

   var slidemenu_container = null;
   var slidemenu_settings = {};

   $.fn.extend({

      slidemenu: function( settings ) {

         slidemenu_settings = jQuery.extend({
               containerClass: 'slidemenu_container',
               fitClass: false
         }, settings );

         // Save pointers to the elements.
         slidemenu_container = this;

         this.createMenu();

      },

      createMenu: function() {

         // Process all menu elements to look for submenus.
         slidemenu_container.children().each( function(i,el) {

            el = $(el);
            // Hide submenus.
            el.children("ul").hide();

            // If the menu element has any submenus.
            if ( el.children( 'ul' ).length > 0 ) {

               // Create the mouse hover effects of the menu item.
               el.hover(

                  // Enter element.
                  function(e) {

                     var el = $(this);
                     // Set which element the slide mneu should be fitted to.
                     if ( slidemenu_settings.fitClass ) {
                        elFit = $( '.'+slidemenu_settings.fitClass );
                     }
                     else {
                        elFit = $( e.target.parentNode );
                     }

                     // Fint positions of fitted element.
                     offsetFit = elFit.offset();

                     // Check if the sliding menu is created before, for reusing it.
                     var sliders = $( '.'+slidemenu_settings.containerClass );

                     // If no slider menu is found, create new.
                     if ( sliders.length == 0 ) {

                        slider = $(document.createElement('DIV'));
                        slider.addClass( slidemenu_settings.containerClass );

                        // Create mouse hover event for the slider menu.
                        slider.hover(
                           // Enter slider.
                           function() {
                              // Set that the timeout hider should not hide the slider, since mouse is currently over the slider.
                              this.parent.hold = true;
                           },
                           // Exit slider.
                           function() {
                              // Set that the timeout hider should hide the slider
                              this.parent.hold = false;
                              // Activate the slider hider.
                              var tid = setTimeout( function() {
                                 delayHide( this.parent );
                              }.bind(this), 200 );
                           }
                        );
                     }
                     // If existing slider is found, use it.
                     else {
                        slider = $(sliders[0]);
                     }

                     // Connect the menu element to the slider.
                     this.subbox = slider;

                     // If the parent to the slider is currently not this menu element, hide the slider for the previous owner.
                     if ( this.subbox[0].parent && this.subbox[0].parent != this ) {

                        // Hide slider an reconnect submenu elements to correct owner element.
                        $(this.subbox).children('ul').hide().appendTo( this.subbox[0].parent );
                        $(this.subbox).hide();
                        // Set that the previous timeout hider should not hide the new slider.
                        this.holdnext = true;
                        this.subbox[0].parent.holdnext = true;

                     }

                     // If the slider currently has no elements attached, set it up.
                     if ( this.subbox.children( 'ul' ).length == 0 ) {

                        // Make sure the timeout hider will hide the slider.
                        this.hold = false;
                        // Set position of the slider..
                        slider.css({
                              left: offsetFit.left + 'px',
                              top: (offsetFit.top + elFit.height()) + 'px'
                        });

                        // Move submenu items to the slider and display them.
                        el.children('ul').show().appendTo( slider );
                        slider.appendTo( 'body' );
                        slider.slideDown( 500 );

                     }
                     // If slider has elements attached means the mouse entered a menu element with an open slider. So we want to keep the slider open.
                     else {
                        this.hold = true;
                     }

                     // Set the menu element to be the parent of the slider.
                     this.subbox[0].parent = this;

                  },

                  // Exit element.
                  function(e) {

                     // Make sure the timeout hider will hide the slider.
                     this.hold = false;
                     this.holdnext = null;
                     // Activate the timeout hider.
                     var tid = setTimeout( function() {
                        delayHide( this );
                     }.bind(this), 200 );
                  }
                  );
            }
            });

         }

   });

   // Timeout hider.
   function delayHide( elem ) {

      var el = $(elem);
      var elSub = $(elem.subbox);
      // Hide slider if nothing has kept it back.
      if ( !elem.hold && !elem.holdnext ) {
         elSub.slideUp( 500, function() {
            var ch = elSub.children('ul');
            if ( ch.length > 0 && !elem.holdnext ) {
               ch.hide().appendTo( el );
               elSub.hide();
            }
         });
      }
      // Reset the property that prevents concurrently opened sliders from hiding right away.
      else {
         elem.holdnext = null;
      }

   }

})(jQuery);

