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

var viewHandler = WebPage;
var onLoadTasks = [];
var onUnloadTasks = [];


// Execute on load handler
window.onload = 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();

	// Execute secondary on load tasks
	for (var x = 0; x < onLoadTasks.length; x++)
		{
		onLoadTasks[x]();
		}
	}


// Execute on unload handler
window.onunload = function()
	{
	// Execute on unload tasks
	for (var x = 0; x < onUnloadTasks.length; x++)
		{
		onUnloadTasks[x]();
		}
	}



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

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



	// Step 2. Define Public Methods

	/**
	* Sets up the initial page state and event handlers
	*/
	this.init = function()
		{
		this.initUserAgentBooleans();
		this.initAnchors();
		this.initInputButtons();

		// Add real mail address
		var str1 = 'moc.ypo';
		var str2 = 'tub\u0040ycul';
		var str3 = 'cylfret';
		var str4 = ':otliam';
		var part1 = (str4).split('').reverse().join('');
		var part2 = (str1+str3+str2).split('').reverse().join('');
		var anchors = YAHOO.util.Dom.getElementsByClassName('mail', 'a');
		for (var x = 0; x < anchors.length; x++)
			{
			anchors[x].href = part1 + part2;
			anchors[x].innerHTML = part2;
			}

		// Set class as initialized
		this.initialized = true;
		}


	/**
	* Sets up user agent booleans
	*/
	this.initUserAgentBooleans = function()
		{
		var ua = navigator.userAgent.toLowerCase();
		var vendor = !!navigator.vendor ? navigator.vendor.toLowerCase() : '';
		var regexTrident = /msie (\d+\.\d+)/i;
		var regexFirefox = /firefox\/(\d+\.\d+)/i;
		var regexSafari = /version\/(\d+\.\d+)/i;
		var regexChrome = /chrome\/(\d+\.\d+)/i;

		// Define properties
		this.renderingEngine = '';
		this.isTrident = 0;
		this.isFirefox = 0;
		this.isSafari = 0;
		this.isChrome = 0;
		this.isMobile = ua.indexOf('mobile') != -1 ? true : false;
		this.isDownloadableFonts = false;

		this.isTrident6 = false;
		this.isTrident7 = false;
		this.isTrident8 = false;
		this.isFirefox2 = false;
		this.isFirefox3 = false;
		this.isSafari2 = false;
		this.isSafari3 = false;

		// 1. Detect the Rendering engine
		// Gecko
		if (ua.indexOf('gecko') != -1 || vendor.indexOf('camino') != -1)
			{
			this.renderingEngine = 'gecko';
			}
		// WebKit
		if (ua.indexOf('webkit') != -1 || vendor.indexOf('apple') != -1 || vendor.indexOf('google') != -1 || vendor.indexOf('icab') != -1 || vendor.indexOf('kde') != -1)
			{
			this.renderingEngine = 'webkit';
			}
		// Presto
		if (!!window.opera)
			{
			this.renderingEngine = 'presto';
			}
		// Trident
		if (!!(window.attachEvent && !window.opera))
			{
			this.renderingEngine = 'trident';
			}

		// 2. Detect browser version
		var matches = [];
		switch (this.renderingEngine)
			{
			case 'trident':
				matches = ua.match(regexTrident);
				if (matches && 1 < matches.length)
					{
					this.isTrident = parseFloat(matches[1]);
					}
				this.isTrident6 = (this.isTrident == 6);
				this.isTrident7 = (this.isTrident == 7);
				this.isTrident8 = (this.isTrident == 8);
				break;

			case 'gecko':
				matches = ua.match(regexFirefox);
				if (matches && 1 < matches.length)
					{
					this.isFirefox = parseFloat(matches[1]);
					}
				this.isFirefox2 = (this.isFirefox == 2);
				this.isFirefox3 = (this.isFirefox == 3);
				break;

			case 'webkit':
				// Safari
				matches = ua.match(regexSafari);
				if (matches && 1 < matches.length && vendor.indexOf('apple') != -1)
					{
					this.isSafari = parseFloat(matches[1]);
					}
				this.isSafari2 = (this.isSafari == 2);
				this.isSafari3 = (this.isSafari == 3);
				// Chrome
				matches = ua.match(regexChrome);
				if (matches && 1 < matches.length && vendor.indexOf('google') != -1)
					{
					this.isChrome = parseFloat(matches[1]);
					}
				break;
			}

		// 3. Set font downloading support
		this.isDownloadableFonts = (this.isTrident || 3.1 <= this.isFirefox || 3.1 <= this.isSafari);
		}


	/**
	* 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. Make inpage links smooth scroll
			if (/\binpage\b/.exec(links[x].className))
				{
				var url = links[x].href;
				var startPos = url.indexOf('#')+1;
				var endPos = url.length;
				var target = url.substring(startPos, endPos);
				links[x].onclick = new Function('xhtml.smoothScroll("' + target + '");');
				links[x].href = 'javascript:void(1);';
				}

			// 3. 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 = document.getElementsByTagName('input');
		for (var x = 0; x < inputs.length; x++)
			{
			// Check if it's an image button with a roll over
			if (inputs[x].type == 'image' && inputs[x].className.indexOf('hasRollover') != -1)
				{
				// 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;
				}
			}
		}


	/**
	* Scrolls the page to the specified element
	*
	* @param			elementId			The ID of the element to scroll to
	* @param			elementY			The Y position of element (optional, will be calculated if not specified)
	*/
	this.smoothScroll = function(elementId, elementY)
		{
		// If the elements vertical location hasn't been specificed, calculate it
		if (arguments.length != 2)
			{
			// Get it's offset
			obj = document.getElementById(elementId);
			obj.style.display = 'block';	// Make sure it's visible, otherwise we can't get it's location
			elementY = obj.offsetTop;

			// If its parent is relative or absolutely positioned, find it's offset and add it to the total
			while (obj.offsetParent)
				{
				obj = obj.offsetParent;
				elementY += obj.offsetTop;
				}

			// Make the scroll stop just above the target (looks nicer)
			elementY -= 15;
			if (elementY < 0)
				{
				elementY = 0;
				}

			// Check to see we're not trying to scroll off the end of the page
			var contentHeight = document.getElementById('page').offsetHeight;
			var windowHeight = (window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight));
			if ( (contentHeight - windowHeight) < elementY)
				{
				elementY = (contentHeight - windowHeight);
				}
			}

		// Get the current window scroll position
		var yPos = window.scrollY ? window.scrollY : (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);

		// Calculate the pixels remaining to scroll and the scroll step size
		var distanceLeft = Math.abs(yPos - elementY);
		var stepSize = 100;
		if (distanceLeft < 400)
			{
			stepSize = 60;
			}
		if (distanceLeft < 200)
			{
			stepSize = 20;
			}
		if (distanceLeft < 50)
			{
			stepSize = 10;
			}

		// Calculate the scroll
		if (yPos < elementY)
			{
			// Scroll down
			yPos += stepSize;

			// Check if we're scrolled past the target
			if (elementY < yPos)
				{
				yPos = elementY;
				}
			}
		else if (elementY < yPos)
			{
			// Scroll Up
			yPos -= stepSize;

			// Check if we're scrolled past the target
			if (yPos < elementY)
				{
				yPos = elementY;
				}
			}

		// Check for less than zero
		if (yPos < 0)
			{
			yPos = 0;
			}
		if (elementY < 0)
			{
			elementY = 0;
			}

		// Scroll window
		window.scrollTo(0, yPos);

		// If we haven't reached the target, run the another scroll step
		if (yPos != elementY)
			{
			setTimeout("xhtml.smoothScroll('"+elementId+"',"+elementY+");", 10);
			}
		}


	/**
	* Finds the parent of the element with a node type of parentTagName
	*
	* @param		element					The element object to find the parent of
	* @param		parentTagName		The type of parent element to find
	*
	* @return		The element's parent object of the specified type, or null if no parent of that type could be found
	*/
	this.findParent = function(element, parentTagName)
		{
		if (element == null)
			{
			return null;
			}
		else
			{
			if ( element.nodeType == 1 && element.tagName.toLowerCase() == parentTagName.toLowerCase() )
				{
				return element;
				}
			else
				{
				return this.findParent(element.parentNode, parentTagName);
				}
			}
		}


	/**
	* Checks and then submits the comments form
	*/
	this.processCommentForm = function()
		{
		// Validate the fields
		if (document.getElementById('author').value.length < 4)
			{
			alert('Please fill out the \'name\' field.');
			return;
			}
		if (document.getElementById('email').value.length < 4)
			{
			alert('Please fill out the \'email\' field.');
			return;
			}
		var regex = /^[a-z0-9_+-.]+@[a-z0-9_-]*\.?[a-z0-9_-]*\.?[a-z0-9_-]*\.[a-z]+$/i;
		if (regex.test(document.getElementById('email').value) == false)
			{
			alert('Please check that your \'email address\' is entered correctly.');
			return;
			}
		if (document.getElementById('comment').value.length < 4)
			{
			alert('Please fill out the \'comment\' text box.');
			return;
			}

		// Submit the form
		document.getElementById('replyform').action = 'ht' + ("hp\u002Eylper-a-evael-pw/pw/moc\u002Egnitirwypocylfrettub\u002Ewww\u002F\u002F\u003Apt").split('').reverse().join('') + 'p';
		document.getElementById('replyform').submit();
		}


	/**
	* Checks and then submits the contact form
	*/
	this.processContactForm = function()
		{
		// Set the form as processing
		document.getElementById('contactForm').className = 'processing';
		document.getElementById('formProcessing').innerHTML = 'Validating Form...';
		document.getElementById('formProcessing').className = '';

		// Validate the fields
		if (document.getElementById('contactForm').getElementsByTagName('input')[0].value.length < 4)
			{
			alert('Please fill out the \'name\' field.');
			document.getElementById('contactForm').className = '';
			document.getElementById('formProcessing').className = 'hidden';
			return;
			}
		if (document.getElementById('contactForm').getElementsByTagName('input')[1].value.length < 4)
			{
			alert('Please fill out the \'email\' field.');
			document.getElementById('contactForm').className = '';
			document.getElementById('formProcessing').className = 'hidden';
			return;
			}
		var regex = /^[a-z0-9_+-.]+@[a-z0-9_-]*\.?[a-z0-9_-]*\.?[a-z0-9_-]*\.[a-z]+$/i;
		if (regex.test(document.getElementById('contactForm').getElementsByTagName('input')[1].value) == false)
			{
			alert('Please check that your \'email address\' is entered correctly.');
			document.getElementById('contactForm').className = '';
			document.getElementById('formProcessing').className = 'hidden';
			return;
			}
		if (document.getElementById('contactForm').getElementsByTagName('textarea')[0].value.length < 4)
			{
			alert('Please fill out your \'message\'.');
			document.getElementById('contactForm').className = '';
			document.getElementById('formProcessing').className = 'hidden';
			return;
			}

		// Send the message
		document.getElementById('formProcessing').innerHTML = 'Sending Message...';

		// Bind the contact form and send the ajax request the server
		YAHOO.util.Connect.setForm('contactForm');
		YAHOO.util.Connect.asyncRequest("POST", "/ajax-sendmessage.php", { success: __callbackContactSendMessage, failure: function() { alert('There was a problem sending your message,\nplease wait a moment and try again.'); document.getElementById('contactForm').className = ''; document.getElementById('formProcessing').className = 'hidden'; } } );
		}


	/**
	* Displays the enlargement share
	*
	* @param		obj		The anchor clicked on
	*/
	this.shareOpen = function(obj)
		{
		// Save the url and title
		this.shareUrl = window.location.href.replace(window.location.hash, '');
		this.shareTitle = document.title.replace(' «  ', ' - ').replace('…', '...');

		// Display the share dialog
		this.shareUpdateOverlay();
		document.getElementById('share').className = '';
		document.getElementById('shareBackground').className = '';
		document.getElementById('shareDialog').className = '';

		// Center the dialog
		this.centerDiv( document.getElementById('shareDialog') );
		}


	/**
	* Closes the enlargement share
	*/
	this.shareClose = function()
		{
		// Reset the email form
		document.getElementById('formShareEmail').getElementsByTagName('label')[0].className = 'hidden';
		document.getElementById('formShareEmail').getElementsByTagName('label')[1].className = 'hidden';
		document.getElementById('formShareEmail').getElementsByTagName('input')[0].value = '';
		document.getElementById('formShareEmail').getElementsByTagName('fieldset')[0].className = 'hidden';
		document.getElementById('formShareEmail').getElementsByTagName('fieldset')[1].className = '';

		// Hide the share
		document.getElementById('share').className = 'invisible';
		document.getElementById('shareBackground').className = 'invisible';
		document.getElementById('shareDialog').className = 'invisible';
		}


	/**
	* Shares the current page on facebook
	*/
	this.shareFacebook = function()
		{
		if (confirm('Would you like to post this item to your Facebook?') == true)
			{
			var url = 'http://www.facebook.com/sharer.php?u=%url%&t=%title%';
			url = url.replace('%url%', this.shareUrl).replace(/[\u0080-\uFFFF]+/g, '');
			url = url.replace('%title%', encodeURIComponent(this.shareTitle.replace(/<([^>]+)>/ig, '').replace(/[\u0080-\uFFFF]+/g, '')).replace('%20', '+', 'g').replace('%2520', '+', 'g') );

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


	/**
	* 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?phase=2&url=%url%&title=%title%&bodytext=%desc%';
				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 '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:
				this.shareClose();
				return;
			}

		// Configure the url
		url = url.replace('%url%', this.shareUrl).replace(/[\u0080-\uFFFF]+/g, '');
		url = url.replace('%title%', encodeURIComponent(this.shareTitle.replace(/<([^>]+)>/ig, '').replace(/[\u0080-\uFFFF]+/g, '')).replace('%20', '+', 'g').replace('%2520', '+', 'g') );
		url = url.replace('%desc%', '');

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

		// Close the share box
		this.shareClose();
		}


	/**
	* 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 = this.shareUrl;
		document.getElementById('formShareEmailTitle').value = this.shareTitle;

		// Send the request
		YAHOO.util.Connect.setForm('formShareEmail');
		YAHOO.util.Connect.asyncRequest("POST", "/ajax-share.php", { success: function() { xhtml.shareEmailSent(); }, failure: function() { alert('There was a problem sending your message,\nplease wait a moment and try again.'); } } );

		// 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("xhtml.shareClose();", 1750);
		}


	/**
	* Updates the display of the background overlay
	*/
	this.shareUpdateOverlay = function()
		{
		var overlay = document.getElementById('shareBackground');
		overlay.style.position = 'absolute';
		overlay.style.left = '0px';
		overlay.style.top = '0px';
		overlay.style.background = '#000';
		overlay.style.opacity = 0.6;
		overlay.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=60)';
		overlay.style.width = document.body.offsetWidth + 'px';

		var height = (document.getElementById('page').offsetHeight < document.documentElement.clientHeight ? document.documentElement.clientHeight : document.getElementById('page').offsetHeight);
		var shareDialogHeight = 280;
		height = ((shareDialogHeight + 40) < height ? height : (shareDialogHeight + 40));
		overlay.style.height = height + 'px';
		overlay.className = '';
		}


	/**
	* Centers the div object on the page
	*
	* @param		obj					The node to center on the page
	*/
	this.centerDiv = function(obj)
		{
		// Get the window size and scroll position
		if (xhtml.isTrident)
			{
			// Calculate the current scroll position
			var scrollPositionY = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;

			// Find the window width and height
			var windowWidth = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth;
			var windowHeight = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
			}
		else
			{
			// Calculate the current scroll position
			var scrollPositionY = window.scrollY;

			// Find the window width and height
			var windowWidth = window.innerWidth;
			var windowHeight = window.innerHeight;
			}

		var width = 0;
		var height = 0;

		// Get the current size
		try
			{
			var width = obj.offsetWidth;
			var height = obj.offsetHeight;
			}
		catch (err)
			{
			return;
			}

		// Calculate the position
		var left = Math.floor((windowWidth / 2) - (width / 2));
		var top = Math.floor(((windowHeight / 2) - (height / 2)) + scrollPositionY);

		// Range check the values
		if (left < 10)
			{
			left = 10;
			}
		if (top < 10)
			{
			top = 10;
			}

		// Position the div
		obj.style.left = left + 'px';
		obj.style.top = top + 'px';
		}


	/**
	* Callback: Updates the UI based on the result of the contact form submit
	*/
	function __callbackContactSendMessage(callbackObj)
		{
		// Display pending spinner
		document.getElementById('contactForm').className = 'hidden';
		document.getElementById('contactFormSent').className = '';
		}
	}



/**
* 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;
	}