//http://blog.nitrogenlabs.com/2009/07/jquery-tools-overlay-fix.html
/**
 * tools.overlay 1.0.4 - Overlay HTML with eye candy.
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/overlay.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch  : March 2008
 * Date: 2009-06-12 11:02:45 +0000 (Fri, 12 Jun 2009)
 * Revision: 1911 
 */
(function($) {
	// static constructs
	$.tools = $.tools || {version: {}};
	$.tools.version.overlay = '1.0.4';
	
	var instances = [];
	
	function Overlay(el, opts) {
		// private variables
		var self	= this, w = $(window), closeButton, img, box, oWidth, oHeight, trigger, bg, exposeApi, boxRadius, boxColor, zoomType;
		var expose	= opts.expose && $.tools.version.expose;
		
		// generic binding function
		function bind(name, fn) {
			$(self).bind(name, function(e, args)  {
				if (fn && fn.call(this) === false && args) {
					args.proceed = false;	
				}	
			});	 
			return self;
		}
		
		// bind all callbacks from configuration
		$.each(opts, function(name, fn) {
			if ($.isFunction(fn)) { bind(name, fn); }
		});   
		
		// get trigger and overlayed element
		var jq = opts.target || el.attr("rel");
		var o = jq ? $(jq) : null;

		if (!o) { o = el; }	
		else { trigger = el; }
		
		// get growing image
		bg			= o.attr("overlay");
		zoomType	= opts.zoomType	|| 'img';
		boxRadius	= opts.boxRadius || 10;
		boxColor	= opts.boxColor	|| '#CCCCCC';
		
		// growing image is required (on this version)	
		if (!bg) { 
			bg = o.css("backgroundImage");
			
			if (!bg) { 
				throw "background-image CSS property not set for overlay element: " + jq; 
			}
			
			// url("bg.jpg") --> bg.jpg
			bg = bg.substring(bg.indexOf("(") + 1, bg.indexOf(")")).replace(/\"/g, "");
			
			if(zoomType == 'img') {
				o.css("backgroundImage", "none");
			}
			
			o.attr("overlay", bg);							
		}			
		
		// set initial growing image properties
		oWidth	= o.outerWidth() - ((parseFloat(o.css('paddingLeft')) + parseFloat(o.css('paddingRight'))) *.5);
		oHeight	= o.outerHeight() - ((parseFloat(o.css('paddingTop')) + parseFloat(o.css('paddingBottom'))) *.5);
		
		// setup growing image
		if(zoomType == 'img') {
			img = $('<img src="' + bg + '"/>');		
			img.css({border:0,position:'absolute',display:'none'}).width(oWidth).attr("overlay", true);
			$('body').append(img);
		}
		else if(zoomType == 'div') {
			box	= $('<div></div>');
			box.css({position:'absolute', display:'block', 'backgroundColor':boxColor}).width(oWidth).height(oHeight).attr("overlay", true);
			box.hide();
			$('body').append(box);
		}
		
		if(expose) {
			opts.expose.api		= true;
			opts.expose.maskID	= 'exposeMask';
			
			if(zoomType == 'img') {
				exposeApi	= img.expose(opts.expose);
			} else {
				exposeApi	= box.expose(opts.expose);
			}
		}
		
		// if trigger is given - assign it's click event
		if (trigger) {
			trigger.bind("click.overlay", function(e) {
				e.preventDefault();
				self.load(e.pageY - w.scrollTop(), e.pageX - w.scrollLeft());
				return false;
			});
		}   		
				
		// close button
		opts.close = opts.close || ".close";
		
		if (!o.find(opts.close).length) {				
			o.prepend('<div class="close"></div>');
		} 
		
		closeButton = o.find(opts.close);
		
		closeButton.bind("click.overlay", function() { 
			self.close();  
		});			
		
		// automatic preloading of the image
		if (opts.preload && zoomType == 'img') {
			setTimeout(function() {
				var img = new Image();
				img.src = bg;					
			}, 2000);
		}

				
		// API methods  
		$.extend(self, {
			exposeBox:null,
			load:function(top, left) {
				// lazy loading if things are not setup yet
				if (!img && zoomType == 'img') { 
					w.load(function()  {
						self.load(top, left);		
					});
					return self;
				}
				
				// one instance visible at once
				if (self.isOpened()) {
					return self;	
				}
				
				if (opts.oneInstance) {
					$.each(instances, function() {
						this.close();
					});
				}
				
				// onBeforeLoad
				var p = {proceed: true};
				$(self).trigger("onBeforeLoad", p);				
				if (!p.proceed) { return self; }						

				// exposing effect
				if(expose) {
					this.exposeBox = exposeApi.load();
				}				
						
				// start position			
				top		= top  || opts.start.top;
				left	= left || opts.start.left;
				
				// finish position 
				var toTop	= opts.finish.top;
				var toLeft	= opts.finish.left;
				
				if (toTop == 'center') { toTop = Math.max((w.height() - oHeight) / 2, 0); }
				if (toLeft == 'center') { toLeft = Math.max((w.width() - oWidth) / 2, 0); }
				
				// adjust positioning relative to scrolling position
				if (!opts.start.absolute)  {
					top += w.scrollTop();
					left += w.scrollLeft();
				}
				
				if (!opts.finish.absolute)  {
					toTop += w.scrollTop();
					toLeft += w.scrollLeft();
				}
				
				// initialize background image  
				if(zoomType == 'img') {
					img.css({top:top, left:left, width: opts.start.width, zIndex: opts.zIndex}).show();
					
					// begin growing
					img.animate({top:toTop, left:toLeft, width: oWidth}, opts.speed, function() { 
						// set content on top of the image
						o.css({position:'absolute', top:toTop, left:toLeft}); 
						var z = opts.zIndex;
						closeButton.add(o).css("zIndex", ++z);
						
						o.fadeIn(opts.fadeInSpeed, function() {  
							$(self).trigger("onLoad"); 	 
						});
					});
				}
				else if(zoomType == 'div') {
					box.html('&nbsp;');
					box.css({top:top, left:left, width:opts.start.width, height:opts.start.height, zIndex: opts.zIndex}).show();
					
					// begin growing
					box.animate({top:toTop + (parseFloat(o.css('paddingTop'))*.5), left:toLeft + (parseFloat(o.css('paddingLeft'))*.5), width:oWidth, height:oHeight, 'MozBorderRadius':boxRadius, 'WebkitBorderRadius':boxRadius}, opts.speed, function() { 
						// set content on top of the image
						o.css({position:'absolute', top:toTop, left:toLeft}); 
						var z = opts.zIndex;
						closeButton.add(o).css("zIndex", ++z);
						
						o.fadeIn(opts.fadeInSpeed, function() {  
							$(self).trigger("onLoad");
							box.hide();
						});
					});
				} 
				
				return self; 
			}, 
			
			close: function() {
				if (!self.isOpened()) { return self; }
				
				var p = {proceed: true};
				$(self).trigger("onBeforeClose", p);				
				if (!p.proceed) { return self; }
				
				// close exposing effect
				for(g=0; g<instances.length; g++) {
					if(instances[g].exposeBox) {
						instances[g].exposeBox.close();
					}
				}
				
				if (zoomType == 'img' && img.is(":visible")) {
					// hide overlayed content
					o.hide();
					
					// calculate triggers position
					var top = opts.start.top; 
					var left = opts.start.left;
					
					if (trigger) {
						p = trigger.offset();
						top = p.top + trigger.height() / 2;
						left = p.left + trigger.width() / 2;
					}					
					
					// shrink image
					img.animate({top: top, left: left, width:0 }, opts.closeSpeed, function()  {
						$(self).trigger("onClose", p);		
					});					
				} else if(zoomType == 'div') {
					// hide overlayed content
					box.show();
					o.hide();
					
					// calculate triggers position
					var top = opts.start.top; 
					var left = opts.start.left;
					
					if (trigger) {
						p = trigger.offset();
						top = p.top + trigger.height() / 2;
						left = p.left + trigger.width() / 2;
					}
					
					box.animate({top:top, left:left, width:0, height:0}, opts.closeSpeed, function() {
						$(self).trigger("onClose", p);		
					});
				}
				
				return self;
			},
			
			
			getBackgroundImage: function() {
				return img;	
			},
			
			getContent: function() {
				return o;	
			}, 
			
			getTrigger: function() {
				return trigger;	
			},

			isOpened: function()  {
				return o.is(":visible")	;
			},
			
			// manipulate start, finish and speeds
			getConf: function() {
				return opts;	
			},

			// callback functions
			onBeforeLoad: function(fn) {
				return bind("onBeforeLoad", fn); 		
			},
			
			onLoad: function(fn) {
				return bind("onLoad", fn); 		
			},
			
			onBeforeClose: function(fn) {
				return bind("onBeforeClose", fn); 		
			},
			 
			onClose: function(fn) {
				return bind("onClose", fn); 		
			} 			
			
		});  
				
		
		// keyboard::escape
		$(document).keydown(function(evt) {
			if (evt.keyCode == 27) {				
				self.close();	
			}
		});		

		
		// when window is clicked outside overlay, we close
		if (opts.closeOnClick) {					
			$(document).bind("click.overlay", function(evt) {
				if (!o.is(":visible, :animated")) { return; }
				var target = $(evt.target);
				if (target.attr("overlay")) { return; }
				if (target.parents("[overlay]").length) { return; }
				self.close(); 
			});						
		}		
		
	}
	
	// jQuery plugin initialization
	$.fn.overlay = function(conf) {   
		
		// already constructed --> return API
		var el = this.eq(typeof conf == 'number' ? conf : 0).data("overlay");
		if (el) { return el; }	
		
		var w = $(window);  		
		
		var opts = { 
		
			/* 
			 - onBeforeLoad 
			 - onLoad
			 - onBeforeClose 
			 - onClose 
			*/			
			
			start: {
				// by default: button position || window center
				top: Math.round(w.height() / 2), 
				left: Math.round(w.width() / 2),				
				width:0,			
				height:0,
				absolute: false
			},
			
			finish: {
				top: 80, 
				left: 'center',
				absolute: false
			},   
			
			speed: 'normal',
			fadeInSpeed: 'fast',
			closeSpeed: 'fast',
			
			close: null,	
			oneInstance: true,
			closeOnClick: true, 
			//preload: true, 
			zIndex: 9999,
			api: false,
			expose: null,
			
			// target element to be overlayed. by default taken from [rel]
			target: null
		};
		
		if ($.isFunction(conf)) {
			conf = {onBeforeLoad: conf};	
		}
		
		$.extend(true, opts, conf);  
		
		
		this.each(function() {			
			el = new Overlay($(this), opts);
			instances.push(el);
			$(this).data("overlay", el);	
		});
		
		return opts.api ? el: this;		
	}; 
	
})(jQuery);