/**ws.js
 *
 * Watershed Common Functions
 * Copyright © 2010
 * Tom Giordano
 * Watershed Company
 * www.watershedcompany.com
 * 
 * Supported On:
 * IE 6+ (both Quirks and Standard Mode), Firefox 1.5+, Safari 2+, Opera 9+
 * Support Notes:
 * ws.Dialog: No rounded corners on Safari 2, Opera 9 - 10.10
 * ws.Fx.Flip: No animation on Firefox 1.5 - 3.0, Safari 2 - 3.0, Opera 9 - 10.10
 *
 */

var ws = {
	Version: 1.20100624
};

ws.Browser = {
	isIE: document.all && !window.opera,
	isCSS3IE: document.all && !window.opera && /Trident/i.test(navigator.userAgent) && !/Trident\/4\./i.test(navigator.userAgent),
	isOldIE: document.all && !window.opera && /MSIE [56]/.test(navigator.userAgent) && !/Trident/i.test(navigator.userAgent),
	isMobileSafari: /AppleWebKit\/.+Mobile\//.test(navigator.userAgent),
	isIPhone: /(iPhone|iPod)/.test(navigator.userAgent),
	isSafariWithTransitions: /WebKit\/\d+/i.test(navigator.userAgent) && (parseInt(navigator.userAgent.match(/WebKit\/(\d+)/i)[1]) >= 531) && !/OS\sX\s10_[45]/i.test(navigator.userAgent),
	isChrome: /Chrome\//.test(navigator.userAgent),
	isOldFirefox: /Firefox[\/\s][12]\./.test(navigator.userAgent),
	isLegacyMode: !/CSS/i.test(document.compatMode)
};

ws.Test = {
	/*
	 * Test for empty input. This is the only testing function that auto-trims input.
	 */
	IsEmpty: function(str)
	{
		if (str.replace(/\s*/g, "").length == 0)
			return true;
		return false;
	},
	/*
	 * Tests for a valid 5-digit U.S. zip code
	 */
	ValidUSZip: function(str)
	{
		return (/^\d{5}$/.test(str));
	},
	/*
	 * Test for a valid email
	 */
	ValidEmail: function(str)
	{
		return (/^([\w|\-]+)(\.[\w|\-]+)*@([\w|\-]+)(\.[\w|\-]+)+$/.test(str));
	},
	/*
	 * Test for a valid U.S. phone number
	 */
	ValidPhone: function(str, cellNumber)
	{
		var str = str.replace(/[\(\)\.\-\ ]/g, "");  //strip out acceptable non-numeric characters
		
		if (!/^\d{10,11}$/.test(str))  // Must contain only 10 or 11 digits
			return false;
		
		if (/^1\d{10}/.test(str))  // If they used a starting 1, strip it
			str = str.substring(1, 11);
		
		// No phone numbers starting with 0 or 1, having 11 as the second and third digits, having 555 as the first 3 digits or 555 as the 3rd through 6th digits
		if (/^([01]|\d11|555|\d{3}555)/.test(str))
			return false;
		
		if (cellNumber && /^(8(00|88|77|66)|9(00|76)|\d{3}976)/.test(str)) // No business or toll numbers: 800, 888, 877, 866, 900, 976, or ###-976
			return false;
		
		return true;
	},
	/*
	 * Test for a valid numeric input
	 */
	ValidNumber: function(str, floatingPoint)
	{
		if (floatingPoint)
			return /^[\d]+\.?[\d]+$/.test(str);
		return /^\d+$/.test(str);
	}
};

