;(function($){
	var content;
	var overlay;
	//private variables
	var $window = $(window);
	var select;
	var templated = false;
	var isIE6 = $.browser.msie && $.browser.version == 6;
	var i=0;
	var loadedAjax = [];
	var current;
	var contentAjax;
	
	
	//private functions
	function isID(string){ return string.indexOf('#') != -1; }
	function template(){
		$('body').append('<div id="serialbox-overlay"></div><div id="serialbox-content"></div>');
		overlay = $('#serialbox-overlay').click($.fn.serialbox.close);
		content = $('#serialbox-content');
		templated = true;	
	}
	function move(id){	
		var $id = $('#'+id.split('#')[1]);
		if(!$id.length) return;
		
		$id.hide().appendTo(content);
	}
	function boolean(string){
		switch(string){
			case "true": case "1": case true: case 1:	return true;
			case "false": case "0": case false: case 0:	return false;
			default: return Boolean(string);
		}
	}
	// parseUri 1.2.2
	// (c) Steven Levithan <stevenlevithan.com>
	// MIT License
	function parseUri(str){var o=parseUri.options,m=o.parser[o.strictMode?"strict":"loose"].exec(str),uri={},i=14;while(i--)uri[o.key[i]]=m[i]||"";uri[o.q.name]={};uri[o.key[12]].replace(o.q.parser,function($0,$1,$2){if($1)uri[o.q.name][$1]=$2});return uri};parseUri.options={strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};
		 
	$.fn.serialbox = function(options) {
		var settings = $.extend({}, $.fn.serialbox.defaults, options);

		if(!templated) template();
		
		this.each(function(){
			var href = $(this).attr('href');
			if(!href) return;		
			
			//bind click
			$(this).click(function(){
				$.fn.serialbox.open(href, settings);
				return false;
			});

			//move content
			if(isID(href)) move(href);
		});
		
		return this;
	}
	
	
	$.fn.serialbox.open = function(target, options){	
		if(!templated) template();
		var method = isID(target) ? 'id' : 'url';
		
		var parsedUrl = parseUri(target);
		var url = parsedUrl.source;
		var params = parsedUrl.queryKey;
		var id = "#"+parsedUrl.anchor;
		
		var settings = $.extend({}, $.fn.serialbox.defaults, options, params); //extend 1) default, 2) options, 3) GET params
		settings.cache = boolean(settings.cache);
		settings.fixed = boolean(settings.fixed);
		var cache = settings.cache;
		
		$.fn.serialbox.settings = settings;
		
		//Extend
		$.extend(this, {
			show: function(){
				if(method == 'id') this.checkMoved(id);
				
				this.before();
				
				//reset
				if(current){
					content.hide();
					current.hide().css('visibility', 'hidden');
				}
				content.removeAttr('style');
				
				//overlay
				if(settings.overlay){
					this.overlayCss(settings);
					overlay.fadeIn();
					$(document).bind('keydown', this.escape);
				}
				
				//pre-content for ajax
				if(method == 'url') target = this.ajax.call(this, url, cache);
				if(method == 'id') target = id;

				//content change css
				this.boxCss(settings);
				
				
				//content
				current = $(target).css('visibility', 'visible').show();
				content.fadeIn('slow');
				
				//position the box
				$window.bind('resize scroll', this.positions).trigger('resize');
				this.top();
				
				if(settings.callback) settings.callback();																						 
			},
			
			top: function(){
				if(settings.top == 'auto'){
					var boxHeight = content.height();
					var centerVerti = ($window.scrollTop() + ($window.height() / 2)) - (boxHeight / 2);
					content.css({top: Math.max(35, centerVerti)});
				} else {
					content.css('top', settings.top+'px')
				}
			},
			
			before: function(){
				if(isIE6){ 
					select = $('body > *').not('#serialbox-content').find('select');
					$window.bind('resize scroll', this.overlay);
					select.css('visibility', 'hidden');
				}
			},
			
			escape: function(event){
				if(event.keyCode == 27) $.fn.serialbox.close();
			},
			
			positions: function(){
				if(settings.left == 'auto'){
					var boxWidth = content.width();
					content.css({marginLeft: -boxWidth/2, left: '50%'});
				} else {
					content.css('left',  settings.left+'px');
				}

				if(boolean(settings.fixed)) plugin.top();
			},
			
			overlay: function(){
				overlay.css({position: 'absolute', left: $window.scrollLeft(), top: $window.scrollTop(), width: $window.width(), height: $window.height()});
			},
			
			//return: 
			//- id of the cached content
			//- or the id of the new created content
			ajax: function(url, cache){
				if(cache){
					for(j in loadedAjax){
						if($.inArray(url, loadedAjax[j]) >= 0) return loadedAjax[j][1];
					}
				}

				i++; 
				var id = "#serialbox-ajax0"+i;
				if(settings.iframe){
					contentAjax = $("<iframe src='"+url+"' id='"+id.split('#')[1]+"' allowTransparency='true' border='0' frameborder='0' width='"+settings.width+"' height='"+settings.height+"' />");
				} else {
					contentAjax = $("<div id='"+id.split('#')[1]+"' />").load(url, this.positions);
				}
				
				$(content).append(contentAjax);
				if(cache) loadedAjax.push([url, id]);

				return id;
			},
			
			overlayCss: function(s){
				//opacity
				if(!overlay.is(':visible'))	overlay.show().css('opacity', 0);							
				overlay.animate({'opacity': s.opacity}, 800);
				
				//background-color
				
				overlay.css('background-color', s.bgcolor);
			},
			
			boxCss: function(s){
				var height = s.height == 'auto' ? 'auto' : s.height+"px";
				var width = s.width == 'auto' ? 'auto' : s.width+"px";
				
				if(s.height) content.css('height', height);
				if(s.width) content.css('width', width);
			},
			
			checkMoved: function(element){
				if(!$(element, content).length){
					move(element);
				}
			}
		});

		
		var plugin = this;
		this.show();
		return this;
	}
	
	$.fn.serialbox.close = function() {
		var settings = $.fn.serialbox.settings;
		if($.fn.serialbox.blocked) return;
		
		overlay.fadeOut();
		content.fadeOut();
		
		if(settings.cache == false){
			contentAjax.remove();
		}
		
		$(document).unbind('keydown');
		$window.unbind('resize scroll');
		
		if(isIE6)	select.css('visibility', 'visible');
	}
	
	$.fn.serialbox.defaults = {
		//overlay
		overlay:true,
		opacity: 0.2,
		bgcolor: '#000',
		//box
		width:500,
		fixed:true,
		top:'auto',
		left:'auto',
		bottom:false,
		right:false,
		//general
		cache:true,
		callback:false
	}
	
	$.fn.serialbox.blocked=false;
})(jQuery);

