/**
 * jQuery Window Plugin - To Popup A Window-like Beautiful Dialog
 * http://fstoke.net/jquery/window/
 * Author: David Hung
 * Version: 3.03
 * Last Revision: 2009-10-20
 *
 * The window status is defined as: cascade, minimized, maxmized
 *
 * This jQuery plugin has been tested in the following browsers:
 * - IE 7, 8
 * - Firefox 3.5
 * - Opera 9.64
 * - Safari 4.0
 * - Chrome 2.0
 *
 * Required jQuery Libraries:
 * jquery.js         (v1.3.2)
 * jquery-ui.js      (v1.7.2)
 *
 * Customized Button JSON Array Sample:
				var myButtons = [
					// facebook button
					{
					id: "btn_facebook",           // required, it must be unique in this array data
					title: "share to facebook",   // optional, it will popup a tooltip by browser while mouse cursor over it
					clazz: "my_button",           // optional, don't set border, padding, margin or any style which will change element position or size
					style: "",                    // optional, don't set border, padding, margin or any style which will change element position or size
					image: "http://justaddme.com/images/icons/facebook.gif", // required, the url of button icon(16x16 pixels)
					callback:                     // required, the callback function while click it
						function(element) {
							// change content display
							$("#demo_text").text("Share to Facebook!");
							$("#demo_logo").attr("src", "http://www.svfc.org.uk/Images/Advert/Facebook.jpg");

							alert('Share to Facebok! '+element);
						}
					},
					// twitter button
					{
					id: "btn_twitter",
					title: "share to twitter",
					clazz: "my_button",
					style: "background:gold;",
					image: "http://www.anvilon.com/img/logo/twitter-logo.png",
					callback:
						function(element) {
							// change content display
							$("#demo_text").text("Share to Twitter!");
							$("#demo_logo").attr("src", "http://img411.imageshack.us/img411/5821/mybanner4aaff081808de.jpg");

							alert('Share to Twitter! '+element);
						}
					}
				];
 *
 * Known Issues:
ISU_001 - If drag & resize a window first, then do maximize, the window will disappear while mouse down the header panel.
          It will appear again when mouse up.
 *
 * Version 3.03 change log:
 * - Modify window icon button margin-right to "4px"
 *
 * Version 3.02 change log:
 * - Fix serveral UI display bugs
 *
 * Version 3.01 change log:
 * - Availalbe to create customized icon buttons with passing a element JSON Array
 *
 * Version 3.00 change log:
 * - Add maximize feature
 * - Add adjust the width of header title text panel while window is resized. And add css style text-overflow: ellipsis; to let browser
 *   auto modify title text with "..." at the end while text width exceed panel width.
 * - Add create window from a html element, and could be limit boundary within it.
 * - Add iframeRedirectCheckMsg attribute to make iframe redirect checking mechanism more simple
 * - Add custBtns attribute to implement customized icon button feature.
 * - Modify bookmark not support message for Chrome, Safari and Opera.
 * - Modify option attribute "zIndex" to simpler "z"
 * - Add option attribute "animationSpeed" to control the animation speed
 *
 * Version 2.03 change log:
 * - Add three options attribute to control show function button(close, minimize, bookmark) or not
 *
 * Version 2.02 change log:
 * - Modify css class name to avoid conflict with others
 *
 * Version 2.01 change log:
 * - Fix checkBoundary work incorrectly bug.
 * - Add show loading animation while opening a iframe window.
 *
 * Version 2.00 change log:
 * - Modify call function method. It doesn't need caller panel now, plugin will add a div elemnt in html body automatically.
 * - Add minimized & restore feature.
 *
 * Version 1.02 change log:
 * - Fix second call, return wrong value bug
 * - Add set focus feature
 *
 * Version 1.01 change log:
 * - Change window panel css attribute: position to "fixed" to let window keep position on screen.
 * - Fix auto align center incorrectly bug
 *
 */
var jqWindowIndex = 0;
var lastFocusWindow = null;
var miniWindowStorage = new Array();
$.window = function(options) {
	var instance = new Window(null, options);
	instance.init();
	$.window.focus(instance); // switch focus
	return instance;
};

