/*!
	jQuery Reveal plugin v1.0 for jQuery
	2009 Travis Hensgen (Traversal)
	License: MIT
*/


(function($) {
  
  var defaults = { // public access through $.fn.reveal.defaults;
    
    event: "click",
    
    fShow: null,
    fHide: null,
    fPosition: null,
    fUnposition: null,
    
    affix: null,

    hideOnTargetClick: false,
    hideOnMouseLeave: false,
    hideOnTargetMouseLeave: false,
    hideTimeout: 500,
    
    target: function(trigger) { var href = $(trigger).attr("href"); if (href != "#") { return $(trigger).attr("href"); } }, // by default, target is a function that assumes the target id is encoded in the href as a hash
    
    showDelay: 200, /* when the event is mouseenter, how long does the mouse need to hover before the reveal is shown */
        
    classShown : "reveal-shown",

    selectorHide: null
    
  };
  
  defaults.affix = defaults.affixOptions;
  
  var getInfo = function(el) {
    var info = {};
    
    if ($(el).data("reveal-target")) {
      info.r = $(el).data("reveal-target");
      info.t = $(el);
    } else if ($(el).data("reveal-trigger")) {
      // this is being called on a reveal target
      info.r = $(el);
      info.t = $(el).data("reveal-trigger");
    }
    
    info.s = info.t.data("reveal-settings");
    
    return info;
  };
  
  getSettings = function(el, options) {
    
    // setup settings
    var s = $.extend(true, $.extend({}, $.fn.reveal.defaults), options || {} );

    if ($.fn.metadata) { // final override with metadata "revealOptions" (if plugin available, and metadata is present)
      s = $.extend(true, s, $(el).metadata().revealOptions || $(el).metadata()['reveal-options'] || $(el).metadata()['reveal_options'] || {});
    }

    // alias some settings, for convenience
    // s.affixOptions = s.affix;
    
    // hook up affix options to "affix" if it's supplied
    
    if (s.event != "click") {
      // mouse leave for target and trigger are more sensible defaults for a mouseenter

      if (options.hideOnMouseLeave == undefined) {
        s.hideOnMouseLeave = true;
      }
      
      if (options.hideOnTargetMouseLeave == undefined) {
        s.hideOnTargetMouseLeave = true;
      }
    }
    
		return s;
  };

  $.fn.revealHide = function() {
    
    this.each(function() {
      
      var info = getInfo($(this));
      
      var t = info.t;
      var r = info.r;
      var s = info.s;    
  
      t.trigger("reveal.beforehide");

      if (s.fUnposition) {
        s.fUnposition(t, r); // if a cleanup positioning function is defined, call it
      }
      else if (r["unaffix"] && s.affix)
        r.unaffix(); // else use unaffix if it's available
    
      if (s.fHide) {
        s.fHide($(r), $(t));
      }
      else {
        r.hide();
      }
    
      t.removeClass(s.classShown);
      t.trigger("reveal.hide");
    
    });
    
    return this;
  };
  
  $.fn.revealShow = function() {

    $(this).each( function() {
      
      var info = getInfo($(this));
      
      var t = info.t;
      var r = info.r;
      var s = info.s;
      
      t.trigger("reveal.beforeshow");

      t.addClass(s.classShown);

      
      if (s.fPosition) {
        s.fPosition(t, r); // if a custom positioning function is defined, call it
      }
      else if (r["affix"] && s.affix) {
        r.affix(t, s.affix); // else use affix if it's available
      }
      
      if (s.fShow) {
        s.fShow($(r), $(t));
      }
      else {
        
        r.show();
      }

      t.trigger("reveal.show");
    });
    
    return this;
    
  };
  
  $.fn.revealToggle = function() {

    this.each( function() {
      var info = getInfo($(this));
      
      var t = info.t;
      var r = info.r;
      var s = info.s;

      if (r.is(":visible")) {
        t.revealHide();
      }
      else {
        t.revealShow();
      }
    });
    
    return this;
  };

  
  $.fn.reveal = function(options) {

    this.each( function() {

      var t = $(this); // trigger

      t.data("reveal-settings", getSettings(t, options) );
      var s = t.data("reveal-settings");
      
      var r;
      
      // if the target is a function, call it to derive the target.
      if ($.isFunction(s.target)) {
        r = s.target(t);
      } else {
        r = $(s.target).eq(0);
      }
      
      
      if (r) {
        
        $(r).data("reveal-trigger", t); // store the reverse relationship 
        t.data("reveal-target", r); 
        
        // setup the events
    
        // set this function as a property of the object, so each has it's own copy and they can't interfere
        t.data("reveal-event", function(event) {
          t.revealToggle(); 
          event.preventDefault();
        });
        
        if (s.event == "click") {
          t.click( t.data("reveal-event") );
        }
        else {
          t.mouseenter( function(event) { 
            t.data("reveal-showTimeout", setTimeout(function() { t.revealShow(); }, s.showDelay)); 
            event.preventDefault();
          });
        }
   
        // setup elements inside the target that should hide it on click
        if (s.selectorHide) {
          $(s.selectorHide, r).click( function(event) {
            t.revealHide();
            event.preventDefault();
          });
        }
      
        // setup mouse leave events to hide the target
       
        // create common functions here so that they are closures on "t"
        mouseLeaveEvent = function(event) {
           t.data("reveal-hideTimeout", setTimeout( function() {
             t.revealHide();
             t.data("reveal-hideTimeout", null);
           }, s.hideTimeout));
          
           var to = t.data("reveal-showTimeout");
          
           if (to) {
             window.clearTimeout(to);
             t.data("reveal-showTimeout", null);
           }
           
           event.preventDefault();
        };
      
        mouseEnterEvent = function(event) {
            
           var to = t.data("reveal-hideTimeout");

      
           if (to) {
             window.clearTimeout(to);
             t.data("reveal-hideTimeout", null);
           }
       
           event.preventDefault();
        };
      
        if (s.hideOnTargetMouseLeave) {
          r.mouseleave( mouseLeaveEvent );
        }
 
        if (s.hideOnTargetClick) {
          r.click( t.data("reveal-event") );
        }
 
 
        if (s.hideOnMouseLeave) {
          t.mouseleave( mouseLeaveEvent );
        }
       
        if (s.hideOnTargetMouseLeave || s.hideOnMouseLeave) {
          // this mouse enter needs to be called it either options are specified, otherwise a mouse out into the target will hide the target
          r.mouseenter( mouseEnterEvent );
          t.mouseenter( mouseEnterEvent );
        }
        
      } // target.length > 0

    });

    
    return this;
  };
  
  $.fn.reveal.defaults = defaults;
  
})(jQuery);