ws.Alter = {
	/*
	 * Trims string and removes (or replaces) HTML characters (<, >, &) 
	 * Replacements should be an array with replacements for <, >, & in that order.
	 * Ex: ws.Alter.Clean(someStr, ["&gt;", "&lt;", "&amp;"]));
	 */
	Clean: function(str, replacements)
	{
		// Clean and replace HTML entities
		str = str.replace(/(<+|>+|&+)/g, function($1)
		{
			if (replacements)
			{
				if ($1 == "<")
					return replacements[0];
				else if ($1 == ">")
					return replacements[1];
				return replacements[2];
			}
			return "";
		});
		
		return str.replace(/^\s+|\s+$/g, "");  // Trim
	},
	FilterWhitespace: function(str)
	{
		return str.replace(/\s+/g, "");
	},
	FilterExpletives: function(str)
	{
		// n, f, s, c, t, cs
		var filter = new RegExp(unescape("([%4E%6E][%49%69][%47%67]{2}[%45%65][%52%72]|[%46%66][55%75%][43%63%4B%6B%]{2}|[%53%73][%48%68][%49%69][%54%74]|[%43%63][%55%75][%4E%6E][%54%74]|[%54%74][%49%69][%54%74][%53%73]|[%43%63][%4F%6F][%43%63%4B%6B]{1,2}[%53%73][%55%75][%43%63%4B%6B]{1,2}[%45%65][%52%72])"), "g");
		return str.replace(filter, "");
	},
	Limit: function(str, length)
	{
		var regex = new RegExp("(.{0," + length + "})");
		return (str.match(regex)[1]);
	},
	//MakeNumeric: function()
	//{
	//	
	//},
	/*
	 * Add commas to a number
	 * Credits to Steven Levithan (http://blog.stevenlevithan.com/archives/commafy-numbers)
	 */
	Commafy: function()
	{
		return this.replace(/(^|[^\w.])(\d{4,})/g, function($0, $1, $2)
		{
			return $1 + $2.replace(/\d(?=(?:\d\d\d)+(?!\d))/g, "$&,");
		});
	},
	/*
	 * Prevents particular keys from having effect
	 * Usage: elm.onkeypress = function(e) { return ws.Alter.PreventInput(e, Array(13)); };
	 */
	//PreventInput: function(e, keysToPreventArray)
	//{
	//	var key = (window.event) ? event.keyCode : e.keyCode;
	//	alert(e.keyCode);
	//	for (var i = 0; i < keysToPreventArray.length; i++)
	//		if (key == keysToPreventArray[i])
	//			return false;		
	//},
	/*
	 * Limits input to a particular length
	 */
	//LimitInput: function(event, elm, length)
	//{
    //
	//},
	/*
	 * Changes the CSS for an element on the page
	 */
	ChangeCSS: function(sheetTitle, ruleSelectorTextFragment, newStyle, newStyleValue)
	{
		var styleRules = new Array();
		var checkRule;

		for (var i = 0; i < document.styleSheets.length; i ++)
		{
			// Search for stylesheet with this "title" attribute:
			if (document.styleSheets[i].title == sheetTitle)
			{
				if (document.styleSheets[i].cssRules)
					styleRules = document.styleSheets[i].cssRules;
				else
					styleRules = document.styleSheets[i].rules;
			}
		}

		for (var i = 0; i < styleRules.length; i++)
		{
			if (styleRules[i].cssText)
				checkRule = styleRules[i].cssText;
			else
				checkRule = styleRules[i].selectorText;

			// Note that in IE, elements if used as part of a selector are uppercase, eg: SPAN.clickable
			if (checkRule.toLowerCase().indexOf(ruleSelectorTextFragment.toLowerCase()) != -1)
				styleRules[i].style[newStyle] = newStyleValue;
		}
	}
};

/*
 * Dialog initialization
 */
ws.Dialog = function()
{
	if (ws.Dialog.initialized)
		return;
	
	if (ws.Browser.isIE && !ws.Browser.isCSS3IE)
	{
		if (!document.namespaces.v)
			document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
		
		var vmlCSS = document.createStyleSheet();
		vmlCSS.addRule("v\\:roundrect", "behavior: url(#default#VML)");
		vmlCSS.addRule("v\\:roundrect", "background-color: transparent !important");
		vmlCSS.addRule("v\\:roundrect", "border: none !important");
	}
	ws.Dialog.initialized = true;
};

