/*
####################################################################################################
# MESSAGE BOX OBJECT
# Version: 2.0.2 | Last Update: 26 July 2009 | Created On: 08 April 2009
####################################################################################################
# Copyright (C) by E-Muze (www.E-Muze.net)
# Copying the content of this file or fragments of this file's content with individual 
# functionality is strictly forbidden without the written consent of the author. Using this code
# as an example in order to understand and learn from it, with the purpose of improving your own
# work and/or writing your own code with similar functionality, is allowed and encouraged.
####################################################################################################
# CHANGELOG:
# v2.0.2 (26 July 2009)
#	- Fixed bug with IE not loosing the scroll lock after the overlay was closed.
####################################################################################################
# NO DEPENDENCIES
####################################################################################################
# DOCUMENTATION:
# Simulates the classic alert box through javascript and it can also be used to display custom
# html content instead of a simple text warning.
# The object is auto-instanciated under msgBox name and will not work and should not be 
# used under multiple instances.
####################################################################################################
# COMPATIBILITY:
# Internet Explorer 8.0.6, Firefox 3.0.8
# System has not been tested on other browsers.
####################################################################################################
# KNOWN, UNFIXED PROBLEMS
# 1. Window can be scrolled using directional keys and page up/down keys while popup opened.
# 2. Only center alignment currently supported.
# 3. No zIndex autodetect.
# 4. Custom position not implemented.
####################################################################################################
*/

