/**
 * $.inPageDialog
 * @version    0.1  (updated: 2009/07/28)
 * @author     Takeshi Takatsudo (http://zudolab.net/)
 * @license    MIT (http://www.opensource.org/licenses/mit-license.php)
 */
(function($){ // start $ encapsulation

	/**
	 * misc
	 */
		var win=$(window);
		var doc=$(document);
		var body=$(document.body);
		
		/*
		 * noCache
		 * most browser has cache problem about ajaxed content.
		 * this funciton add the useless url parameter to the url.
		 * this will be prevent browser to cache the page.
		 */
		function noCache(url){
			return url.concat(/\?/.test(url)?"&":"?","noCache=",(new Date).getTime(),".",Math.random()*1234567)
		}
		
		/* extend browser object */
		$.browser.msie6 = $.browser.msie && $.browser.version==="6.0";
		$.browser.macFx = (function(){
			var userAgent = navigator.userAgent.toLowerCase();
			if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1){
				return true;
			}else{
				return false;
			}
		})();
	
	/**
	 * $.inPageDialog
	 */
	$.inPageDialog = {
	
		/* config */
		config: {
			
			/* global config */
			global: {
				iframeSrc: "javascript:false",
				loadingImgPath: "loading.gif",
				fadeSpeed: {
					overlay: 200,
					content: 200
				}
			},
			
			/* dialogSet individual config */
			individual: {
				useNoCache : false,
				showColorOverlay: true,
				showIframeOverlay: true,
				showLoading: true,
				width: null,
				height: null,
				extraClass: null,
				useTitleAsDialogTitle: false,
				useAltAsDialogTitle: false,
				selector: {
					closeButton: "a.js_inPageDialog_close",
					locChangeA: "a.js_inPageDialog_locChangeA",
					locChangeForm: "form.js_inPageDialog_locChangeForm"
				},
				dialogHtml: (function(){
					return [
						'<div class="inPageDialog_container">',
						'    <table class="inPageDialog_posTable"><tr><td class="inPageDialog_posTd">',
						'        <div class="inPageDialog_inTableContainer">',
						'            <div class="inPageDialog_titleBar">',
						'                <p class="inPageDialog_closeBtn"><a href="javascript:$.inPageDialog.close()"><img src="close.gif" alt="" /></a></p>',
						'                <p class="inPageDialog_title"></p>',
						'            </div>',
						'            <div class="inPageDialog_content"></div>',
						'        </div>',
						'    </td></tr></table>',
						'</div>'
					].join("");
				})(),
				opener: null,
				type: null
			}
		},
		
		/* overlay instances */
		overlay: {
			color: null,
			iframe: null,
			loading: null
		},
		
		/* flags */
		setupComplete: false,
		whiteAnimation: false,
		
		/* current dialogs */
		currentDialogSet: null,
		currentDialog: null,
		
		/* dialogs */
		dialogSets: [],
		
		/**
		 * setup
		 * setup overlays. this will be executed once.
		 */
		setup: function(){
			if(this.setupComplete) return;
			this.overlay.color = new ColorOverlay;
			this.overlay.iframe = new IframeOverlay;
			this.overlay.loading = new LoadingOverlay;
			this.setupComplete = true;
		},
		/**
		 * register
		 * create dialogSet instance from received config.
		 */
		register: function(config){
			var extendedConfig = {};
			$.extend(extendedConfig, this.config.individual, config);
			var dialog;
			switch(extendedConfig.type){
				case "img": dialog = new ImgDialogSet(extendedConfig); break;
				case "ajax": dialog = new AjaxDialogSet(extendedConfig); break;
				case "iframe": dialog = new IframeDialogSet(extendedConfig); break;
				case "anchor": dialog = new AnchorDialogSet(extendedConfig); break;
				default: return; break;
			}
			this.dialogSets.push(dialog);
			return dialog;
		},
		/**
		 * close
		 */
		close: function(){
			if(!this.currentDialog){
				$.each(this.overlay,function(){
					this.hide();
				});
			}else{
				this.currentDialog.close();
			}
		}
	}
	/**
	 * Overlay (abstract)
	 */
	var Overlay = function(){
		body.append(this.elem);
		this.bindOvelayAdjustEvents();
		this.elem.click(function(){
			$.inPageDialog.close();
		});
	};
	Overlay.prototype = {
		isVisible: false,
		show: function(){
			if(this.isVisible) return;
			this.setOverlayPosition();
			this.elem.show();
			this.isVisible = true;
		},
		hide: function(){
			if(!this.isVisible) return;
			this.elem.hide();
			this.isVisible = false;
		},
		/*
		 * setOverlayPosition
		 * IE6 doesnot support position:fixed. so, use absolute instead.
		 * this method will expand the overlays to fullsize.
		 */
		setOverlayPosition: function(){
			if(!$.browser.msie6) return;
			var style={
				"top" : doc.scrollTop(),
				"left" : doc.scrollLeft(),
				"width" : win.width(),
				"height" : win.height()
			}
			this.elem.css(style);
		},
		/*
		 * bindOvelayAdjustEvents
		 * IE6 doesnot support position:fixed. so, use absolute instead.
		 * this method will adjust the overlays' position when scroll and resize.
		 */
		bindOvelayAdjustEvents: function(){
			if(!$.browser.msie6) return;
			var self = this;
			win.bind("resize scroll", function(){
				if(!$.inPageDialog.currentDialog) return;
				if(!self.isVisible) return;
				self.setOverlayPosition();
			});
		}
	};
	/**
	 * Overlay child class
	 */
		/**
		 * ColorOverlay
		 */
		var ColorOverlay = function(){
			this.elem = $('<div id="inPageDialog_colorOverlay"></div>');
			if ($.browser.macFx) this.elem.addClass("inPageDialog_macFX");
			Overlay.apply(this, arguments);
		};
		$.extend(ColorOverlay.prototype,Overlay.prototype,{
			hide: function(){
				if(!this.isVisible) return;
				var self = this;
				if($.browser.msie){
					/* IE ignore opacity when fadeOut so avoid it */
					this.elem.hide();
					this.isVisible = false;
				}else{
					$.inPageDialog.whileAnimation = true;
					this.elem.fadeOut($.inPageDialog.config.global.fadeSpeed.overlay,function(){
						self.isVisible = false;
						$.inPageDialog.whileAnimation = false;
					});
				}
			}
		});
		/**
		 * LoadingOverlay
		 */
		var LoadingOverlay = function(){
			var html = [
				'<div id="inPageDialog_loading"><table><tr><td><img src="',
				$.inPageDialog.config.global.loadingImgPath,'" alt="" /></td></tr></table></div>'
			];
			this.elem = $(html.join(""));
			Overlay.apply(this, arguments);
		};
		$.extend(LoadingOverlay.prototype,Overlay.prototype, {
			show: function(){
				if(this.isVisible) return;
				this.setOverlayPosition();
				var self=this;
				setTimeout(function(){ /* make short delay */
					if($.browser.msie6){
						var style = {
							"top": doc.scrollTop(),
							"height": win.height(),
							"display": "block"
						};
						self.elem.css(style);
					}else{
						self.elem.show();
					}
					self.isVisible = true;
				},4);
			}
		});
		/**
		 * IframeOverlay
		 */
		var IframeOverlay = function(){
			var html = [
				'<iframe id="inPageDialog_iframeOverlay" frameborder="0" src="',
				$.inPageDialog.config.global.iframeSrc,'"></iframe>'
			];
			this.elem = $(html.join(""));
			Overlay.apply(this, arguments);
		};
		$.extend(IframeOverlay.prototype,Overlay.prototype);
	/**
	 * DialogSet (abstract)
	 */
	var DialogSet = function(config){
		this.config = config;
		this.dialogs = [];
		this.elem = {};
		this.elem.opener = $(this.config.opener);
		if(!this.elem.opener.size()) return;
		$.inPageDialog.setup(); // setup overlays
		var self = this;
		this.elem.opener.click(function(){
			var anchor = $(this);
			anchor.blur();
			if($.inPageDialog.currentDialog) return false;
			if($.inPageDialog.whileAnimation) return false;
			$.inPageDialog.whileAnimation = true; // set animation start flag
			$.inPageDialog.currentDialogSet = self;
			if(self.config.showColorOverlay) $.inPageDialog.overlay.color.show();
			if(self.config.showIframeOverlay) $.inPageDialog.overlay.iframe.show();
			if(self.config.showLoading) $.inPageDialog.overlay.loading.show();
			self.openDialog(anchor);
			return false;
		});
	};
	DialogSet.prototype = {
		/**
		 * getAnchorInfo
		 */
		getAnchorInfo: function(anchor){
			var ref = anchor.attr("href");
			if(this.config.useNoCache) ref = noCache(ref);
			var title = null;
			/* get dialog title */
			if(this.config.useAltAsDialogTitle) title = anchor.find("img").eq(0).attr("alt") || null;
			if(this.config.useTitleAsDialogTitle) title = anchor.attr("title") || title || null;
			/*
			 * respect direct specified width,height.
			 * you can specify this by adding extra class like
			 * "w_300px_h_400px"
			*/
			if(anchor.is("[class*= w_]")){
				var classAry = anchor.attr("class").split(" ");
				var width,height,strAry;
				for(var i=0,current; current=classAry[i]; i++){
					if(current.indexOf("w_")===0){
						strAry = current.split("_");
						width = strAry[1] || null;
						height = strAry[3] || null;
						break;
					}
				}
			}
			return {
				ref: ref,
				title: title,
				width: width,
				height: height
			};
		},
		/**
		 * openDialog
		 */
		openDialog: function(anchor){
			var individualInfo = this.getAnchorInfo(anchor);
			var dialog;
			/*
			 * if the dialog was created once, open it
			 */
			$.each(this.dialogs,function(){
				if(this.ref!=individualInfo.ref) return;
				if(this.title!=individualInfo.title) return;
				if(this.width && this.width!=individualInfo.width) return;
				if(this.height && this.height!=individualInfo.height) return;
				dialog = this;
				dialog.open();
			});
			/*
			 * if not yet, create it
			 */
			if(!dialog){
				dialog = this.createDialog(individualInfo);
				this.dialogs.push(dialog);
			}
		}
	};
	/**
	 * DialogSet subclass
	 */
		/**
		 * ImgDialogSet
		 */
		var ImgDialogSet = function(config){ DialogSet.apply(this, arguments); };
		$.extend(ImgDialogSet.prototype,DialogSet.prototype,{
			createDialog: function(individualInfo){
				return new ImgDialog(this.config, individualInfo);
			}
		});
		/**
		 * AjaxDialogSet
		 */
		var AjaxDialogSet = function(config){ DialogSet.apply(this, arguments); };
		$.extend(AjaxDialogSet.prototype,DialogSet.prototype,{
			createDialog: function(individualInfo){
				return new AjaxDialog(this.config, individualInfo);
			}
		});
		/**
		 * IframeDialogSet
		 */
		var IframeDialogSet = function(config){ DialogSet.apply(this, arguments); };
		$.extend(IframeDialogSet.prototype,DialogSet.prototype,{
			createDialog: function(individualInfo){
				return new IframeDialog(this.config, individualInfo);
			}
		});
		/**
		 * AnchorDialogSet
		 */
		var AnchorDialogSet = function(config){ DialogSet.apply(this, arguments); };
		$.extend(AnchorDialogSet.prototype,DialogSet.prototype,{
			createDialog: function(individualInfo){
				return new AnchorDialog(this.config, individualInfo);
			}
		});
	/**
	 * Dialog (abstract)
	 */
	var Dialog = function(config,individualInfo){
		this.elem = {};
		this.elem.container = $(config.dialogHtml);
		this.elem.posTable = this.elem.container.find("table.inPageDialog_posTable").eq(0);
		this.elem.posTd = this.elem.container.find("td.inPageDialog_posTd").eq(0);
		this.elem.inTableContainer = this.elem.container.find("div.inPageDialog_inTableContainer").eq(0);
		this.elem.titleBar = this.elem.container.find("div.inPageDialog_titleBar").eq(0);
		this.elem.title = this.elem.container.find("p.inPageDialog_title").eq(0);
		this.elem.closeBtn = this.elem.container.find("p.inPageDialog_closeBtn").eq(0);
		this.elem.content = this.elem.container.find("div.inPageDialog_content").eq(0);
		if(config.extraClass) this.elem.container.addClass(config.extraClass);
		if(config.width && !individualInfo.width) this.elem.content.css("width",config.width);
		if(config.height && !individualInfo.height) this.elem.content.css("height",config.height);
		if(individualInfo.width) this.elem.content.css("width",individualInfo.width);
		if(individualInfo.height) this.elem.content.css("height",individualInfo.height);
		this.ref = individualInfo.ref || null;
		this.title = individualInfo.title || null;
		if(this.title) this.elem.title.text(this.title);
		this.config = config;
	};
	Dialog.prototype = {
		/**
		 * bindInsideEvents
		 */
		bindInsideEvents: function(){
			var self = this;
			/* set event to closeButtons */
			this.elem.container.find(this.config.selector.closeButton).click(function(){
				self.close();
			});
			/* set event to locationChangeAnchors */
			this.elem.container.find(this.config.selector.locChangeA).click(function(){
				var url = $(this).attr("href");
				if(self.config.useNoCache) url = noCache(url);
				self.elem.content.load(url, function(data){
					self.bindInsideEvents();
					if(self.config.pageLoadCallback) self.config.pageLoadCallback();
				});
				return false;
			});
			/* set event to locationChangeForms */
			this.elem.container.find(this.config.selector.locChangeForm).submit(function(){
				var form = $(this);
				var url = form.attr("action");
				var method = form.attr("method").toUpperCase();
				if(self.config.useNoCache) url = noCache(url);
				$.ajax({
					type: method,
					url: url,
					success: function(data){
						self.elem.content.html(data);
						self.bindInsideEvents();
						if(self.config.pageLoadCallback) self.config.pageLoadCallback();
					},
					error: function(){
						self.content.html("GOT SERVER ERROR");
					}
				});
				
				return false;
			});
		},
		/**
		 * bindContainerClickCloseEvents
		 */
		bindContainerClickCloseEvents: function(){
			var self = this;
			this.elem.container.click(function(){
				self.close();
			});
			this.elem.inTableContainer.click(function(evt){
				evt.stopPropagation();
			});
		},
		/**
		 * open
		 */
		open: function(){
			$.inPageDialog.currentDialog = this;
			var self = this;
			var fadeSpeed = $.inPageDialog.config.global.fadeSpeed.content;
			setTimeout(function(){ // keep min time
				if($.browser.msie6){
					/* IE6 is not cool at fading so just show */
					/* IE6 sometimes cant caliculate table's height 100% correctly */
					self.elem.posTable.height(win.height());
					self.elem.container.show();
					self.elem.inTableContainer.show();
					self.elem.content.show();
					self.setPosition();
					self.bindAdjustEvents();
					afterLoad();
				}else{
					self.elem.container.show();
					self.elem.inTableContainer.fadeIn(fadeSpeed, function(){
						afterLoad();
					});
				}
				function afterLoad(){
					if(self.config.showLoading) $.inPageDialog.overlay.loading.hide();
					$.inPageDialog.whileAnimation = false;
					if(self.config.pageLoadCallback) self.config.pageLoadCallback();
				}
			},50);
		},
		/**
		 * close
		 */
		close: function(){
			$.inPageDialog.whileAnimation = true; // set animation end flag
			var self=this;
			if($.browser.msie6){
				/* IE6 is not cool at fading so just hide */
				afterHide();
				self.unbindAdjustEvents();
			}else{
				var fadeSpeed = $.inPageDialog.config.global.fadeSpeed.content;
				self.elem.inTableContainer.fadeOut(fadeSpeed, function(){
					afterHide();
				});
			}
			function afterHide(){
				$.inPageDialog.whileAnimation = false; // set animation end flag
				self.elem.container.hide();
				$.inPageDialog.overlay.iframe.hide();
				$.inPageDialog.overlay.color.hide();
				if(self.config.pageCloseCallback) self.config.pageCloseCallback();
				$.inPageDialog.currentDialog = null;
				$.inPageDialog.currentDialogSet = null;
			}
		},
		/**
		 * bindAdjustEvents (IE6)
		 * IE6 doesnot support position:fixed. so, use absolute instead.
		 * this method will adjust the dialog's position when scroll and resize.
		 */
		bindAdjustEvents: function(){
			if(!$.browser.msie6) return;
			var self=this;
			win.bind("scroll resize",adjust);
			function adjust(){
				if(self.elem.container.is(":hidden")) return;
				self.setPosition();
			}
		},
		/**
		 * unbindAdjustEvents (IE6)
		 * release the adjust Events
		 */
		unbindAdjustEvents: function(){
			if(!$.browser.msie6) return;
			win.unbind("scroll resize",adjust);
		},
		/**
		 * setPosition (IE6)
		 * IE6 doesnot support position:fixed. so, use absolute instead.
		 * this method will adjust the dialog's position.
		 */
		setPosition: function(){
			if(!$.browser.msie6) return;
			var style={
				"top" : win.scrollTop(),
				"left" : win.scrollLeft()
			};
			// IE6 doesnot support position:fixed
			// so need to style top and left with absolute position
			// IE6 sometimes cant caliculate table's height 100% correctly
			this.elem.container.css(style);
			this.elem.posTable.height(win.height());
			return;
		}
	};
	/**
	 * Dialog subclass
	 */
		/**
		 * ImgDialog
		 */
		var ImgDialog = function(config,individualInfo){
			Dialog.apply(this, arguments);
			var self = this;
			var html = ['<img src="',this.ref,'" alt="" />'];
			this.elem.img = $(html.join(""));
			this.elem.img.load(function(){
				// DEBUG - applyIndividualScale
				self.elem.content.html(self.elem.img);
				self.elem.img.click(function(){
					$.inPageDialog.close();
				});
				body.append(self.elem.container);
				self.bindContainerClickCloseEvents();
				self.bindInsideEvents();
				self.open();
			});
		};
		$.extend(ImgDialog.prototype,Dialog.prototype);
		/**
		 * AjaxDialog
		 */
		var AjaxDialog = function(config,individualInfo){
			Dialog.apply(this, arguments);
			var self = this;
			self.elem.content.load(this.ref, function(data){
				// DEBUG - applyIndividualScale
				body.append(self.elem.container);
				self.bindContainerClickCloseEvents();
				self.bindInsideEvents();
				self.open();
			});
		};
		$.extend(AjaxDialog.prototype,Dialog.prototype);
		/**
		 * IframeDialog
		 */
		var IframeDialog = function(config,individualInfo){
			Dialog.apply(this, arguments);
			/* add random str to iframe to avoid cache */
			var html = [
				'<iframe frameborder="0" src="',this.ref,'" name="inPageDialog_iframeDialog',
				Math.round(Math.random()*1000),'"></iframe>'
			];
			var iframe = $(html.join(""));
			this.elem.content.html(iframe);
			this.bindContainerClickCloseEvents();
			body.append(this.elem.container);
			this.open();
		};
		$.extend(IframeDialog.prototype,Dialog.prototype);
		/**
		 * AnchorDialog
		 */
		var AnchorDialog = function(config,individualInfo){
			Dialog.apply(this, arguments);
			var html = $(this.ref).html();
			this.elem.content.html(html);
			this.bindContainerClickCloseEvents();
			this.bindInsideEvents();
			body.append(this.elem.container);
			this.open();
		};
		$.extend(AnchorDialog.prototype,Dialog.prototype);
	 	
})(jQuery); // end $ encapsulation