ws.Dialog.prototype = {
	defaultBackgroundColor: "#003049",
	/*
	 * Creates and populates a in-DOM popup dialog
	 */
	Show: function(msgTitle, msgInfo, msgButton, widthOfPopup, heightOfPopup)
	{
		this.widthOfPopup = widthOfPopup;
		this.heightOfPopup = heightOfPopup;
		
		// Setup inner content
		this.contentDiv = document.createElement("div");
		this.contentDiv.className = "ws_dialog_content";
		this.contentDiv.style.position = "relative";
		this.contentDiv.style.width = this.widthOfPopup + "px";
		this.contentDiv.style.height = this.heightOfPopup + "px";
		this.contentDiv.style.marginLeft = "auto";
		this.contentDiv.style.marginRight = "auto";
		
		var contentElm;
		if (ws.Browser.isIE && !ws.Browser.isCSS3IE)
		{
			// An added benefit to using VML is that the text won't look weird in fade-ins and outs on IE6!
			contentElm = document.createElement("v:roundrect");
			contentElm.arcsize = ".03";
			contentElm.fillcolor = "#464646";
			contentElm.strokecolor = "#ffffff";
			contentElm.strokeweight = "2px";
		}
		else
		{
			contentElm = document.createElement("div");
		}
		
		contentElm.style.width = this.widthOfPopup + "px";
		contentElm.style.height = this.heightOfPopup + "px";
		contentElm.style.fontFamily = "arial, helvetica, sans-serif";
		contentElm.style.fontSize = "14px";
		contentElm.style.display = "block";
		contentElm.style.width = this.widthOfPopup + "px";
		contentElm.style.height = this.heightOfPopup + "px";
		contentElm.style.backgroundColor = "#464646";
		contentElm.style.border = "2px solid #ffffff";
		contentElm.style.MozBorderRadius = "10px";
		contentElm.style.webkitBorderRadius = "10px";
		contentElm.style.borderRadius = "10px";
		contentElm.innerHTML = '<div style="padding: 30px 30px 20px 30px; text-align: left; color: #ffffff;"><span style="display: block; position: absolute;' + ((ws.Browser.isOldIE && !ws.Browser.isLegacyMode) ? ' ' : 'left: 0px; right: 0px; ') + 'bottom: 30px; width: 100%; cursor: pointer; text-decoration: underline; font-size: 115%; text-align: center;" class="ws_dialog_close_button">' + msgButton + '</span><strong style="display: block; text-align: center;">' + msgTitle + '</strong>' + msgInfo + '</div>';
		
		this.contentDiv.appendChild(contentElm);
		
		// Setup the close handler (note that the close button is in our first span, since message content and title follow it.)
		// Note that we have to store "this" so that we don't lose reference to it (so the hide function knows what to call)
		var thisDialog = this;
		this.contentDiv.getElementsByTagName("span")[0].onclick = function()
		{
			// If we wanted to add another function to be called, let's say it's in the 
			// parameter for the Show() function named fnOnCloseAlsoDo, we could call
			// it here like so:
			// fnOnCloseAlsoDo();
			thisDialog.Hide();
		};
		
		this._build();
	},
	/*
	 * Creates and populates a in-DOM popup dialog, styled with user HTML
	 * Pass an HTML color as a string as the 5th parameter to change the default background color
	 */
	ShowHTML: function(html, widthOfPopup, heightOfPopup, onCloseFn)
	{
		this.widthOfPopup = widthOfPopup;
		this.heightOfPopup = heightOfPopup;
		
		var backgroundColor = this.defaultBackgroundColor;
		if (arguments.length == 5)
			backgroundColor = arguments[4];
		
		// Setup inner content
		this.contentDiv = document.createElement("div");
		this.contentDiv.className = "ws_dialog_content ws_dialog_custom_content";
		this.contentDiv.style.position = "relative";
		this.contentDiv.innerHTML = html;
		this.contentDiv.style.width = this.widthOfPopup + "px";
		this.contentDiv.style.height = this.heightOfPopup + "px";
		this.contentDiv.style.marginLeft = "auto";
		this.contentDiv.style.marginRight = "auto";
		
		var thisDialog = this;
		var contentDivSpans = this.contentDiv.getElementsByTagName("span");
		for (var i = 0; i < contentDivSpans.length; i++)
		{
			if (/ws_dialog_close_button/.test(contentDivSpans[i].className))
			{
				contentDivSpans[i].onclick = function()
				{
					onCloseFn(this);  // Call on close function provided by user
					thisDialog.Hide();
					return false; // Cancel the event
				};
			}
		}
		
		this._build(backgroundColor);
	},
	/*
	 * Begins removal of an in-DOM popup dialog
	 */
	Hide: function()
	{
		 // Prevent hide function from being called twice (i.e. user double-clicks background)
		if (this.hideCalled)
			return;
		
		this.hideCalled = true;
		
		window.onresize = this._previousOnResize;
		
		// See if Fx library is loaded		
		if (typeof(Fx) == "object")
		{
			this.backgroundDiv.mooFx = new Fx.Style(this.backgroundDiv, 'opacity', {duration: 300});
			this.backgroundDiv.mooFx._start(0.5, 0.01);
			
			var thisDialog = this;
			this.popupDiv.mooFx = new Fx.Style(this.popupDiv, 'opacity', {duration: 300, onComplete: function()
			{
				// We would lose reference to the dialog during callback functions too, so store "this" in thisDialog
				thisDialog._hideComplete();
			}});
			this.popupDiv.mooFx._start(1.0, 0.01);
		}
		else
		{
			this._hideComplete();
		}
	},
	/*
	 * Removes an in-DOM popup dialog
	 */
	_hideComplete: function()
	{
		this.backgroundDiv.parentNode.removeChild(this.backgroundDiv);
		this.popupDiv.parentNode.removeChild(this.popupDiv);
		if (ws.Browser.isOldIE && this.hiddenSelects)
		{
			for (var i = 0; i < this.hiddenSelects.length; i++)
				this.hiddenSelects[i].style.visibility = "visible";
		}
		if (ws.Browser.isLegacyMode && ws.Browser.isIE)
		{
			document.body.scroll = "yes"; // Re-enable scrolling in IE
			document.body.style.marginRight = (parseInt(document.body.currentStyle.marginRight) - this.scrollBarSize) + "px";
		}
	},
	/*
	 * Sizes or resizes the dialog to the browser window
	 */
	_sizeDialog: function()
	{
		var marginOffset = 0;
		
		if (ws.Browser.isMobileSafari)
		{
			this.backgroundDiv.style.width = document.body.clientWidth + "px";
			this.backgroundDiv.style.height = Math.max(document.body.clientHeight, window.innerHeight) + window.pageYOffset + "px";
			// We have to factor in scroll offset on Mobile Safari since there is no CSS fixed positioning
			marginOffset = ((window.innerHeight - this.heightOfPopup) / 2) + window.pageYOffset;
		}
		else if (ws.Browser.isLegacyMode && ws.Browser.isIE)
		{
			this.backgroundDiv.style.height = document.body.clientHeight + "px";
			this.backgroundDiv.style.width = document.body.clientWidth + "px";
			marginOffset = ((document.body.clientHeight - this.heightOfPopup) / 2) + document.body.scrollTop;
		}
		else if (ws.Browser.isOldIE)
		{
			// We have to factor in scroll offset on old IE since there is no CSS fixed positioning
			marginOffset = ((document.documentElement.clientHeight - this.heightOfPopup) / 2) + document.documentElement.scrollTop;
			
			// Include page margins on Old IE:
			this.backgroundDiv.style.width = document.body.clientWidth + parseInt(document.body.currentStyle.marginLeft) + parseInt(document.body.currentStyle.marginRight) + "px";

			// If page content is shorter than browser height, use browser height:
			var backgroundHeight;
			if (document.body.clientHeight < document.documentElement.clientHeight)
				backgroundHeight = document.documentElement.clientHeight;
			else
				backgroundHeight = document.body.clientHeight + parseInt(document.body.currentStyle.marginTop) + parseInt(document.body.currentStyle.marginBottom);
			
			if ((this.heightOfPopup + marginOffset) > backgroundHeight)
				backgroundHeight = this.heightOfPopup + marginOffset;
			
			this.backgroundDiv.style.height = backgroundHeight + "px";
		}
		else if (ws.Browser.isIE)
		{
			marginOffset = ((document.documentElement.clientHeight - this.heightOfPopup) / 2);
		}
		else
		{
			marginOffset = ((window.innerHeight - this.heightOfPopup) / 2);
		}
		
		if (marginOffset < 0)
			marginOffset = 0;
						
		this.popupDiv.style.marginTop = marginOffset + "px";
	},
	/*
	 * Builds the elements for an in-DOM popup dialog
	 */
	_build: function()
	{
		var backgroundColor = this.defaultBackgroundColor;
		if (arguments.length == 3)
			backgroundColor = arguments[2];
		
		// Create a translucent background div to go behind popup div
		this.backgroundDiv = document.createElement("div");
		this.backgroundDiv.style.top = "0px";
		this.backgroundDiv.style.right = "0px";
		this.backgroundDiv.style.bottom = "0px";
		this.backgroundDiv.style.left = "0px";
		this.backgroundDiv.style.backgroundColor = backgroundColor;
		this.backgroundDiv.style.opacity = "0.01";
		this.backgroundDiv.style.filter = "alpha(opacity=1)";
		this.backgroundDiv.style.zIndex = "10";  // Make sure it is above other elements
		this.backgroundDiv.className = "ws_dialog_background";
		
		var thisDialog = this;
		this.backgroundDiv.onclick = function()
		{
			thisDialog.Hide();
		};
		
		// Create the popup div
		this.popupDiv = document.createElement("div");
		this.popupDiv.style.marginLeft = "auto";
		this.popupDiv.style.marginRight = "auto";
		this.popupDiv.style.textAlign = "center";
		this.popupDiv.style.top = "0px";
		this.popupDiv.style.right = "0px";
		this.popupDiv.style.bottom = "0px";
		this.popupDiv.style.left = "0px";
		this.popupDiv.style.zIndex = "20"; // Make sure it is above background
		this.popupDiv.className = "ws_dialog_popup";
		this.popupDiv.style.opacity = "0.01";
		this.popupDiv.style.filter = "alpha(opacity=1)";
					
		// Perform some browser-specific things:
		if (ws.Browser.isOldIE || (ws.Browser.isLegacyMode && ws.Browser.isIE) || ws.Browser.isMobileSafari)
		{
			this.backgroundDiv.style.position = "absolute";
			this.popupDiv.style.position = "absolute";
			this.popupDiv.style.width = "100%"; // We don't need to set a height for this, since we compute a top margin
			
			if (ws.Browser.isOldIE)
			{
				// Need to hide all the SELECT elements in the DOM, since IE6 has a Z-order bug:
				this.hiddenSelects = Array();
				var selectsToHide = document.getElementsByTagName("select");
				for (var i = 0; i < selectsToHide.length; i++)
				{
					if (selectsToHide[i].style.visibility.toLowerCase() != "hidden")
					{
						selectsToHide[i].style.visibility = "hidden";
						this.hiddenSelects.push(selectsToHide[i]);
					}	
				}
			}
			
			if ((ws.Browser.isLegacyMode && ws.Browser.isIE))
			{
				var sizeWithScrollBar = document.body.clientWidth;
				window.scroll(0, 0);
				document.body.scroll = "no";
				this.scrollBarSize = document.body.clientWidth - sizeWithScrollBar;  // Compute scroll bar width
				// Adjust margin to compensate for change
				document.body.style.marginRight = (parseInt(document.body.currentStyle.marginRight) + this.scrollBarSize) + "px";
			}
		}
		else
		{
			// Set top margin so that image displays centered, unless window is too short
			this.backgroundDiv.style.position = "fixed";
			this.popupDiv.style.position = "fixed";
		}
		
		this._sizeDialog();  // Size and position the dialog
		
		// Setup window onresize event to handle popup position and background size on browser size change:
		if (typeof(window.onresize) == "function")
			this._previousOnResize = window.onresize;
		if (typeof(window.onscroll) == "function")
			this._previousOnScroll = window.onscroll;
		window.onresize = function()
		{
			thisDialog._previousOnResize();
			thisDialog._sizeDialog();
		};
		window.onscroll = window.onresize;
		
		document.body.appendChild(this.backgroundDiv);
		this.popupDiv.appendChild(this.contentDiv);
		document.body.appendChild(this.popupDiv);
		
		// See if Fx library is loaded:
		if (typeof(Fx) == "object")
		{
			this.backgroundDiv.mooFx = new Fx.Style(this.backgroundDiv, 'opacity', {duration: 750});
			this.backgroundDiv.mooFx._start(0.01, 0.5);
			this.popupDiv.mooFx = new Fx.Style(this.popupDiv, 'opacity', {duration: 500});
			this.popupDiv.mooFx._start(0.01, 1.0);
		}
		else
		{
			this.backgroundDiv.style.opacity = "0.5";
			this.backgroundDiv.style.filter = "alpha(opacity=50)";
			this.popupDiv.style.opacity = "1";
			this.popupDiv.style.filter = "alpha(opacity=100)";
		}
	},
	/* Used for storing existing onresize functions */
	_previousOnResize: function() { },
	/* Used for storing existing onscroll functions */
	_previousOnScroll: function() { }
};