function msgBoxSystem (CFG)
{
	//----------------------------------------------------------------------------------------------
	// OBJECT PROPERTIES
	
	var self = this; // bind reference to self
	
	self.CFG = null; // container for local configuration parameters
	
	self.origScrollCoords = [0, 0]; // scroll coordinates at the time of message window open
	self.msgBoxCoords = [0, 0]; // coordinates of the currently displayed message box
	self.msgBoxSize = [0, 0]; // size of the currently displayed message box
	
	self.recallOnSelectStart = null; // container to store any existing onselectstart method before window lockdown
	self.recallOnMouseDown = null; // container to store any existing onmousedown method before window lockdown
	self.recallOnScroll = null; // container to store any existing onscroll method before window lockdown
	self.recallOnResize = null; // container to store any existing onresize method before window lockdown
	
	self.mBoxLocker = null; // referrence to message box locking layer
	self.mBox = null; // referrence to message box window
	self.opened = false; // true if overlay is opened false if it is not
	
	self.lockerZindex = 0;
	self.windowZindex = 0;
	
	// define popup window template
	self.template = '<div style="position: absolute; border: solid 2px #000055;	background: #ffffff;"><div style="display:{SHOW_TITLE};">{TITLE}</div><div>{BODY}</div><div>[&nbsp;<a href="Javascript:;" onclick="msgBox.close ();">Close</a>&nbsp;]</div></div>';
	
	//----------------------------------------------------------------------------------------------
	// OBJECT INIT
	
	self.init = function (CFG)
	{
		// load configuration params
		self.loadConfig (CFG);
		
		// overwrite template if we have custom one
		if (self.CFG.template) self.template = CFG.template;
	};
	
	//----------------------------------------------------------------------------------------------
	// GET SCROLL COORDS METHOD
	
	/*
		Cross browser function to get x and y offsets for scrolling windows.
	*/
	
	self.getScrollCoords = function ()
	{
		var scrOfX = 0, scrOfY = 0;
		
		// Netscape compliant
		if (typeof (window.pageYOffset) == "number")
		{
			scrOfY = window.pageYOffset;
			scrOfX = window.pageXOffset;
		} 
		// DOM compliant
		else if (document.body && (document.body.scrollLeft || document.body.scrollTop))
		{
			scrOfY = document.body.scrollTop;
			scrOfX = document.body.scrollLeft;
		}
		// IE6 compliant mode
		else if	(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop))
		{
			scrOfY = document.documentElement.scrollTop;
			scrOfX = document.documentElement.scrollLeft;
		}
		
		return [ scrOfX, scrOfY ];
	};
	
	//----------------------------------------------------------------------------------------------
	// LOCK WINDOW METHOD
	
	self.lockWindow = function (allowMouseDown)
	{
		// disable scroll
		document.body.style.overflow = "hidden";
		
		// remember original scroll coordinates
		self.origScrollCoords = self.getScrollCoords ();
		
		// remember original window size
		self.origSize = [window.innerWidth ? window.innerWidth : document.body.offsetWidth, window.innerHeight ? window.innerHeight : document.body.offsetHeight];
		
		// remember original events
		self.recallOnSelectStart = document.body.onselectstart; 
		self.recallOnMouseDown = document.body.onmousedown;
		self.recallOnScroll = document.body.onscroll;
		
		// overwrite some events to prevent text selection 
		document.body.onselectstart = function () { return false; }
		if (!allowMouseDown) document.body.onmousedown = function () { return false; }
		
		// bind onscroll reset method
		document.body.onscroll = self.resetScroll;
		
		// bind update method on onresize event
		window.onresize = self.update;
		
		// MISSING CODE: intercept keyboard events to disable arrow keys, page up/down and any other keys that can cause manual scrolling
	}
	
	//----------------------------------------------------------------------------------------------
	// UNLOCK WINDOW METHOD
	
	self.unlockWindow = function ()
	{
		// re-enable scroll
		document.body.style.overflow = "auto";
		
		// revert overwrtitten events to their original values
		document.body.onselectstart = self.recallOnSelectStart;
		document.body.onmousedown = self.recallOnMouseDown;
		document.body.onscroll = self.recallOnScroll;
		document.body.onresize = self.recallOnResize;
		
		// MISSING CODE: disable keyboard interception
		
		// return to original scroll coordinates (there should be no way to scroll while the window is locked, but just in case)
		self.resetScroll ();
	}
	
	//----------------------------------------------------------------------------------------------
	// RESET POSITION METHOD
	
	self.resetScroll = function ()
	{
		// resets the main window to its original scroll offset
		if (self.opened)
			window.scroll (self.origScrollCoords[0], self.origScrollCoords[1]);
	};
	
	//----------------------------------------------------------------------------------------------
	// CLOSE METHOD
	
	self.close = function ()
	{
		// hide locking layer and popup window
		self.mBoxLocker.style.display = "none";
		self.mBox.style.display = "none";
		
		// unlock window
		self.unlockWindow ();
		
		// mark as closed
		self.opened = false;
	};
	
	//----------------------------------------------------------------------------------------------
	// OPEN METHOD
	
	self.open = function (title, body, pos, size, zIndex, template, customHTML, overflow, allowMouseDown)
	{
		// set overflow
		self.overflow = overflow;
		
		// lock window
		self.lockWindow (allowMouseDown);
		
		// MISSING CODE: pos can be an alignment as 'center' or other alignment, or an array containing x and y coordinates, this should be handled here and stored as class properties 
		
		// set window size
		if (size) self.msgBoxSize = size;
		else self.msgBoxSize = [self.CFG.width, self.CFG.height];
		
		// update locking layer and popup window
		self.update ();
		
		// if custom html is set, use it as it is
		if (customHTML) self.mBox.innerHTML = customHTML;
		else
		{
			// otherwise process template and write it within the popup window
			var buff = template ? template : self.template;
			if (self.CFG.title) buff = buff.replace (/\{TITLE\}/, self.CFG.title);
			buff = buff.replace (/\{SHOW_TITLE\}/, self.CFG.title ? '' : 'none');
			buff = buff.replace (/\{BODY\}/, self.CFG.body);
			self.mBox.innerHTML = buff;
		}
		
		// display locking layer and popup window
		self.mBoxLocker.style.display = '';
		self.mBox.style.display = '';
		
		// mark as opened
		self.opened = true;
	};
	
	//----------------------------------------------------------------------------------------------
	// OPEN CUSTOM METHOD
	
	self.openCustom = function (customHTML, pos, size, zIndex)
	{
		self.open (null, null, pos, size, zIndex, null, customHTML, true, true);
	}
	
	//----------------------------------------------------------------------------------------------
	// UPDATE METHOD
	
	self.update = function (overflow)
	{
		// get screen size
		var screenWidth = window.innerWidth ? window.innerWidth : document.body.offsetWidth;
		var screenHeight = window.innerHeight ? window.innerHeight : document.body.offsetHeight;
		
		// get page size
		var pageHeight = document.body.scrollHeight;
		var pageWidth = document.body.scrollWidth;
		
		// determine coordinates for the center of the screen 
		var center = [Math.round (screenWidth / 2), Math.round (screenHeight / 2)];
		
		// use custom coordinates if we have any
		if (self.CFG.position)
		{
			self.msgBoxCoords = self.CFG.position;
		}
		// else, get coordinates based on alignment
		else
		{
			// handle center alignment
			if (self.CFG.align == "center")
			{
				// set coordinates relative to screen
				self.msgBoxCoords = [center[0] - Math.round (self.msgBoxSize[0] / 2), center[1] - Math.round (self.msgBoxSize[1] / 2)];
				
				// add scroll offsets to coordinates
				var aux = self.getScrollCoords();
				self.msgBoxCoords[0] += aux[0];
				self.msgBoxCoords[1] += aux[1];
			}
		}
		
		// create locking element if none exist
		if (!self.mBoxLocker)
		{
			// place locker container
			self.mBoxLocker = document.createElement ("div");
			document.body.appendChild (self.mBoxLocker);
			
			// get locker zindex
			self.lockerZindex = parseInt (self.CFG.zIndex ? self.CFG.zIndex : 1000);
		}
		
		// set locker layer properties
		self.mBoxLocker.id = 'msgBoxLocker';
		self.mBoxLocker.style.position = 'absolute';
		self.mBoxLocker.style.left = '0px';
		self.mBoxLocker.style.top = '0px';
		self.mBoxLocker.style.width = pageWidth + 'px';
		self.mBoxLocker.style.height = pageHeight + 'px';
		self.mBoxLocker.style.zIndex = self.lockerZindex;
		self.mBoxLocker.style.background = self.CFG.lockerBgrStyle;
		self.mBoxLocker.style.filter = 'alpha(opacity=' + self.CFG.lockerOpacity + ')';
		self.mBoxLocker.style.opacity = (self.CFG.lockerOpacity / 100);
		
		// create window element if none exist
		if (!self.mBox)
		{
			// place window container
			self.mBox = document.createElement ("div");
			document.body.appendChild (self.mBox);
			
			// get window zindex
			self.windowZindex = self.lockerZindex + 1;
		}
		
		// set window layer properties
		self.mBox.id = 'msgBox';
		self.mBox.style.position = 'absolute';
		self.mBox.style.left = self.msgBoxCoords[0] + 'px';
		self.mBox.style.top = self.msgBoxCoords[1] + 'px';
		self.mBox.style.zIndex = self.windowZindex;
		self.mBox.style.filter = 'alpha(opacity=' + self.CFG.windowOpacity + ')';
		self.mBox.style.opacity = (self.CFG.windowOpacity / 100);
		self.mBox.style.backgroundColor = '#ff0000';
		
		if (!self.overflow)
		{
			self.mBox.style.width = self.CFG.width + 'px';
			self.mBox.style.height = self.CFG.height + 'px';
		}
		
		// return success
		return true;
	};
	
	//----------------------------------------------------------------------------------------------
	// LOAD CONFIG
	
	/*
		This method loads the configuration parameters from the given configuration array and
		uses defaults where values are not set.
	*/
	
	self.loadConfig = function (CFG)
	{
		if (!CFG) CFG = new Object ();
		
		self.CFG = 
		{
			width : self.def (CFG.width, 320), // width of popup box
			height : self.def (CFG.height, 240), // height of popup box
			align : self.def (CFG.align, 'center'), // alignment for the popup window (this gets overwritten by custom coordinates if they are set)
			position : self.def (CFG.position, null), // custom position for the popup window (note that system does not autoupdate window when custom positioned)
			lockerBgrStyle : self.def (CFG.lockerBgrStyle, '#333333'), // locking layer background style
			lockerOpacity : self.def (CFG.lockerOpacity, 50), // locking layer opacity
			windowOpacity : self.def (CFG.windowOpacity, 100), // window layer opacity
			zIndex : self.def (CFG.zIndex, null), // custom zIndex (will overwrite autodetect)
			title : self.def (CFG.title, null), // title to be displayed within the title area of the popup box
			body : self.def (CFG.body, 'Sample Message'), // text or html to go inside the message area of the popup box
			template : self.def (CFG.template, null) // if set, this will overwrite the default popup window template
		};
	};
	
	//----------------------------------------------------------------------------------------------
	// DEF
	
	/*
		Method used to return the value if it is valid (including zeros) or return the default
		when value is undefined or non existing
	*/
	
	self.def = function (value, def)
	{
		if (value === 0 || (value && value != undefined)) return value;
		else return def;
	}
	
	//----------------------------------------------------------------------------------------------
	// INIT THE OBJECT AUTOMATICALLY
	
	self.init (CFG);
}

// automatically create object instance
var msgBox = new msgBoxSystem ();

/*
####################################################################################################
*/
