(function($) {

  function recursiveSum ( current, attrName ) {
    var p = current, val = 0;
    do {
      val += $(p).attr(attrName);
      p = $(p).attr('offsetParent');
    } while( p && p.nodeName != 'BODY' );
    return val ;
  }

  function delayHide ( selector ) {
    setTimeout(
	function (  ) {
	  dom = $(selector);
	  if( !dom.data('shown') )
	    // dom.slideUp('fast');
	    dom.hide('fast');
	},
	200
      );
  }

  $.fn.extend({
      getabsleft:	function (  ) {
	return recursiveSum(this, 'offsetLeft');
      },

      getabstop:	function (  ) {
	return recursiveSum(this, 'offsetTop');
      },

      setupmenu:	function (  ) {
	if( !$(this).data('setup') ) {
	  var o = $(this).data('options');
	  var l = $(this).getabsleft(), t = $(this).getabstop();
	  if( o['horizontal'] ) {
	    menuLeft = l + $(this).width() + o['hoffset'];
	    menuTop = t + o['voffset'];
	  } else {
	    menuLeft = l + o['hoffset'];
	    menuTop = t + $(this).height() + o['voffset'];
	  }

	  var menu = $(o['menu']);
	  menu.css({
	      'left':	menuLeft + 'px',
	      'top':	menuTop + 'px'
	    });

	  if( o['trigger'] == 'mouseover' ) {
	    menu.find('*').each(
		function ( i, e ) {
		  $(e)
		    .mouseover( function (  ) { $(e.parentNode).trigger('mouseover'); } )
		    .mouseout( function (  ) { $(e.parentNode).trigger('mouseout'); } )
		    ;
		}
	      );
	    menu.mouseover(
		function (  ) {
		  $(this).data('shown', true);
		}
	      );
	    menu.mouseout(
		function (  ) {
		  $(this).data('shown', false);
		  delayHide(this);
		}
	      );
	  }
	}

	$(this).data('setup', true);
      },

      attachmenu:	function ( options ) {
	var o = jQuery.extend({
	    horizontal:	true,
	    trigger:	'mouseover',
	    upper:	null,
	    hoffset:	0,
	    voffset:	0
	  }, options);

	$(this)
	  .data('setup', false)
	  .data('shown', false)
	  .data('options', o);

	if( o['trigger'] == 'mouseover' ) {
	  $(this).mouseover(
	      function (  ) {
		$(this).setupmenu();
		menu = $( $(this).data('options')['menu'] );
		menu.data('shown', true).slideDown('fast');
	      }
	    );
	  $(this).mouseout(
	      function (  ) {
		menu = $( $(this).data('options')['menu'] );
		menu.data('shown', false);
		delayHide(menu);
	      }
	    );
	}
	return $(this);
      }
    });

})(jQuery);