$.fn.window = function(options) {
	var caller = $(this);
	var instance = new Window(caller, options);
	instance.init();
	$.window.focus(instance); // switch focus
	return instance;
}

$.window.focus = function(windowIntance) {
	if( lastFocusWindow != null ) {
		lastFocusWindow.releaseFocus();
	}
	lastFocusWindow = windowIntance;
	lastFocusWindow.setFocus();
};

$.window.getVersion = function() {
	var version = "3.03";
	return version;
};

function Window(caller, options) {
	var ICON_WH = 16;
	var ICON_MARGIN = 4;
	var ICON_OFFSET = ICON_WH + ICON_MARGIN;
	var me = this;
	me.windowId = "window_" + (jqWindowIndex++);

	// flag & variables
	var absolute = true;
	var resizing = false;
	var minimized = false;
	var maximized = false;
	var redirectCheck = false;
	var pos = new Object();           // to save cascade mode current position
	var wh = new Object();            // to save cascade mode current width & height
	var orgPos = new Object();        // to save position before minimize
	var orgWh = new Object();         // to save width & height before minimize
	var targetCssStyle = {};          // to save target css style json object
	var funcBarWidth = 0;             // the width of header function bar

	// element
	var container = null;
	var header = null;
	var frame = null;
	var footer = null;

	var options = $.extend({
		title: "",                      // the title text of window
		url: null,                      // the target url of iframe ready to load.
		content: "",                    // the html content of window. this attribute only works when url is null.
		x: -1,                          // the x-axis value on screen(or caller element), if -1 means put on screen(or caller element) center
		y: -1,                          // the y-axis value on screen(or caller element), if -1 means put on screen(or caller element) center
		z: 2000,                        // the css z-index value
		width: 400,                     // window width
		height: 300,                    // window height
		minWidth: 200,                  // the minimum width, if -1 means no checking
		minHeight: 150,                 // the minimum height, if -1 means no checking
		maxWidth: 800,                  // the maximum width, if -1 means no checking
		maxHeight: 600,                 // the maximum height, if -1 means no checking
		closable: true,                 // a boolean flag to control window closable
		minimizable: true,              // a boolean flag to control window minimizable
		maximizable: true,              // a boolean flag to control window maximizable
		bookmarkable: true,             // a boolean flag to control window with remote url could be bookmarked
		draggable: true,                // a boolean flag to control window draggable
		resizable: true,                // a boolean flag to control window resizable
		scrollable: true,               // a boolean flag to show scroll bar or not
		checkBoundary: false,           // a boolean flag to check window dialog overflow html body or caller element
		custBtns: null,                 // a JSON Array to describe the customized button display & callback function
		onOpen: null,                   // a callback function while container is added into body
		onShow: null,                   // a callback function while whole window display routine is finished
		onClose: null,                  // a callback function while user click close button
		onIframeStart: null,            // a callback function while iframe ready to connect remoting url. this attribute only works while url attribute is given
		onIframeEnd: null,              // a callback function while iframe load finished. this attribute only works while url attribute is given
		iframeRedirectCheckMsg: null,   // if null means no check, or pass a string to show warning message while iframe is going to redirect
		animationSpeed: 400,            // the speed of various animations: maximize, minimize, restore, shift, in milliseconds
		showLog: true                   // a boolean flag to decide show log in Firefox plugin - firebug, IE8, chrome console
	}, options);

	//======================= public functions =======================
	me.init = function() {
		// build html
		var realCaller = caller != null? caller:$("body");
		realCaller.append("<div id='"+me.windowId+"' class='window_panel'></div>");
		container = realCaller.children("div#"+me.windowId);

		// onOpen call back
		if( options.onOpen != null && $.isFunction(options.onOpen) ) {
			options.onOpen(container);
		}

		wh.w = options.width;
		wh.h = options.height;
		container.width(options.width);
		container.height(options.height);
		container.css("position", absolute ? 'absolute' : 'fixed'); // must do this, or it will occurs display error
		container.css("z-index", options.z);

		// set position x
		if( options.x >= 0 || options.y >= 0 ) {
			if( options.x >= 0 ) {
				var pLeft = 0;
				if( caller != null ) {
					pLeft = options.x + caller.offset().left;
				} else {
					pLeft = options.x + jQuery(window).scrollLeft();
				}
				container.css("left", pLeft);
			} else { // put on center
				me.alignHorizontalCenter();
			}

			// set position y
			if( options.y >= 0 ) {
				var pTop = 0;
				if( caller != null ) {
					pTop = options.y + caller.offset().top;
				} else {
					pTop = options.y + jQuery(window).scrollTop();
				}
				container.css("top", pTop);
			} else { // put on middle
				me.alignVerticalCenter();
			}
		} else {
			me.alignCenter();
		}

		// build header html
		var headerHtml = "<div class='window_header window_header_normal'>"+
			"<div class='window_title_text'>"+options.title+"</div>"+
			"<div class='window_function_bar'></div>"+
			"</div>";

		container.append(headerHtml);
		header = container.children("div.window_header");
		var headerFuncPanel = header.children("div.window_function_bar");

		// add close button
		if( options.closable ) {
			headerFuncPanel.append( "<div title='close window' class='closeImg window_icon_button no-draggable'></div>" );
			headerFuncPanel.children(".closeImg").click(function() {
				redirectCheck = false;
				// onClose call back
				if( options.onClose != null && $.isFunction(options.onClose) ) {
					options.onClose(container);
				}
				me.destroy();
			});
			funcBarWidth += ICON_OFFSET;
		}

		// add maxmize button
		if( options.maximizable ) {
			headerFuncPanel.append( "<div title='maximize window' class='maximizeImg window_icon_button no-draggable'></div>" );
			headerFuncPanel.append( "<div title='cascade window' class='cascadeImg window_icon_button no-draggable' style='display:none;'></div>" );
			headerFuncPanel.children(".maximizeImg").click(function() {
				me.maximize();
			});
			headerFuncPanel.children(".cascadeImg").click(function() {
				me.restore(true);
			});
			funcBarWidth += ICON_OFFSET;
		}

		// add minimize button
		if( options.minimizable ) {
			headerFuncPanel.append( "<div title='minimize window' class='minimizeImg window_icon_button no-draggable'></div>" );
			headerFuncPanel.children(".minimizeImg").click(function() {
				me.minimize();
			});
			funcBarWidth += ICON_OFFSET;
		}

		// add bookmark button
		if( options.bookmarkable && options.url != null ) {
			headerFuncPanel.append( "<div title='bookmark this' class='bookmarkImg window_icon_button no-draggable'></div>" );
			headerFuncPanel.children(".bookmarkImg").click(function() {
				doBookmark(options.title, options.url);
			});
			funcBarWidth += ICON_OFFSET;
		}

		// add customized buttons
		addCustomizedButtns(headerFuncPanel);

		// set text & function bar width
		adjustHeaderTextPanelWidth();
		headerFuncPanel.width( funcBarWidth );

		// build iframe html
		var frameHeight = getFrameHeight(wh.h);
		if( options.url != null ) {
			// iframe starting call back
			if( options.onIframeStart != null && $.isFunction(options.onIframeStart) ) {
				log("start connecting iframe: "+options.url);
				options.onIframeStart(options.url);
			}

			// add iframe redirect checking
			if( options.iframeRedirectCheckMsg ) {
				redirectCheck = true;
				window.onbeforeunload = function() {
					if( redirectCheck ) {
						var msg = options.iframeRedirectCheckMsg.replace("{url}", options.url);
						return msg;
					}
				}
			}

			// show loading image
			container.append("<div class='frame_loading'>Loading...</div>");
			var loading = container.children(".frame_loading");
			loading.css("marginLeft",	'-' + (loading.outerWidth() / 2) - 20 + 'px');
			loading.click(function() {
				loading.remove();
			});

			// append iframe html
			var scrollingHtml = options.scrollable? "yes":"no";
			container.append("<iframe style='display:none;' class='window_frame no-draggable' scrolling='"+scrollingHtml+"' src='"+options.url+"' width='100%' height='"+frameHeight+"px' frameborder='0'></iframe>");
			frame = container.children(".window_frame");

			// iframe load finished call back
			frame.ready(function() {
				frame.show();
			});

			frame.load(function() {
				redirectCheck = false;
				loading.remove();
				log("load iframe finished: "+options.url);
				if( options.onIframeEnd != null && $.isFunction(options.onIframeEnd) ) {
					options.onIframeEnd(options.url);
				}
			});
		} else {
			container.append("<div class='window_frame no-draggable' style='width:100%; height:"+frameHeight+"px;'></div>");
			frame = container.children(".window_frame");
			frame.append(options.content);

			var scrollingCss = options.scrollable? "auto":"hidden";
			frame.css("overflow", scrollingCss);
		}

		// build footer html
		container.append("<div class='window_footer no-draggable'></div>");
		footer = container.children("div.window_footer");

		// bind container handle focus event
		container.mousedown(function() {
			$.window.focus(me);
		});

		// make window draggable
		if( options.draggable ) {
			container.draggable({
				cancel: '.no-draggable',
				start: function() {
					log( "drag start" );
					if( minimized || maximized ) { // if window is minimized or maximized, reset the css style
						container.css("position", "fixed");
						container.css(targetCssStyle);
					}
					hideContent();
				},
				stop: function() {
					log( "drag stop" );
					if( minimized || maximized ) { // if window is minimized or maximized, reset the css style
						container.css("position", "fixed");
						container.css(targetCssStyle);
					}
					showContent();
				}
			});
			// set boundary if got opotions
			if( options.checkBoundary ) {
				container.draggable('option', 'containment', 'parent');
			}
		}

		// make window resizable
		if( options.resizable ) {
			container.resizable({
				alsoResize: frame,
				start: function() { // this will be triggered when window is going to drag in minimized or maximized mode
					log( "resize start" );
					if( minimized || maximized ) { // if window is minimized or maximized, reset the css style
						container.css("position", "fixed");
						container.css(targetCssStyle);
					}
					hideContent();
				},
				stop: function() {
					log( "resize stop" );
					if( minimized || maximized ) { // if window is minimized or maximized, reset the css style
						container.css("position", "fixed");
						container.css(targetCssStyle);
					}
					adjustHeaderTextPanelWidth();
					showContent();
				}
			});

			// set resize min, max width & height
			if( options.maxWidth >= 0 ) {
				container.resizable('option', 'maxWidth', options.maxWidth);
			}
			if( options.maxHeight >= 0 ) {
				container.resizable('option', 'maxHeight', options.maxHeight);
			}
			if( options.minWidth >= 0 ) {
				container.resizable('option', 'minWidth', options.minWidth);
			}
			if( options.minHeight >= 0 ) {
				container.resizable('option', 'minHeight', options.minHeight);
			}
		}

		// handle window resize event
		$(window).resize(function() {
			if( maximized ) {
				if( minimized ) {
					// reset the restore width/height
					var screenWH = getBrowserScreenWH();
					orgWh.w = screenWH.width;
					orgWh.h = screenWH.height;
				} else {
					me.maximize(true, true);
				}
			}
		});

		//testing
		testing();

		// onShow call back
		if( options.onShow != null && $.isFunction(options.onShow) ) {
			options.onShow(container);
		}
	};

	me.setFocus = function() {
		container.css("z-index", options.z+1);
	};

	me.releaseFocus = function() {
		container.css("z-index", options.z);
	};

	me.getContainer = function() {
		return container;
	};

	me.getHeader = function() {
		return header;
	};

	me.getFrame = function() {
		return frame;
	};

	me.getFooter = function() {
		return footer;
	};

	me.alignCenter = function() {
		if( caller != null ) {
			var pLeft = (caller.width() - container.width())/2 + caller.offset().left;
			var pTop = (caller.height() - container.height())/2 + caller.offset().top;
			container.css({
				left:		pLeft,
				top:		pTop
			});
		} else {
			container.css({
				left:		'50%',
				top:		'50%'
			}).css({
				marginLeft:	'-' + (container.outerWidth() / 2) + 'px',
				marginTop:	'-' + (container.outerHeight() / 2) + 'px'
			});

			if (absolute) {
				container.css({
					marginLeft:	parseInt(container.css('marginLeft'), 10) + jQuery(window).scrollLeft(),
					marginTop:	parseInt(container.css('marginTop'), 10) + jQuery(window).scrollTop()
				});
			}
		};
	}

	me.alignHorizontalCenter = function() {
		if( caller != null ) {
			var pLeft = (caller.width() - container.width())/2 + caller.offset().left;
			container.css({
				left:		pLeft
			});
		} else {
			container.css({
				left:		'50%'
			}).css({
				marginLeft:	'-' + (container.outerWidth() / 2) + 'px'
			});

			if (absolute) {
				container.css({
					marginLeft:	parseInt(container.css('marginLeft'), 10) + jQuery(window).scrollLeft()
				});
			}
		}
	};

	me.alignVerticalCenter = function() {
		if( caller != null ) {
			var pTop = (caller.height() - container.height())/2 + caller.offset().top;
			container.css({
				top:		pTop
			});
		} else {
			container.css({
				top:		'50%'
			}).css({
				marginTop:	'-' + (container.outerHeight() / 2) + 'px'
			});

			if (absolute) {
				container.css({
					marginTop:	parseInt(container.css('marginTop'), 10) + jQuery(window).scrollTop()
				});
			}
		}
	};

	me.maximize = function(bImmediately, bNoSaveDisplay) {
		maximized = true;
		container.draggable( 'disable' );
		container.resizable( 'disable' );

		// save current display
		if( bNoSaveDisplay != true ) {
			pos.left = container.css("left");
			pos.top = container.css("top");
			pos.marginLeft = container.css("marginLeft");
			pos.marginTop = container.css("marginTop");
			wh.w = container.width();
			wh.h = container.height();
		}

		var screenWH = getBrowserScreenWH();
		targetCssStyle = {
			left: 0,
			top: 0,
			marginLeft: 0,
			marginTop: 0,
			width: screenWH.width,
			height: screenWH.height,
			opacity: 1
		};

		transferToFixed(); // transfer position first
		if( bImmediately ) {
			container.css(targetCssStyle);
			adjustHeaderTextPanelWidth();
			adjustFrameWH();
			// switch maximize, cascade button
			var headerFuncPanel = header.children("div.window_function_bar");
			headerFuncPanel.children(".maximizeImg").hide();
			headerFuncPanel.children(".cascadeImg").show();
		} else {
			frame.hide();
			footer.hide();
			container.animate(targetCssStyle, options.animationSpeed, 'swing', function() {
				frame.show();
				footer.show();
				adjustHeaderTextPanelWidth();
				adjustFrameWH();
				// switch maximize, cascade button
				var headerFuncPanel = header.children("div.window_function_bar");
				headerFuncPanel.children(".maximizeImg").hide();
				headerFuncPanel.children(".cascadeImg").show();
			});
		}

		//header.attr("title", options.title);
		//header.removeClass('window_header_normal');
		//header.addClass('window_header_minimize');
	};

	me.minimize = function() {
		minimized = true;
		frame.hide();
		footer.hide();
		container.draggable( 'disable' );
		container.resizable( 'disable' );

		// save current display
		orgPos.left = container.css("left");
		orgPos.top = container.css("top");
		orgPos.marginLeft = container.css("marginLeft");
		orgPos.marginTop = container.css("marginTop");
		orgWh.w = container.width();
		orgWh.h = container.height();

		var top = ( miniWindowStorage.length * 120) + "px";
		targetCssStyle = {
			left: 0,
			top: top,
			marginLeft: 0,
			marginTop: 0,
			width: 24,
			height: 120,
			opacity: 0.5
		};

		if( maximized == false ) { // transfer position first
			transferToFixed();
		}

		container.animate(targetCssStyle, options.animationSpeed, 'swing', function() {
			header.children("div.window_title_text").width( "100%" );
			transformTitleText();

			// bind header click event
			header.click(function() {
				me.restore();
			});
		});
		container.mouseover(function() {
			$(this).css("opacity", "1");
		});
		container.mouseout(function() {
			$(this).css("opacity", "0.5");
		});

		header.attr("title", options.title);
		header.removeClass('window_header_normal');
		header.addClass('window_header_minimize');
		header.children(".window_function_bar").hide();

		// put into minimized window storage
		miniWindowStorage[miniWindowStorage.length] = me;
	};

	me.restore = function(fromCascade) {
		var rpos = null;
		var rwh = null;
		if( fromCascade ) {
			maximized = false;
			rpos = pos;
			rwh = wh;
			frame.hide();
			footer.hide();
		} else {
			minimized = false;
			rpos = orgPos;
			rwh = orgWh;
		}
		header.removeAttr("title");
		header.removeClass('window_header_minimize');
		header.addClass('window_header_normal');
		header.children(".window_function_bar").show();

		container.unbind("mouseover");
		container.unbind("mouseout");
		restoreTitleText();
		if( minimized == false && maximized == false ) { // transfer position first
			transferToAbsolute();
		}

		targetCssStyle = {
			left: rpos.left,
			top: rpos.top,
			marginLeft: rpos.marginLeft,
			marginTop: rpos.marginTop,
			width: rwh.w,
			height: rwh.h,
			opacity: 1
		};

		container.animate(targetCssStyle, options.animationSpeed, 'swing', function() {
			frame.show();
			footer.show();
			header.unbind('click');
			adjustHeaderTextPanelWidth();
			adjustFrameWH();

			// switch maximize, cacade icon
			var headerFuncPanel = header.children("div.window_function_bar");
			if( maximized ) {
				headerFuncPanel.children(".maximizeImg").hide();
				headerFuncPanel.children(".cascadeImg").show();
			} else {
				container.draggable( 'enable' );
				container.resizable( 'enable' );
				headerFuncPanel.children(".maximizeImg").show();
				headerFuncPanel.children(".cascadeImg").hide();
			}
		});

		// pop from minimized window storage
		adjustPosition();
	};

	me.destroy = function() {
		container.remove();
	};

	me.getTargetCssStyle = function() {
		return targetCssStyle;
	};

	//======================= private functions =======================
	var transferToFixed = function() {
		var currPos = container.offset();
		var scrollXY = getBrowserScrollXY();
		container.css({
			position: "fixed",
			left: currPos.left - scrollXY[0],
			top: currPos.top - scrollXY[1],
			marginLeft: 0,
			marginTop: 0
		});
	};

	var transferToAbsolute = function() {
		var currPos = container.offset();
		container.css({
			position: "absolute",
			left: currPos.left,
			top: currPos.top
		});
	};

	var adjustPosition = function() {
		var doAdjust = false;
		for( var i=0; i<miniWindowStorage.length; i++ ) {
			var wnd = miniWindowStorage[i];
			if( wnd.windowId == me.windowId ) {
				miniWindowStorage.splice(i--,1); // remove array element
				doAdjust = true;
				continue;
			}
			if( doAdjust ) {
				var position = wnd.getContainer().position();
				//var top = position.top - 120;
				var top = i * 120;
				wnd.getContainer().animate({
					top: top
				}, options.animationSpeed);

				// modify target css style
				wnd.getTargetCssStyle().top = top;
			}
		}
	};

	var addCustomizedButtns = function(headerFuncPanel) {
		if( options.custBtns != null && typeof options.custBtns == 'object' ) {
			for( var i=0; i<options.custBtns.length; i++ ) {
				var btnData = options.custBtns[i];
				if( btnData != null && typeof btnData == 'object' ) {
					if( btnData.id != null && btnData.image != null && btnData.callback != null ) { // it's a JSON object
						var id = btnData.id != null? btnData.id:"";
						var clazz = btnData.clazz != null? btnData.clazz:"";
						var title = btnData.title != null? btnData.title:"";
						var style = btnData.style != null? btnData.style:"";
						var image = btnData.image != null? btnData.image:"";
						var callback = btnData.callback != null? btnData.callback:"";
						headerFuncPanel.append( "<img id='"+id+"' src='"+image+"' title='"+title+"' class='"+clazz+" window_icon_button no-draggable' style='"+style+"'/>" );
						var btn = headerFuncPanel.children("img[id="+id+"]");
						btn.get(0).clickCb = callback;
						if( callback != null && $.isFunction(callback)) {
							btn.click(function() {
								this.clickCb(this);
							});
						}
					} else { // it's a html element(or wrapped with jQuery)
						var btn = null;
						if( btnData.get ) {
							btn = btnData;
						} else {
							var btn = $(btnData);
						}
						btn.addClass("window_icon_button no-draggable");
						headerFuncPanel.append( btn );
						btn.show();
					}
				}
				funcBarWidth += ICON_OFFSET;
			}
		}
	};

	var adjustHeaderTextPanelWidth = function() {
		header.children("div.window_title_text").width( header.width() - funcBarWidth - 10 );
	};

	var adjustFrameWH = function() {
		var width = container.width();
		var height = container.height();
		var frameHeight = getFrameHeight(height);
		frame.width( width );
		frame.height( frameHeight );
	};

	var getBrowserScreenWH = function() {
		var width = document.documentElement.clientWidth;
		var height = document.documentElement.clientHeight;
		return {width:width, height:height};
	};

	function getBrowserScrollXY() {
	  var scrOfX = 0, scrOfY = 0;
	  if( typeof( window.pageYOffset ) == 'number' ) {
	    //Netscape compliant
	    scrOfY = window.pageYOffset;
	    scrOfX = window.pageXOffset;
	  } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
	    //DOM compliant
	    scrOfY = document.body.scrollTop;
	    scrOfX = document.body.scrollLeft;
	  } else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
	    //IE6 standards compliant mode
	    scrOfY = document.documentElement.scrollTop;
	    scrOfX = document.documentElement.scrollLeft;
	  }
	  return [ scrOfX, scrOfY ];
	}

	var doBookmark = function(title, url) {
		var ua = navigator.userAgent.toLowerCase();
		if ( $.browser.mozilla && window.sidebar ) { // Mozilla Firefox Bookmark
			window.sidebar.addPanel(title, url, "");
		} else if( $.browser.msie && window.external ) { // IE Favorite
			window.external.AddFavorite( url, title);
		} else if( ua.indexOf("chrome") >= 0 ) { // Chrome
			alert("Sorry! Chrome doesn't support bookmark function currently.");
			//alert("Press [Ctrl + D] to bookmark in Chrome");
		} else if($.browser.safari || ua.indexOf("safari") >= 0 ) { // Safari
			alert("Sorry! Safari doesn't support bookmark function currently.");
			//alert("Press [Ctrl + D] to bookmark in Safari");
		} else if($.browser.opera || ua.indexOf("opera") >= 0 ) { // Opera Hotlist
			alert("Sorry! Opera doesn't support bookmark function currently.");
			//alert("Press [Ctrl + D] to bookmark in Opera");
		}
	};

	var hideContent = function() {
		log("hideContent");
		if( minimized == false ) {
			frame.hide();
			container.css("opacity", "0.5");
		}
	};

	var showContent = function() {
		log("showContent");
		if( minimized == false ) {
			frame.show();
			container.css("opacity", "1");
		}
	};

	var getFrameHeight = function(windowHeight) {
		return windowHeight - 20 - 16 - 4; // minus header & footer & iframe's padding height
	};

	// modify title text as vertical presentation
	var transformTitleText = function() {
		var textBlock = header.children("div.window_title_text");
		var text = textBlock.text();
		var buf = "";
		var limitHeight = 120 - 7 - 13; // total height - padding height - one font height
		for( var i=0; i<text.length; i++ ) {
			var c = text.charAt(i);
			if( c == "-" || c == "_" ) {
				c = "|";
			}
			if( c == " " ) {
				c = "<div style='height:5px; line-height:5px;'>&nbsp;</div>";
				buf += c;
			} else {
				buf += c+"<br>";
			}
			textBlock.html(buf);
			//log( textBlock.html() +': ' +textBlock.height() +','+textBlock.outerHeight());
			if( textBlock.outerHeight() + 13 > limitHeight ) {
				buf += ":";
				textBlock.html(buf);
				break;
			}
		}
	};

	var restoreTitleText = function() {
		var textBlock = header.children("div.window_title_text");
		textBlock.text(options.title);
	};

	var testing = function() {
	};

	var log = function(msg) {
		if(options != null && options.showLog && window.console != null) {
			console.log(msg);
		}
	};
}