/**
* Global JavaScript Definitions
*
* @author				Matt Gifford
* @copyright			2009 Timeshifting Interactive Limited
* @version			1.6
*/

var viewHandler = WebPage;

dojo.require('dojo.cookie');
dojo.require("dijit.Tooltip");



// Execute on load handler
dojo.addOnLoad(
	function()
		{
		if (viewHandler !== WebPage)
			{
			// Extend the base page class and create the xhtml object
			viewHandler.inheritsFrom( WebPage );
			xhtml = new viewHandler();
			}
		else
			{
			// Create a generic page xhtml object
			xhtml = new WebPage();
			}

		// Main page initialization
		xhtml.init();
		}
	);


/**
* Creates a new WebPage object with methods used by all pages, can be extended to add page specific methods.
*
* @author				Matt Gifford
* @copyright			2009 Timeshifting Interactive Limited
*/
function WebPage()
	{
	// Step 1. Define Properties

	var _instance = this;
	this.log = function(msg) { if (typeof(console) != 'undefined') { console.log(msg); } };
	this.animationReferences = {};
	__videoPlaying = false;

	// Scrolling regions (global variables to improve performance in IE)
	__scrollbars =
		{
		contentHeight: {},
		contentRange: {},
		grabberY: {},
		grabberSize: {},
		grabberRange: {},
		previousMouseY: 0,
		regionBeingDragged: '',
		eventHandlersAdded: false,
		locked: false
		}
	__isTrident = !!(window.attachEvent && !window.opera);
	__artboard = null;
	__grabber = null;


	// Step 2. Define Public Methods

	/**
	* Sets up the initial page state and event handlers
	*/
	this.init = function()
		{
		this.ratingStars = new RatingStars();
		this.isMobileSafari = navigator.userAgent.toLowerCase().indexOf('mobile') != -1 && navigator.userAgent.toLowerCase().indexOf('safari') != -1 ? true : false;

		this.initAnchors();
		this.initInputButtons();
		this.initGlobalNav();
		this.initTooltips();

		// Set class as initialized
		this.initialized = true;
		this.loadSpazzyBlogContent();
		this.loadJustineBlogContent();
		}

	
	/**
	* Loads the latest content for the spazzy blog
	*/
	this.loadSpazzyBlogContent = function()
		{
		// Update the content
		dojo.xhrGet(
			{
			url: '/blog/spazzy',
			preventCache: true,
			handleAs: "text",
				load: function(data)
					{
					// Add the blog content into the document
					if (document.getElementById('spazzyBody'))
						{
						document.getElementById('spazzyBody').innerHTML = data;
						}
					}
				}
			);
		}


	/**
	* Loads the latest content for the 40 and bitter blog
	*/
	this.loadJustineBlogContent = function()
		{
		if (document.getElementById('justineBody') && typeof( tumblr_api_read ) != 'undefined')
			{
			 var postDate = new Date(tumblr_api_read.posts[0]["date"]);
			var html = '<h4><a title="Subscribe to 40 and Bitter" href="http://www.40andbitter.tv/rss" class="rss">RSS Feed</a><a href="http://www.40andbitter.tv/" class="title">' + tumblr_api_read.posts[0]["regular-title"] + '</a></h4>';
			html += '<p class="timestamp">Posted ' + (postDate.getMonth()+1 < 10 ? '0' : '') + (postDate.getMonth()+1) + '/' + (postDate.getDate() < 10 ? '0' : '') + postDate.getDate() + '/' + (postDate.getYear() > 100 ? (postDate.getYear() + '').substring(1,3) : postDate.getYear()) + ' ' + (postDate.getHours() > 12 ? (postDate.getHours() - 12) : postDate.getHours()) + ':' + (postDate.getMinutes() < 10 ? '0' : '') + postDate.getMinutes() + (postDate.getHours() < 12 ? 'am' : 'pm') + '</p>';
			html += '<p class="except">' + tumblr_api_read.posts[0]["regular-body"].replace(/<([^>]+)>/ig, '').substring(0,200) + '...</p>';
			document.getElementById('justineBody').innerHTML = html;
			}
		}


	/**
	* Adds standard event handlers to process in-page links and offsite links
	*/
	this.initAnchors = function()
		{
		var links = document.getElementsByTagName('a');
		for (var x = 0; x < links.length; x++)
			{
			// 1. Make offsite links and pdfs open in a new tab/window
			if (/\b(offsite|pdf)\b/.exec(links[x].className))
				{
				links[x].onclick = function()
					{
					window.open(this.href,'_blank');
					return false;
					}
				}

			// 2. Set the active class on links to the current page
			if ((links[x].href == window.location.href || links[x].href == window.location.href + 'index.html') && links[x].href.indexOf('#') == -1)
				{
				if (links[x].className.indexOf('active') == -1)
					{
					links[x].className += ' active';
					}
				}
			}
		}


	/**
	* Adds rollover support to input[type=image] elements
	*/
	this.initInputButtons = function()
		{
		var rolloverCache = [];
		var inputs = dojo.query('input.hasRollover');
		for (var x = 0; x < inputs.length; x++)
			{
			// 1. Add event handlers to swap the images
			inputs[x].onmouseover = function()
				{
				this.src = this.src.replace(/\.(gif|jpg|png)/, '-over.$1');
				}
			inputs[x].onmouseout = function()
				{
				this.src = this.src.replace(/-over\.(gif|jpg|png)/, '.$1');
				}

			// 2. Pre-cache the rollover image
			var newImage = new Image();
			newImage.src = inputs[x].src.replace(/\.(gif|jpg|png)/i, '-over.$1');
			rolloverCache[rolloverCache.length] = newImage;
			}
		}


	/**
	* Adds the animation to the global header nav menu
	*/
	this.initGlobalNav = function()
		{
		if (!document.getElementById('globalHeaderNav'))
			{
			return;
			}

		var nodeIds = ['navHome', 'navRoster', 'navCoworker', 'navMerchandise'];
		for (var x = 0, url = ''; x < nodeIds.length; x++)
			{
			if (document.getElementById(nodeIds[x]))
				{
				this.animationReferences[nodeIds[x]] = null;

				// Add on mouseover event
				document.getElementById(nodeIds[x]).onmouseover = function()
					{
					// Try to stop any current animation
					try { xhtml.animationReferences[this.id].stop(false); } catch (err) {}

					// Start the new animation
					xhtml.animationReferences[this.id] = dojo.fadeIn( {duration: 200, node: document.getElementById(this.id).getElementsByTagName('h3')[0].getElementsByTagName('a')[0] } );
					xhtml.animationReferences[this.id].play();
					}

				// Add on mouseover event
				document.getElementById(nodeIds[x]).onmouseout = function()
					{
					// Try to stop any current animation
					try { xhtml.animationReferences[this.id].stop(false); } catch (err) {}

					// Start the new animation
					xhtml.animationReferences[this.id] = dojo.fadeOut( {duration: 700, node: document.getElementById(this.id).getElementsByTagName('h3')[0].getElementsByTagName('a')[0] } );
					xhtml.animationReferences[this.id].play();
					}
				}
			}
		}


	/**
	* Adds tooltips to nodes with the 'hasTooltip' class
	*/
	this.initTooltips = function()
		{
		// Set tooltip position
		dijit.Tooltip.defaultPosition = ["above"];

		// Get the nodes and process
		var nodes = dojo.query(".hasTooltip");
		for (var x = nodes.length-1; 0 <= x; x--)
			{
			// Only add the tooltip if there's a title attrbiute (we remove this, so stops tooltip being added twice)
			if (nodes[x].getAttribute('title') != '')
				{
				// Add the tooltip
				new dijit.Tooltip({
				connectId: [nodes[x]],
				label: nodes[x].getAttribute('title')
					});

				// Remove the title attribute
				nodes[x].setAttribute('title', '');
				}
			}
		}


	/**
	* Sets the connection speed cookie and hides the connection speed overlay
	*
	* @param		speed			The connection speed to set
	*/
	this.setConnectionSpeed = function(speed)
		{
		// Remove the overlay
		dojo.destroy('mediaPlayerSpeed');

		// Save the connection speed
		dojo.cookie('connectionspeed', speed, {expires: 365});
		// Start the player
		initFlash();
		}


	/**
	* Changes the blog page displayed
	*
	*/
	this.loadSpazzyPage = function()
		{
		// Update the content
		dojo.xhrGet(
			{
			url: '/blog/spazzy',
			preventCache: true,
			handleAs: "text",
				load: function(data)
					{
					// Add the new playlist in to the document
					document.getElementById('spazzyBody').innerHTML = data;
					xhtml.initTooltips();
					}
				}
			);
		}


	/**
	* Shares the current page on the specified network
	*
	* @param		network		The network to share on (optional, displays full share dialog if omitted)
	*/
	this.share = function(network)
		{
		// Update the share params
		this.shareUpdate();

		// Select the correct url to throw
		switch (network)
			{
			case 'Facebook':
				var url = 'http://www.facebook.com/sharer.php?u=%url%&t=%title%';
				break;

			case 'Twitter':
				var url = 'http://twitter.com/home?status=Currently+reading+%url%';
				break;

			case 'Digg':
				var url = 'http://digg.com/submit?url=%url%&title=%title%';
				break;

			case 'MySpace':
				var url = 'http://www.myspace.com/Modules/PostTo/Pages/?u=%url%&t=%title%';
				break;

			default:
				// No network specified, so display share box
				xhtml.shareDialog();
				return;
			}

		// Confirm, add the content and throw
		if (confirm('Would you like to post this item to your ' + network + ' account?') == true)
			{
			url = url.replace('%url%', encodeURIComponent(document.getElementById('shareURL').getAttribute('content')));
			url = url.replace('%title%', encodeURIComponent(document.getElementById('shareTitle').getAttribute('content')));

			// Throw the url
			if (network == 'Facebook')
				{
				window.open(url,'sharer','toolbar=0,status=0,width=626,height=436');
				}
			else
				{
				window.open(url, '_blank');
				}
			return false;
			}
		}


	/**
	* Updates the share this meta tags from the anchor clicked on
	*
	* @param		obj		The anchor clicked on
	*/
	this.shareUpdate = function(obj)
		{
		if (arguments.length)
			{
			// Update with the supplied values
			document.getElementById('shareURL').setAttribute('content', obj.href);
			document.getElementById('shareTitle').setAttribute('content', obj.getAttribute('rel'));
			}
		else
			{
			// Check if there's episode list, if so extract the values from the now playing video
			if (document.getElementById('episodeListArtboard'))
				{
				var playlistActiveNode = dojo.query('#episodeListArtboard div.episodeItemPlaying');

				// Check if there's a currently playing item
				if (playlistActiveNode.length == 0)
					{
					return;
					}

				// Update the share values
				document.getElementById('shareURL').setAttribute('content', 'http://www.easytoassembleseries.com' + playlistActiveNode[0].getAttribute('shareUrl'));
				document.getElementById('shareTitle').setAttribute('content', playlistActiveNode[0].getAttribute('shareTitle'));
				}
			}
		}


	/**
	* Displays the share this dialog (social networking or email)
	*/
	this.shareDialog = function()
		{
		// Kill any existing share dialog
		if (!!document.getElementById('share') == true)
			{
			document.body.removeChild( document.getElementById('share') );
			}

		// Build the dialog html
		var html = [];
		html.push('<div id="shareBackground" onclick="document.body.removeChild(document.getElementById(\'share\'));"></div>');
		html.push('<div id="shareDialog">');
		html.push('<div id="shareDialogSocial" class="social">');
		html.push('<h3>Share via Social Networking</h3>');
		html.push('<ul class="list1">');
		html.push('<li><a onclick="xhtml.shareSocial(\'facebook\');" href="javascript:;" class="facebook">Facebook</a></li>');
		html.push('<li><a onclick="xhtml.shareSocial(\'bebo\');" href="javascript:;" class="bebo">Bebo</a></li>');
		html.push('<li><a onclick="xhtml.shareSocial(\'delicious\');" href="javascript:;" class="delicious">Delicious</a></li>');
		html.push('<li><a onclick="xhtml.shareSocial(\'digg\');" href="javascript:;" class="digg">Digg</a></li>');
		html.push('<li><a onclick="xhtml.shareSocial(\'google\');" href="javascript:;" class="google">Google Bookmarks</a></li>');
		html.push('</ul>');
		html.push('<ul class="list2">');
		html.push('<li><a onclick="xhtml.shareSocial(\'myspace\');" href="javascript:;" class="myspace">MySpace</a></li>');
		html.push('<li><a onclick="xhtml.shareSocial(\'technorati\');" href="javascript:;" class="technorati">Technorati</a></li>');
		html.push('<li><a onclick="xhtml.shareSocial(\'windowslive\');" href="javascript:;" class="windowslive">Windows Live</a></li>');
		html.push('<li><a onclick="xhtml.shareSocial(\'yahoomyweb\');" href="javascript:;" class="yahoomyweb">Yahoo! My Web</a></li>');
		html.push('</ul>');
		html.push('</div>');
		html.push('<div class="email">');
		html.push('<h3>Email to a Friend</h3>');
		html.push('<form id="formShareEmail" onsubmit="return false" method="post" action="#">');
		html.push('<fieldset>');
		html.push('<label class="hidden"><b>Missing Information</b><br/>Please complete the name &amp; email addresses fields and ensure the email addresses are valid.</label>');
		html.push('<label class="hidden"><b>Sending Message</b><br/>Please wait...</label>');
		html.push('</fieldset>');
		html.push('<fieldset>');
		html.push('<label>Friend\'s Email</label>');
		html.push('<input type="text" value="" name="toAddress" class="text"/>');
		html.push('<label>Your Name</label>');
		html.push('<input type="text" value="" name="fromName" class="text"/>');
		html.push('<label>Your Email</label>');
		html.push('<input type="text" value="" name="fromAddress" class="text"/>');
		html.push('<label>Message</label>');
		html.push('<textarea name="message"></textarea>');
		html.push('<input id="formShareEmailUrl" type="hidden" name="url" value=""/>');
		html.push('<input id="formShareEmailTitle" type="hidden" name="title" value=""/>');
//		html.push('<label>Verfication Code</label>');
//		html.push('<input type="text" value="" name="captcha" class="text"/>');
//		html.push('<div class="captcha"><img src="images/FPO-captcha.png" width="182" height="60" alt=""/><a href="#">Can\'t read the verfication code?</a></div>');
		html.push('<a class="send" href="javascript:;" onclick="xhtml.shareEmail();">Send Message</a>');
		html.push('</fieldset>');
		html.push('</form>');
		html.push('</div>');
		html.push('<br class="clear"/>');
		html.push('<a class="close" href="javascript:;" onclick="document.body.removeChild(document.getElementById(\'share\'));"></a>');
		html.push('</div>');

		// Create the dialog
		var share = document.createElement('div');
		share.id = 'share';
		share.innerHTML = html.join('\n');
		document.body.appendChild( share );
		}


	/**
	* Displays the share this embed video dialog
	*/
	this.shareEmbed = function()
		{
		// Kill any existing share dialog
		if (!!document.getElementById('share') == true)
			{
			document.body.removeChild( document.getElementById('share') );
			}

		// Build embed code
		var flashHtml = '<object width="580" height="326"><param name="movie" value="' + document.getElementById('shareFlash').getAttribute('href') + '"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="' + document.getElementById('shareFlash').getAttribute('href') + '" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="580" height="326"></embed></object>';

		// Build the dialog html
		var html = [];
		html.push('<div id="shareBackground" onclick="document.body.removeChild(document.getElementById(\'share\'));"></div>');
		html.push('<div id="shareDialog">');
		html.push('<div class="embed">');
		html.push('<h3>Embed this Video</h3>');
		html.push('<p>Add this video to your blog or webpage, copy and paste the code in the box below:</p>');
		html.push('<form method="post" action="#">');
		html.push('<fieldset>');
		html.push('<textarea name="code" onfocus="this.select();">' + flashHtml + '</textarea>');
		html.push('</fieldset>');
		html.push('</form>');
		html.push('</div>');
		html.push('<br class="clear"/>');
		html.push('<a class="close" href="javascript:;" onclick="document.body.removeChild(document.getElementById(\'share\'));"></a>');
		html.push('</div>');

		// Create the dialog
		var share = document.createElement('div');
		share.id = 'share';
		share.innerHTML = html.join('\n');
		document.body.appendChild( share );
		}


	/**
	* Shares the current page via social networking
	*
	* @param		network		The social media network
	*/
	this.shareSocial = function(network)
		{
		// Select the correct url to throw
		switch (network)
			{
			case 'bebo':
				var url = 'http://www.bebo.com/c/share?Url=%url%&t=%title%';
				break;

			case 'delicious':
				var url = 'http://del.icio.us/post?url=%url%&title=%title%';
				break;

			case 'digg':
				var url = 'http://digg.com/submit?url=%url%&title=%title%';
				break;

			case 'facebook':
				var url = 'http://www.facebook.com/sharer.php?u=%url%&t=%title%';
				break;

			case 'google':
				var url = 'http://www.google.com/bookmarks/mark?op=edit&bkmk=%url%&title=%title%';
				break;

			case 'myspace':
				var url = 'http://www.myspace.com/Modules/PostTo/Pages/?u=%url%&t=%title%';
				break;

			case 'stumbleupon':
				var url = 'http://www.stumbleupon.com/submit?url=%url%&title=%title%';
				break;

			case 'technorati':
				var url = 'http://www.technorati.com/faves?add=%url%';
				break;

			case 'windowslive':
				var url = 'https://favorites.live.com/quickadd.aspx?marklet=1&mkt=en-us&url=%url%&title=%title%&top=1';
				break;

			case 'yahoomyweb':
				var url = 'http://myweb2.search.yahoo.com/myresults/bookmarklet?u=%url%&t=%title%';
				break;

			default:
				document.body.removeChild(document.getElementById('share'));
				return;
			}

		// Configure the url
		url = url.replace('%url%', encodeURIComponent(document.getElementById('shareURL').getAttribute('content')));
		url = url.replace('%title%', encodeURIComponent(document.getElementById('shareTitle').getAttribute('content')));

		// Throw the url
		window.open(url, '_blank');

		// Close the share box
		document.body.removeChild(document.getElementById('share'));
		}


	/**
	* Shares the current page via email
	*/
	this.shareEmail = function()
		{
		// Check for blank input
		var obj = document.getElementById('formShareEmail');
		var inputs = obj.getElementsByTagName('input');
		for (var x = 0; x < 3; x++)
			{
			if (inputs[x].value == '')
				{
				obj.getElementsByTagName('fieldset')[0].className = '';
				obj.getElementsByTagName('label')[0].className = 'missing';
				return;
				}
			}

		// Check for valid email addresses
		var regex = /^[a-z0-9_+-.]+@[a-z0-9_-]*\.?[a-z0-9_-]*\.?[a-z0-9_-]*\.[a-z]+$/i;
		if (regex.test(inputs[0].value) == false || regex.test(inputs[2].value) == false)
			{
			obj.getElementsByTagName('fieldset')[0].className = '';
			obj.getElementsByTagName('label')[0].className = 'missing';
			return;
			}

		// Inject the page details
		document.getElementById('formShareEmailUrl').value = document.getElementById('shareURL').getAttribute('content');
		document.getElementById('formShareEmailTitle').value = document.getElementById('shareTitle').getAttribute('content');

		// Send the request
		dojo.xhrPost(
			{
			url: '/ajax/share.php',
			form: 'formShareEmail',
			handleAs: "text",
				load: function(data)
					{
					xhtml.shareEmailSent();
					},
				error: function(error)
					{
					}
				}
			);

		// Update the share box
		obj.getElementsByTagName('fieldset')[0].className = '';
		obj.getElementsByTagName('label')[0].className = 'hidden';
		obj.getElementsByTagName('label')[1].className = 'sending';
		}


	/**
	* Displays the message send message, and closes the share dialog
	*/
	this.shareEmailSent = function()
		{
		// Update the share box message
		document.getElementById('formShareEmail').getElementsByTagName('fieldset')[0].className = '';
		document.getElementById('formShareEmail').getElementsByTagName('label')[0].className = 'hidden';
		document.getElementById('formShareEmail').getElementsByTagName('label')[1].className = 'sending';
		document.getElementById('formShareEmail').getElementsByTagName('label')[1].innerHTML = '<b>Message Sent!</b>';
		document.getElementById('formShareEmail').getElementsByTagName('fieldset')[1].className = 'hidden';

		// Close the share box
		setTimeout("if (!!document.getElementById('share')==true){document.body.removeChild( document.getElementById('share'));}", 1750);
		}


	/**
	* Removes the thanks for voting movie
	*/
	this.thanksVotingHide = function()
		{
		if (!!document.getElementById('thanksVoting') == true)
			{
			try {swfobject.removeSWF('thanksVotingDialogMovie');}catch(err){}
			document.body.removeChild( document.getElementById('thanksVoting') );
			}
		}

	
	/**
	* Displays the thanks for voting movie
	*/
	this.thanksVotingShow = function()
		{
		// Don't display for mobile browsers
		if (navigator.userAgent.toLowerCase().indexOf('mobile') != -1 && navigator.userAgent.toLowerCase().indexOf('safari') != -1)
			{
			return;
			}

		// Check if the main video is playing, if so don't display
		document.getElementById('videoPlayer').checkPlayStatus();
		setTimeout("xhtml.thanksVotingBuild();", 250);
		}


	/**
	* Displays the thanks for voting movie
	*/
	this.thanksVotingBuild = function()
		{
		// Check if the main video is playing, if so don't display
		if (__videoPlaying == true)
			{
			return;
			}

		// Kill any existing dialog
		xhtml.thanksVotingHide();

		// Build the dialog html
		var html = [];
		html.push('<div id="thanksVotingBackground" onclick="xhtml.thanksVotingHide();"></div>');
		html.push('<div id="thanksVotingDialog">');
		html.push('<div id="thanksVotingDialogMovie">');
		html.push('</div>');
		html.push('</div>');

		// Create the dialog
		var thanksVoting = document.createElement('div');
		thanksVoting.id = 'thanksVoting';
		thanksVoting.innerHTML = html.join('\n');
		document.body.appendChild( thanksVoting );

		// Embed the flash player
		__thanksVotingHide = this.thanksVotingHide;
		swfobject.embedSWF('/flash/IKEA_VideoPlayer.swf?playlist=http://www.easytoassembleseries.com/thankyou&videoID=0&completeJavascriptFunction=__thanksVotingHide', 'thanksVotingDialogMovie', '580', '326', '9', 'media/flash/expressinstall.swf', {autoStart: true}, {bgcolor: '#000000', menu: 'false' , allowfullscreen: "true", wmode: "opaque"}, {id: 'thanksVotingDialogMovie'}, null);
		}

	
	/**
	* Displays the about the site overlay
	*/
	this.aboutSiteShow = function()
		{
		if (document.getElementById('aboutSite'))
			{
			document.body.removeChild(document.getElementById('aboutSite'));
			}
		
		var aboutSite = document.createElement('div');
		aboutSite.id = 'aboutSite';
		aboutSite.innerHTML = '<div id="aboutSiteBackground" onclick="document.body.removeChild(document.getElementById(\'aboutSite\'));"></div><div id="aboutSiteDialog"><h3>V&auml;lkommen!</h3><p>We decided to give Hollywood stars a second chance to get a real job here at IKEA Burbank and document it all on video. Illeana Douglas and Justine Bateman are showing some real promise, but I need your help in making up my mind about who will be named "Co-Worker of the Year." <a href="/management">Vote now</a> and your input will decide the outcome of the final episode. Tack s&aring; mycket. Go IKEAns! <br/>- Erik, Store Manager.</p><a class="close" href="javascript:;" onclick="document.body.removeChild(document.getElementById(\'aboutSite\'));">close</a></div>';
		document.body.appendChild( aboutSite );
		}


	/**
	* Hides the vote now box
	*/
	this.closeVoteNowBox = function()
		{
		if (document.getElementById('homeVoteNow'))
			{
			dojo.fadeOut(
					{
					node: 'homeVoteNow',
					onEnd: function()
						{
						// Remove the notice
						dojo.destroy('homeVoteNow');

						// Set a cookie so we know not to redisplay it
						dojo.cookie('homeVoteNow', 'false', {expires: 365});
						}
					}
				).play();
			}
		if (document.getElementById('managementVoteNow'))
			{
			dojo.fadeOut(
					{
					node: 'managementVoteNow',
					onEnd: function()
						{
						// Remove the notice
						dojo.destroy('managementVoteNow');

						// Set a cookie so we know not to redisplay it
						dojo.cookie('homeVoteNow', 'false', {expires: 365});
						}
					}
				).play();
			}
		}


	/**
	* Initializes the scrolling for a region
	*
	* @param		region		The region to add scrolling to
	*/
	this.scrollingRegionInit = function(region)
		{
		// Add global mouse tracking event handlers on first call
		if (__scrollbars.eventHandlersAdded == false)
			{
			if (this.isMobileSafari == false)
				{
				document.body.onmousemove = this._eventHandlerScrollBarGrabberMove;
				document.body.onmouseup = this._eventHandlerScrollBarGrabberUp;
				}
			__scrollbars.eventHandlersAdded = true;
			}

		// Calculate the scrolling region and grabber bar heights
		var scrollingRegionHeight = document.getElementById(region + 'Artboard').parentNode.offsetHeight;
		var grabberBarHeight = document.getElementById(region + 'Grabber').parentNode.offsetHeight;

		// Calculate content size and range
		__scrollbars.contentHeight[region] = parseInt(document.getElementById(region + 'Artboard').offsetHeight);
		__scrollbars.contentRange[region] = (__scrollbars.contentHeight[region] - scrollingRegionHeight) < 0 ? 0 : (__scrollbars.contentHeight[region] - scrollingRegionHeight);

		// Calculate the grabber size and range
		var pages = __scrollbars.contentHeight[region] / scrollingRegionHeight;
		pages = (pages < 1 ? 1 : pages);
		__scrollbars.grabberSize[region] = parseInt(grabberBarHeight / pages);
		__scrollbars.grabberRange[region] = grabberBarHeight - __scrollbars.grabberSize[region];

		// Add event handler to the grabber
		if (__isTrident)
			{
			document.getElementById(region + 'Grabber').onmousedown = this._eventHandlerScrollBarGrabberDown;
			document.getElementById(region + 'Artboard').onmousewheel = this._eventHandlerScrollBarGrabberWheel;
			document.getElementById(region + 'Grabber').onclick = function()
				{
				// Cancel the default event response
				window.event.cancelBubble = true;
				window.event.returnValue = false;
				}
			}
		else
			{
			if (this.isMobileSafari == false)
				{
				document.getElementById(region + 'Grabber').ondragstart  = function() { return false; }
				document.getElementById(region + 'Grabber').onmousedown = function() { return false; }
				document.getElementById(region + 'Grabber').onclick = this._eventHandlerCancelBubbleAndDefault;

				document.getElementById(region + 'Grabber').onmousedown = this._eventHandlerScrollBarGrabberDown;
				document.getElementById(region + 'Artboard').onmousewheel = this._eventHandlerScrollBarGrabberWheel;
				document.getElementById(region + 'Artboard').onDOMMouseScroll = this._eventHandlerScrollBarGrabberWheel;
				}
			}

		// Set the grabber size and position
		document.getElementById(region + 'Grabber').style.top = '0px';
		document.getElementById(region + 'Grabber').style.height = __scrollbars.grabberSize[region] + 'px';
		__scrollbars.previousMouseY = 0;

		// Set the current location
		document.getElementById(region + 'Artboard').style.top = '0px';

		// If there's not enough content to scroll, grey out the scrollbars
		if (__scrollbars.grabberRange[region] == 0)
			{
			document.getElementById(region + 'Grabber').parentNode.parentNode.className += ' scrollbarDisabled';
			}
		else
			{
			document.getElementById(region + 'Grabber').parentNode.parentNode.className = document.getElementById(region + 'Grabber').parentNode.parentNode.className.replace(/\s?scrollbarDisabled/g, '');
			}
		}


	/**
	* Updates the entry/grabber position while the grabber is being dragged
	*
	* @param		mouseY		The mouse position
	*/
	this.scrollingRegionDrag = function(mouseY)
		{
		// Calculate the new grabber position
		var newGrabberPosition = (((mouseY * 1) - (__scrollbars.previousMouseY * 1)) * 1) + (parseInt(__grabber.style.top) * 1);

		// Save the mouse location
		__scrollbars.previousMouseY = mouseY;

		// Range check grabber
		var grabberRange = __scrollbars.grabberRange[__scrollbars.regionBeingDragged];
		if (newGrabberPosition < 0)
			{
			newGrabberPosition = 0;
			}
		if (grabberRange < newGrabberPosition)
			{
			newGrabberPosition = grabberRange;
			}

		// Move the grabber
		__grabber.style.top = newGrabberPosition + 'px';

		// Move the content
		__artboard.style.top = (parseInt((newGrabberPosition / grabberRange) * __scrollbars.contentRange[__scrollbars.regionBeingDragged]) * -1) + 'px';
		}


	/**
	* Scrolls the scrolling region up
	*
	* @param		region		The region to scroll
	*/
	this.scrollingRegionUp = function(region)
		{
		try
			{
			// Calculate the new grabber position
			var newGrabberPosition = (parseInt(document.getElementById(region + 'Grabber').style.top) * 1) - 50;

			// Range check grabber
			if (newGrabberPosition < 0)
				{
				newGrabberPosition = 0;
				}
			if (__scrollbars.grabberRange[region] < newGrabberPosition)
				{
				newGrabberPosition = __scrollbars.grabberRange[region];
				}

			// Move the grabber
			document.getElementById(region + 'Grabber').style.top = newGrabberPosition + 'px';

			// Move the content
			document.getElementById(region + 'Artboard').style.top = (parseInt((newGrabberPosition / __scrollbars.grabberRange[region]) * __scrollbars.contentRange[region]) * -1) + 'px';
			}
		catch(e)
			{
			}
		}


	/**
	* Scrolls the scrolling region down
	*
	* @param		region		The region to scroll
	*/
	this.scrollingRegionDown = function(region)
		{
		try
			{
			// Calculate the new grabber position
			var newGrabberPosition = (parseInt(document.getElementById(region + 'Grabber').style.top) * 1) + 50;

			// Range check grabber
			if (newGrabberPosition < 0)
				{
				newGrabberPosition = 0;
				}
			if (__scrollbars.grabberRange[region] < newGrabberPosition)
				{
				newGrabberPosition = __scrollbars.grabberRange[region];
				}

			// Move the grabber
			document.getElementById(region + 'Grabber').style.top = newGrabberPosition + 'px';

			// Move the content
			document.getElementById(region + 'Artboard').style.top = (parseInt((newGrabberPosition / __scrollbars.grabberRange[region]) * __scrollbars.contentRange[region]) * -1) + 'px';
			}
		catch(e)
			{
			}
		}


	/**
	* Starts the drag of the grabber
	*
	* @param		event		The browser event object
	*/
	this._eventHandlerScrollBarGrabberDown = function(event)
		{
		// Build the function based on rendering engine
		if (__isTrident)
			{
			return function()
				{
				var event = window.event;

				if (__scrollbars.locked == true || __scrollbars.regionBeingDragged != '')
					{
					return;
					}

				// Get the mouse location and save region being dragged
				__scrollbars.previousMouseY = event.clientY;
				__scrollbars.startMouseY = event.clientY;
				__scrollbars.regionBeingDragged = this.id.replace('Grabber', '');

				// Disable text selection
				document.body.onselectstart = function() { return false; };

				// Save references for the current scrolling region
				__artboard = document.getElementById(__scrollbars.regionBeingDragged + 'Artboard');
				__grabber = document.getElementById(__scrollbars.regionBeingDragged + 'Grabber');
				}
			}
		else
			{
			// 2. Gecko, Webkit & Presto
			return function(event)
				{
				if (__scrollbars.locked == true || __scrollbars.regionBeingDragged != '')
					{
					return;
					}

				// Get the mouse location and save region being dragged
				__scrollbars.previousMouseY = event.pageY;
				__scrollbars.startMouseY = event.pageY;
				__scrollbars.regionBeingDragged = this.id.replace('Grabber', '');

				// Save references for the current scrolling region
				__artboard = document.getElementById(__scrollbars.regionBeingDragged + 'Artboard');
				__grabber = document.getElementById(__scrollbars.regionBeingDragged + 'Grabber');

				// Cancel the dragging in firefox 3
				return false;
				}
			}
		}();



	/**
	* Processes the drag of the grabber
	*
	* @param		event		The browser event object
	*/
	this._eventHandlerScrollBarGrabberMove = function(event)
		{
		// Build the function based on rendering engine
		if (__isTrident)
			{
			return function()
				{
				// Check if we're dragging a grabber, if so move the it
				if (__scrollbars.regionBeingDragged != '' && __scrollbars.grabberRange[__scrollbars.regionBeingDragged])
					{
					xhtml.scrollingRegionDrag(window.event.clientY);
					return;
					}
				}
			}
		else
			{
			// 2. Gecko, Webkit & Presto
			return function(event)
				{
				// Check if we're dragging a grabber, if so move the it
				if (__scrollbars.regionBeingDragged != '' && __scrollbars.grabberRange[__scrollbars.regionBeingDragged])
					{
					xhtml.scrollingRegionDrag(event.pageY);
					return;
					}
				}
			}
		}();


	/**
	* Processes the scroll of the mouse wheel
	*
	* @param		event		The browser event object
	*/
	this._eventHandlerScrollBarGrabberWheel = function(event)
		{
		// Get the event object if necessary
		!!event ? event : window.event

		var delta = 0;

		// Find the delta
		if (event.wheelDelta)
			{
			delta = event.wheelDelta/120;
			if (window.opera)
				{
				delta *= -1;
				}
			}
		else if (event.detail)
			{
			delta = -event.detail/3;
			}

		// Scroll the region
		if (delta != 0)
			{
			if (delta < 0)
				{
				xhtml.scrollingRegionDown(this.id.replace('Artboard', ''));
				}
			else
				{
				xhtml.scrollingRegionUp(this.id.replace('Artboard', ''));
				}
			}

		// Cancel the default event response
		xhtml._eventHandlerCancelBubbleAndDefault(event);
		}


	/**
	* End the drag of the grabber
	*/
	this._eventHandlerScrollBarGrabberUp = function()
		{
		// Build the function based on rendering engine
		if (__isTrident)
			{
			return function(event)
				{
				if (__scrollbars.regionBeingDragged == '')
					{
					return;
					}

				// Set the artboard as not being dragged
				__scrollbars.regionBeingDragged = '';

				// Clear references for the current scrolling region
				__artboard = null;
				__grabber = null;

				// Enable text selection
				document.body.onselectstart = null;

				// Cancel the default event response
				window.event.cancelBubble = true;
				window.event.returnValue = false;
				}
			}
		else
			{
			// 2. Gecko, Webkit & Presto
			return function(event)
				{
				if (__scrollbars.regionBeingDragged == '')
					{
					return;
					}

				// Set the artboard as not being dragged
				__scrollbars.regionBeingDragged = '';

				// Clear references for the current scrolling region
				__artboard = null;
				__grabber = null;

				// Cancel the default event response
				event.stopPropagation();
				event.preventDefault();
				}
			}
		}();


	/**
	* Cancels the propagation of the event up the dom tree and the default event action
	*
	* @param		event		The browser event object
	*/
	this._eventHandlerCancelBubbleAndDefault = function(event)
		{
		if(__isTrident)
			{
			// Cancel the default event response
			window.event.cancelBubble = true;
			window.event.returnValue = false;
			}
		else
			{
			// Cancel the default event response
			event.stopPropagation();
			event.preventDefault();
			}
		}
	}



/**
* Flash Callback: Updates thes video playing variable
*
* @param		playStatus		Boolean whether the main video is playing
*/
function recievePlayStatus(playStatus)
	{
	__videoPlaying = playStatus ? true : false;
	}



/**
* Inherts a prototype from the specified class, updates the constructor reference
*
* @param		parent		The parent class or object
* @return		The inherted object
*/
Function.prototype.inheritsFrom = function( baseClass )
	{
	// Inherit the base class
	this.prototype = new baseClass;
	this.prototype.constructor = this;

	// Add access to the base's methods
	this.prototype.base = {};
	for (method in this.prototype)
		{
		// hasOwnProperty test is a workaround for "for..in" bug, see: http://yuiblog.com/blog/2006/09/26/for-in-intrigue/
		if (typeof this.prototype[method] === 'function' && this.prototype.hasOwnProperty(method) && this.prototype[method] !== this.prototype.constructor)
			{
			this.prototype.base[method] = this.prototype[method];
			}
		}
	return this;
	}