// Most effects can be provided with Fx (fx.js), or Scriptaculous and Prototype,
// but for custom effects, we create our own ws.Fx library:
ws.Fx = {};

/*
 * Flip initialization
 */
ws.Fx.Flip = function(containerElm, flipElm, frontElm, backElm) {
	this.flipElm = flipElm;
	this.frontElm = frontElm;
	this.backElm = backElm;
	// Setup properties for Safari here:
	this.containerElm = containerElm;
	this.flipElm.style.webkitTransformStyle = "preserve-3d";
	// This is so we don't have to deal with changing opacity; Webkit can handle this for us:
	this.frontElm.style.webkitBackfaceVisibility = "hidden";
	this.backElm.style.webkitBackfaceVisibility = "hidden";
};

ws.Fx.Flip.prototype = {
	skew: 0,
	scale: 1,
	speed: 28,
	depth: 3,
	flipped: false,
	vertical: false,
	circular: false,
	reverse: false,  // For now, only reverses in Safari
	inProgress: false,
	/*
	 * Begins the flip animation
	 */
	Start: function(depth, speed, vertical, circular, reverse, onComplete)
	{
		if (ws.Browser.isIE)
			this.depth = depth / 10;  // IE's animation gets bad when depth is significant
		else
			this.depth = depth;
		
		this.speed = speed;
		this.vertical = vertical;
		this.circular = circular;
		this.reverse = reverse;
		this.flipped = !this.flipped;
		this.onComplete = onComplete;
		
		// This code path only for Safari 4.0.4 or greater (531), and not for Chrome at all (maybe someday)
		if (ws.Browser.isSafariWithTransitions && !ws.Browser.isChrome)
		{
			// Setup properties for Safari here:
			this.containerElm.style.webkitPerspective = 1000 - (this.depth * 100);  // Give depth to container, the lower the number, the greater the depth
			this.flipElm.style.webkitTransition = "-webkit-transform " + this.speed * 0.035 + "s ease-in-out";
			
			// Back side must be flipped (otherwise it will display mirrored)
			if (this.vertical)
			{
				this.backElm.style.webkitTransform = "rotateX(180deg)";
				if (this.circular)
					this.flipElm.style.webkitTransform = "rotateX(" + (parseInt((this.flipElm.style.webkitTransform + "(0)").match(/(-?\d+)/)[1], 10) + (this.reverse ? 1 : -1) * 180) + "deg)";
				else if (this.flipped)
					this.flipElm.style.webkitTransform = "rotateX(" + ((this.reverse ? 1 : -1) * 180) + "deg)";
				else
					this.flipElm.style.webkitTransform = "";
			}
			else
			{
				this.backElm.style.webkitTransform = "rotateY(180deg)";
				if (this.circular)
					this.flipElm.style.webkitTransform = "rotateY(" + (parseInt((this.flipElm.style.webkitTransform + "(0)").match(/(-?\d+)/)[1], 10) + (this.reverse ? 1 : -1) * 180) + "deg)";
				else if (this.flipped)
					this.flipElm.style.webkitTransform = "rotateY(" + ((this.reverse ? 1 : -1) * 180) + "deg)";
				else
					this.flipElm.style.webkitTransform = "";
			}
		}
		else
		{
			this.inProgress = true;
			this._flip();
		}
	},
	/*
	 * Handles first half of flip
	 */
	_flip: function()
	{
		var pn = this.circular ? 1 : -1;
		var elm = this.frontElm;
		var hiddenElm = this.backElm;

		if (!this.flipped)
		{
			pn = this.circular ? -1 : 1;
			elm = this.backElm;
			hiddenElm = this.frontElm;
		}

		this._setStyle(elm, this.vertical);
		hiddenElm.style.display = "none";
		this.skew += pn * this.depth;
		this.scale -= 0.1;

		if (this.scale >= 0)
		{
			var thisFlip = this;
			setTimeout(function(){ return thisFlip._flip(); }, this.speed);
		}
		else
		{
			elm.style.display = "none";
			this.skew = (-pn) * 10 * this.depth;
			this.scale = 0;
			this._flipBack();
		}
	},
	/*
	 * Handles last half of flip
	 */
	_flipBack: function()
	{
		var pn = this.circular ? 1 : -1;
		var elm = this.backElm;

		if (!this.flipped)
		{
			pn = this.circular ? -1 : 1;
			elm = this.frontElm;
		}

		this._setStyle(elm, this.vertical);
		elm.style.display = "";
		this.skew += pn * this.depth;
		this.scale += 0.1;

		if (this.scale <= 1)
		{
			var thisFlip = this;
			setTimeout(function(){ return thisFlip._flipBack(); }, this.speed);
		}
		else
		{
			this.skew = 0;
			this.scale = 1;
			this.inProgress = false;
			this.onComplete();
		}
	},
	/*
	 * Sets the scale and skew for the element.
	 * IE Matrix Calculations Overview:
	 *  For Skew-Y: [1 Math.tan(Y * Math.PI * 2 / 360) 0 1]
	 *  For Skew-X: [1 0 Math.tan(X * Math.PI * 2 / 360) 1]
	 *  For Scale: [(X * scale) (X * scale) (Y * scale) (Y * scale)]
	 */
	_setStyle: function(elm, vertical)
	{
		if (ws.Browser.isIE)
		{
			// We're also accounting for the possibility of other filters being applied to the elm
			if (vertical)
			{
				elm.style.filter = elm.currentStyle.filter.replace(/progid:DXImageTransform.Microsoft.Matrix\([^\)]*\)/g, "") + "progid:DXImageTransform.Microsoft.Matrix(m11=1, m21=0, m12=" + (Math.tan(this.skew * Math.PI * 2 / 360) * this.scale) + ", m22=" + this.scale + ", sizingMethod='auto expand')";
				elm.style.top = (50 - (50 * this.scale)) + "%";  // On IE8 matrix filter doesn't change element height, so for all IE, we change the margin instead of centering
			}
			else
			{
				elm.style.filter = elm.currentStyle.filter.replace(/progid:DXImageTransform.Microsoft.Matrix\([^\)]*\)/g, "") + "progid:DXImageTransform.Microsoft.Matrix(m11=" + this.scale + ", m21=" + (Math.tan(this.skew * Math.PI * 2 / 360) * this.scale) + ", m12=0, m22=1, sizingMethod='auto expand')";
				elm.style.left = (50 - (50 * this.scale)) + "%";  // On IE8 matrix filter doesn't change element width, so for all IE, we change the margin instead of centering
			}
		}
		else
		{
			var propertyValue = "skew(0deg, " + this.skew + "deg) scale(" + this.scale + ", 1)";
			if (vertical)
				propertyValue = "skew(" + this.skew + "deg, 0deg) scale(1, " + this.scale + ")";
			
			elm.style.webkitTransform = propertyValue; // This is for Chrome, since it doesn't fully support webkit's transitions
			elm.style.MozTransform = propertyValue;
			elm.style.OTransform = propertyValue;
			elm.style.transform = propertyValue;
		}
	}
};

/* EOF */
