/* JS Scripts for the configurator Model.asp page */

/*
 * This is for the NEW configurator Model page, created 2010
 * -Leland
*/

// Define a switch, then check for older versions of IE (IE6 and below), as some of the fancy animations won't work there.
var	isCapable = true;
if($.browser.msie && $.browser.version < 7){
	isCapable = false;
}

// do stuff when DOM is ready
jQuery(document).ready(function($) {
	
	/* Init the 'select another model' dropdown */
	/* **************************************** */
	// reset to the first option 'select another option' since browsers hold onto the last selection when you go back
	$('form#cmOtherModels select#cmModelMenu').val($('form#cmOtherModels select#cmModelMenu option:first').val());
	// Submit the form onChange of the selection
	$('form#cmOtherModels select#cmModelMenu').change(
		function(form) {																// $.log("changed to: " + this.value);
			if (this.value !== "") {														// $.log("submitting: Model=" + this.value);
				$(this).closest("form").submit();
			} else {																	// $.log("oops, don't do anything yet");
			}
		}
	);
	
	/* Init Summary Block Appearance (equal heights + stick-to-top) */
	/* ************************************************************ */

	//first, makes sure the image is preloaded, b/c Safari will break if it tries to get the image height before it's done loading
	$('#cmSummary #cmImage img').preload({
		// once the image is done loading...
		onFinish : function(){
			setSummaryHeight();
			if (!isCapable) {
				// if the img load finishes after the some things are setup, IE6 will go wonky... this just resets that.
				$('div.cmOptions').hide().show();
			}
		}
	});

	if (isCapable) {
		// check on the stickiness of the Summary box on init
		stickySummary();
		// whenever scrolling the window, check on the stickiness of the Summary box too
		$(window).scroll(stickySummary);
		
		// toggle-control the stickiness of the Summary window
		$('#cmStickySwitch').live('click', function(){
			toggleIsSticky();
		});
	}
	
	
	/* Init Disclaimer blocks */
	
	// uses a 2nd class in the span.moreInfo to define which disclaimer content to include in the tooltip.
		// so far, we only have two disclaimers to work with... if we change any of them, we need to make changes here,
		// as well as at the bottom of the html, within DIV#disclaimers.
	// get disclaimer content from DIVs in the DOM
	var MSRPs = new String()
	var dphFees = new String()
	MSRPs = $('#MSRPs').html();						//$.log(MSRPs);
	dphFees = $('#dphFees').html();					//$.log(dphFees);
	
	// set up the wTootip function for each different Disclaimer Content
	$('.moreInfo.MSRPs').wTooltip({
		content	: MSRPs,
		className	: 'disclaimers',
		offsetX	: -230,
		offsetY	: 5, 
		delay	: 200,
		fadeIn	: 100, 
		fadeOut	: 200,
		follow	: false
	});
	
	$('.moreInfo.dphFees').wTooltip({
		content	: dphFees,
		className	: 'disclaimers',
		offsetX	: -230,
		offsetY	: 5, 
		delay	: 200,
		fadeIn	: 100, 
		fadeOut	: 200,
		follow	: false
	});
	
	
	/* Since the number of color chips can vary, determine & set width on chip-colors container, so it can center within its container DIV */
	/* *********************************************************************************************************************************** */
	// set the variable to hold the total width of all the chips; start at 0.
	var chipsWidth = 0;
	// get the container width
	var containerWidth = $('#cmSelectColor div.cmOptionsSub').width();
	// for each color chip....
	$('ul#cmColorChips li.cmChipColor').each(function(){
		// ...get the outer width of the color chip and add it to our variable
		chipsWidth += $(this).outerWidth(true);
	});
	
	// if there are less chips than will fill the width of the outer container...
	if (chipsWidth < containerWidth) {
		// ...set the width of the group of color chips, so they'll center (in coordination with CSS settings - margin-left:auto; margin-right:auto;)
		$('ul#cmColorChips').width(chipsWidth);
	}	
		
	
	/* make each div.cmOptions (options sections) collapsible [except for the Form] */
	/* **************************************************************************** */
	if (isCapable) {
		$('div.cmOptions h3').not('div#cmOfferAndRequest h3').click(function(){
			// toggles the appearance of the correct DIV												    
			$(this).siblings('div.cmOptionsSub').slideToggle();
			// toggles a class for the header so it shows the different background graphic, with a '+' or a '-' on the left, in conjunction w/ CSS.
			$(this).toggleClass('closed');
		});
	}
	
		
	/* Reset the form, so nothing is selected from the browser's memory, and thus shown MSRP & Options Pricing are accurate */
	$('form#signup')[0].reset();
	
	
	/* Init Color Chips */
	/* **************** */
	// reset to first color chip, since browsers keep the last selection, but our image will always go back to the first one...
	$("input[name='ExteriorColor']:radio:first").click();	
	
	// Declare and define the main image paths, for use with toggling colors on Hover
	var selectedColorURI, selectedColorPath, selectedColor, hoveringColor, newImgSrc;
	// get the img src path info
	updateImgPath();
	
	// preload images
	var urls = [];
	
	$("input[name='ExteriorColor']:radio").each(function(){
		urls.push(this.value);														//$.log(urls);
	});
	
	$.preload( urls, {
		base :selectedColorPath,
		ext	:'.jpg'
	});
	
	
	// Change image on RadioBtn Change
	$("input[name='ExteriorColor']:radio").change(function() { 								// $.log("Color Option changed to: " + this.value+'.jpg');		
		// build new img src path
		newImgSrc = selectedColorPath + this.value + '.jpg';
		
		// change the src & alt attributes of the img
		$('#cmImage img#altimg').attr({
			src : newImgSrc,
			alt : this.value
		});
		
		// Reset the variables so they still work with the Hovering
		updateImgPath();
	});
	
	// Toggle image on Hover
	//$("#cmColorChips .cmChipColor label").hover(
	$("#cmColorChips .cmChipColor").hover(										 
		function() {
			// id chip color
			//hoveringColor = $(this).attr('for');											// $.log("Hovering over color chip: " + hoveringColor +'.jpg');		
			hoveringColor = $(this).attr('title');											// $.log("Hovering over color chip: " + hoveringColor +'.jpg');		
						
			// change the src & alt attributes of the img
			$('#cmImage img#altimg').attr({
				src : selectedColorPath + hoveringColor + '.jpg',
				alt : hoveringColor
			});
		},
		function() {
			// change the src & alt attributes of the img back to the selected one
			$('#cmImage img#altimg').attr({
				src : selectedColorURL,
				alt : selectedColor
			});
		}
	);
	
	// force a change on clicking the color chip...
	$("#cmColorChips .cmChipColor label").click(function(){
		// since not all browsers select the radio button attached to its label's IMG...
		clickedColor = $(this).attr('for');												// $.log('clicked color chip' + clickedColor);
		//clickedColor = $(this).attr('title');												// $.log('clicked color chip' + clickedColor);
		$("#cmColorChips .cmChipColor input[value='"+ clickedColor +"']").click().change();		
	});
	
	// Updates the Img Src variables so that the hover states return to the right image after a different radio button has been selected
	function updateImgPath(){															 // $.log('updating imageColor');
		selectedColorURL = $('#cmImage img#altimg').attr('src');  								 // $.log('URI: '+selectedColorURL);
		selectedColorPath = $.url.setUrl(selectedColorURL).attr("directory"); 					 // $.log('Path: ' + selectedColorPath);
		selectedColorFile = $.url.setUrl(selectedColorURL).attr("file"); 						 // $.log('ColorFile: ' + selectedColorFile);
		selectedColor = selectedColorFile.slice(0,(selectedColorFile.lastIndexOf('.')));			 // $.log('Color: ' + selectedColor);
		$.url.setUrl(); // reset the current URL to the function
	}
	
	
	/* Init Trim layout */
	/* **************** */
	
	// ensure all trim containers are equal height, to prevent funky floating
	var trimHeight = 0;
	var trimContainers = $('ul#cmAvailableTrims li.cmTrim');

	$(trimContainers).each(function(){
	   if ($(this).height() > trimHeight) { trimHeight = $(this).height(); }
	});
	
	$(trimContainers).height(trimHeight);
	
	$(trimContainers).hover(
		function(){
			$(this).addClass('hovering');
		},
		function(){
			$(this).removeClass('hovering');
		}
	);

	
	/* Init trim-level change event to reload page w/ trim change */
	/* ********************************************************** */
	
	// get the current URL & trim
	var currentPath = $.url.setUrl().attr('source');												//$.log(currentPath);
	var currTrimQuery = $.url.param('T') ? $.url.param('T') : $.url.param('t') ? $.url.param('t') : false;	//$.log(currTrimQuery);
		
	// whenever a new trim is clicked...	
	$("input[name='TrimPackage']:radio").change(function() {								//$.log("Trim Option changed to: " + this.value); $.log('currentPath: '+currentPath);	
		var newTrimQuery = ($(this).attr('id')).replace('t','');							//$.log(newTrimQuery);
		
		if (currTrimQuery) {														//$.log('yes, there is a trim');
			// if there's already a trim in the URL string, replace w/ the new trim
			currentPath = currentPath.replace(currTrimQuery,newTrimQuery);
		} else {																	//$.log('nope, there is not a trim');
			// otherwise, add the trim to the query string
			currentPath = currentPath += ('&T=' + newTrimQuery);
		}																		//$.log(currentPath);
		go(currentPath);
	});
	
	
	/* Init Table Zebra Striping - adds .odd to the odd rows & .even to the even rows of the options table, starting over after each <TH> row, to zebra stripe it. */
	/* ****************************************************************************************************************************** */
	// flag for even/odd 0 is even, 1 is odd
	var evenOddFlag = 0;
	// run function on each tr
	$('table.striped tr').each(function(index){
		 var $tr = $(this);
		 if ($tr.find('th').length == 1) {
			  //this is a header row, set evenOddFlag to zero
			  evenOddFlag = 0
		 } else {
			  //this is a table row
			  if (evenOddFlag == 0) {
				   // add even class and change flag
				   $tr.addClass('even');
				   evenOddFlag = 1;
			  } else {
				   // add odd class and change flag
				   $tr.addClass('odd');	
				   evenOddFlag = 0;
			  }
		 }
	});
	
	
	/* Init Options Selections & Price Block Adjustments */
	/* ******************************************** */
	//init the price MSRP in the pricing block
	var basePrice, fees, selOptions, msrp;
	var opt = $('#cmPricing .cmSelectedOptions td.value');
	var tot = $("span#total");
	updateMSRP();
	
	// init variables used in the changeOptionsTotal function	
	var last = new Array;		// last = an array to hold the last amount added to the options total from a single-choice (radioBtn) group
	var cb   = 0;				// cb   = a switch used to determine a radio-btn change (vs a checkbox change), so we can then determine the difference between the *last* amount for that group & this one.
	
	// make sure that all prices are shown with penny values
	$('#cmPricing .cmBasePrice td.value').text("$"+formatAsMoney(unformatAsMoney($('#cmPricing .cmBasePrice td.value').text())));	
	$('#cmPricing .cmFees td.value').text("$"+formatAsMoney(unformatAsMoney($('#cmPricing .cmFees td.value').text())));	
	$('#cmPricing .cmSelectedOptions td.value').text("$"+formatAsMoney(unformatAsMoney($('#cmPricing .cmSelectedOptions td.value').text())));
	
	
	// handler for options change events
	$('#cmSelectOptions input').change(function(){
		//$.log('changed options')
		
		if ($(this).is(':radio')){
			cb=1;  			// if this is a radioBtn (as opposed to a checkbox), cb=1
		}
		
		// get the amount, the switch state, and the group from various HTML Elements
		var amnt = parseFloat($(this).parent().siblings('.optionAmount').text());					//$.log(amnt);  	// amnt comes from the text in the last column of the table
		var swtch = ($(this).is(':checked')); 												//$.log(swtch); 	// swtch looks at the state of the checkbox or radioBtn
		var groupName = ($(this).attr('name'));												//$.log(groupName);	// get group from name attr.
		
		// get group# based on groupName
		switch (groupName) {
			case 'Options_Wanted'	: group = 0;
			break;
			
			case 'Packages'		: group = 1;
			break;
			
			case 'Engine'			: group = 2;
			break;
			
			case 'Transmission'		: group = 3;
			break;
			
			case 'DriveTrain'		: group = 4;
			break;
			
			case 'Bed'			: group = 5;
			break;
			
			case 'Cab'			: group = 6;
			break;
			
			default				: group = 0;
		}
		
		// figure and update pricing
		changeOptionsTotal(amnt, swtch, group);
	});
	
	
	/* Init Main Submission Form */
	$('form#signup').submit(function() {
		return checkData();
	});
	
	
	/* Add'l functions req'd after the document is ready */
	/* ************************************************* */
	
	// adds up the total for options, then update the pricing shown
	function changeOptionsTotal(amnt, swtch, group) {
		// amnt = the amount of the changed option
		// swtch = (boolean) state of the checkbox or radio button of the changed option
		// group = the options group of the changed option
		
		//get current options total
		var current = unformatAsMoney($(opt).text());
		
		// make sure we're dealing w/ numbers, not strings
		amnt*=1;
		current*=1;
			
		if (swtch == true) { 															
		// if we are turning the option ON (or changing radio choice)
			
			if (cb == "1") { 																
			// if we're dealing w/ a radio btn
				if (!last[group]) { 
					// if there was no previously selected item for this RadioBtn group,
					// make the previous amount for that group = 0
					last[group] = 0; 
				}
				// figure the total by adding the new amnt & subtracting the old amount
				var result = ((current+amnt) - last[group]);
				// reassign the new amnt tp the 'last' variable, for the next time we change this group
				last[group] = amnt;
				// reset our  radioBtn switch
				cb=0;
			} else { 																		
			// or else we're dealing w/ a checkbox
				// so just add the new Amount
				var result = (current+amnt);
			}
			
		} else {																		
		// or else we're turning the option OFF
			// so just subtract the new amount
			var result = ((current-amnt));	
		}
		
		// take the new options total and update the amount shown on the page
		updateOptions(formatAsMoney(result));
	} 
	// endfunction changeOptionsTotal()
	
	// updates the options pricing shown -- is called after each option is selected or deselected
	function updateOptions(result) {
		var result = result;
		// update the Options Total
		$(opt).text('$'+result);
		// re-check the amounts shown and update the total MSRP
		updateMSRP();
	}
	// end function updateOptions()
	
	// updates the MSRP shown -- is called after each time the options total is updated, as well as at page init
	function updateMSRP(){
		// grabs the numbers shown from the DOM
		var basePrice = unformatAsMoney($('#cmPricing .cmBasePrice td.value').text());							//$.log('basePrice = '+basePrice);
		var fees = unformatAsMoney($('#cmPricing .cmFees td.value').text());									//$.log('fees = '+fees);
		var selOptions = unformatAsMoney($('#cmPricing .cmSelectedOptions td.value').text());					//$.log('selOptions = '+selOptions);
		// and adds 'em up to make the new MSRP
		var msrp = formatAsMoney(( basePrice + fees + selOptions ));										//$.log('msrp = '+msrp);
		// and updates the DOM
		$(tot).text('$'+msrp);																		//$.log('updating total to: '+msrp);
	}
	// end function updateMSRP()
	
	// fixes an IE Bug where clicking on a radio button doesn't generate an onChange event until you click again *away* from the button.
	if ($.browser.msie) {
		$('input:radio').click(function () {
			this.blur();
			this.focus();
		});
	}	
	
}); /* end doc.ready functions */

/* functions and variables used throughout */

/* console logging for debugging help */
jQuery.log = function(message) {
  try {
     console.debug(message);
  } catch(e) {
	  try {
		console.log(message);
	  } catch(e) {
		alert(message);
	  }
  }
};


/* js page linking (to load new trim) */
function go(loc) {
	window.location.href = loc;
}


/* Set the Height of the Summary Block based on Img Height */
function setSummaryHeight() {
	// get/set initial values
	var adjustmentAmt;
	var cmImg = $('#cmSummary #cmImage img').height(); 		//$.log('cmImg = ' + cmImg);
	var cmPrc = $('#cmSummary #cmPricing').height(); 			//$.log('cmPrc = ' + cmPrc);
	var cmSummaryBlocks = $('#cmSummary > div').filter('#cmImage, #cmPricing');
	
	// adjust to the larger height
	if ( cmImg  >  cmPrc ) {
		$(cmSummaryBlocks).height(cmImg);
	} else {
		$(cmSummaryBlocks).height(cmPrc);
	}
	
	// get adjusted height of image container
	var cmImgWrap = $('#cmSummary #cmImage').height(); 		//$.log('cmImgWrap = ' + cmImgWrap);
	var cmPrcWrap = $('#cmSummary #cmPricing').height(); 		//$.log('cmPrcWrap = ' + cmPrcWrap);
	
	// if the image is too skinny, center it vertically within the block
	if (cmImgWrap > cmImg) {
		adjustmentAmt = (cmImgWrap - cmImg)/2;			//$.log('adjustmentAmt = ' + adjustmentAmt);
		$('#cmSummary #cmImage img').css('top', adjustmentAmt);
	}	
	
	// if the textblock is too skinny, near-center it vertically within the block
	if (cmPrcWrap > cmPrc) {
		adjustmentAmt = (cmPrcWrap - cmPrc)/3;			//$.log('adjustmentAmt = ' + adjustmentAmt);
		$('#cmSummary #cmPricing table').css('top', adjustmentAmt);
	}	
}


/* Sticky Summary - make the summary box stick to the header */

// Get DIVs
var stickyDiv = $('#cmSummary');
var nextDiv = $('.cmOptions:first');

// define switches
var firstStick = 0;				// a switch to show the stick/unstick button only after the very first time it sticks
var isStuck = 0;				// resets every time we scroll to top... so animation only runs as it first sticks each time
var isSticky = 1;				// a switch so we can turn the sticky feature on and off programatically

// define Sticky text
var makeSticky = "Make Sticky";
var unStick = "Un-Stick";

function toggleIsSticky(){			// toggles the stickiness of the cmSummary DIV
	if (isSticky) {
		isSticky = 0;
		resetSticky();
		$('#cmStickySwitch').text(makeSticky);
	} else {
		isSticky = 1;
		$('#cmStickySwitch').text(unStick);
		stickySummary();
		if (!isStuck) {
			$('#cmStickySwitch').hide();			
		}
	}
}
// the function
function stickySummary() {
	if(isSticky) {
		//$.log('we can stick')
		// get the current location of the page in relation to the window
		var window_top = $(window).scrollTop();
		// get the current location of the area just above the summary box (the bottom of the header)
		var div_top = (($('#cmHeader').offset().top)+($('#cmHeader').outerHeight()));
		// get height of the Summary box
		var divOffset = $(stickyDiv).outerHeight();
		// get the left position of the div, so it can stay there when it sticks
		var div_left = ($('#cmHeader').offset().left);						//$.log(div_left);
		// If we've scrolled down past the top of the cmSummary DIV
		if (window_top > div_top) {
			$(nextDiv).css('margin-top',divOffset);
			$(stickyDiv).addClass('sticky').css('left',div_left);
			// each time the DIV gets Sticky after being unstuck...
			if (!isStuck) {
				// if it's the first time, attach the sticky switch
				if(!firstStick){
					$("<div id='cmStickySwitch'>"+unStick+"</div>").appendTo("div#cmSummary");
					firstStick = 1;
				}
				// reset the switch
				isStuck = 1;
				//show the switch if hidden
				if ($('#cmStickySwitch').css('display')=='none') {
					$('#cmStickySwitch').show();
				}
				// stop any current animations and start the border animation
				$(stickyDiv)
					.stop()
					.animate({
						borderRightColor	: 'orange',
						borderBottomColor	: 'orange',
						borderLeftColor	: 'orange'
					}, 10)
					.delay(1000)
					.animate({
						borderRightColor	: 'yellow',
						borderBottomColor	: 'yellow',
						borderLeftColor	: 'yellow'
					}, 3000)
					.animate({
						borderRightColor	: 'white',
						borderBottomColor	: 'white',
						borderLeftColor	: 'white'
					}, 4000);
			}	
		} else { // if we've scrolled above the normal position...
			resetSticky();
		}
	} else {
		//$.log('we can NOT stick')
	}
}

function resetSticky(){// stop all animations and reset the DIV's to defaults
	$(stickyDiv)
		.stop()
		.css({
			borderRightColor	: 'white',
			borderBottomColor	: 'white',
			borderLeftColor	: 'white'
		})
		.removeClass('sticky')
		.css('left','');
	$(nextDiv).css('margin-top','');
	if (isSticky) {
		$('#cmStickySwitch').hide()
	}
	// reset the switch, so the animations can re-run next time we stick
	isStuck = 0;
}


/* Money & Number Formatting functions */ 
function unformatAsMoney(str) { // cleans a dollar-amount expressed as a string & converts into a number that the rest of the code can handle
		str = str.replace('$','');
		str = str.replace(',','');
		str *= 1;
		str = (Math.round(str*100))/100;		
		return str
}
// end of function unformatAsMoney()


function CurrencyFormatted(amount) { // returns a number with exactly 2 decimal points
	// make sure it's a number
	var i = parseFloat(amount);
	// if not a number, = 0.00
	if(isNaN(i)) { i = 0.00; }
	// set up handling for negative numbers...
	var minus = '';
	if(i < 0) { minus = '-'; }
	i = Math.abs(i);
	// round off to the nearest 1/100ths
	i = parseInt((i + .005) * 100);
	i = i / 100;
	// makes sure there are two digits following the decimal point, prepends the "-" character if it started as a negative number, and returns the result
	s = new String(i);
	if(s.indexOf('.') < 0) { s += '.00'; }
	if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
	s = minus + s;
	return s;
}
// end of function CurrencyFormatted()

function formatAsMoney(amount) { // takes a number, sends it to the currency formatter, then adds commas every 3rd position from the right of the whole number (to the left of the decimal)
	// sends the amount through the CurrencyFormatted function, to help clean it up
	var amount = amount;
	amount = CurrencyFormatted(amount)
	// assign the delimeter
	var delimiter = ","; 
	// convert to a string, then split at the decimal
	var amt = new String(amount);
	var a = amt.split('.',2)
	// store the decimal
	var d = a[1];
	// store the whole number
	var i = parseInt(a[0]);
	if(isNaN(i)) { return ''; }
	// setup handling for negative numbers
	var minus = '';
	if(i < 0) { minus = '-'; }
	i = Math.abs(i);
	// set up arrays and strings
	var n = new String(i);
	var a = [];
	//three digits are removed from the end of the number and assigned to array variable a, so long as the number is longer than three digits. 
	while(n.length > 3)
	{
		var nn = n.substr(n.length-3);
		a.unshift(nn);
		n = n.substr(0,n.length-3);
	}
	// The number is then reformed using the elements of array a, with the delimiter digit inserted between each element.
	if(n.length > 0) { a.unshift(n); }
	n = a.join(delimiter);
	if(d.length < 1) { amt = n; }
	else { amt = n + '.' + d; }
	amt = minus + amt;
	return amt;
}
// end of function formatAsMoney()


// form validation - basic 
function checkData (){
	if (document.signup.First_Name.value == "") {
		alert("Please fill in your first name.");
		document.signup.First_Name.focus();
		return false;
	}
	
	if (document.signup.Last_Name.value == "") {
		alert("Please fill in your last name.");
		document.signup.Last_Name.focus();
		return false;
	}
	if (document.signup.Customer_Email.value == "") {
		alert("Please fill in your email Address.");
		document.signup.Customer_Email.focus();
		return false;
	}
}


/* jQuery.Preload - Multifunctional preloader 
 * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com
 * http://flesler.blogspot.com/2008/01/jquerypreload.html
 * Dual licensed under MIT and GPL.
 * Date: 3/25/2009
 * @author Ariel Flesler
 * @version 1.0.8
 */
;(function($){var h=$.preload=function(c,d){if(c.split)c=$(c);d=$.extend({},h.defaults,d);var f=$.map(c,function(a){if(!a)return;if(a.split)return d.base+a+d.ext;var b=a.src||a.href;if(typeof d.placeholder=='string'&&a.src)a.src=d.placeholder;if(b&&d.find)b=b.replace(d.find,d.replace);return b||null}),data={loaded:0,failed:0,next:0,done:0,total:f.length};if(!data.total)return finish();var g=$(Array(d.threshold+1).join('<img/>')).load(handler).error(handler).bind('abort',handler).each(fetch);function handler(e){data.element=this;data.found=e.type=='load';data.image=this.src;data.index=this.index;var a=data.original=c[this.index];data[data.found?'loaded':'failed']++;data.done++;if(d.enforceCache)h.cache.push($('<img/>').attr('src',data.image)[0]);if(d.placeholder&&a.src)a.src=data.found?data.image:d.notFound||a.src;if(d.onComplete)d.onComplete(data);if(data.done<data.total)fetch(0,this);else{if(g&&g.unbind)g.unbind('load').unbind('error').unbind('abort');g=null;finish()}};function fetch(i,a,b){if(a.attachEvent&&data.next&&data.next%h.gap==0&&!b){setTimeout(function(){fetch(i,a,1)},0);return!1}if(data.next==data.total)return!1;a.index=data.next;a.src=f[data.next++];if(d.onRequest){data.index=a.index;data.element=a;data.image=a.src;data.original=c[data.next-1];d.onRequest(data)}};function finish(){if(d.onFinish)d.onFinish(data)}};h.gap=14;h.cache=[];h.defaults={threshold:2,base:'',ext:'',replace:''};$.fn.preload=function(a){h(this,a);return this}})(jQuery);


/* JQuery URL Parser 
 * Version 1.0
 * Parses URLs and provides easy access to information within them.
 *
 * Author: Mark Perkins
 * Author email: mark@allmarkedup.com
 *
 * For full documentation and more go to http://projects.allmarkedup.com/jquery_url_parser/
 *
 * ---------------------------------------------------------------------------
 *
 * CREDITS:
 *
 * Parser based on the Regex-based URI parser by Steven Levithan.
 * For more information (including a detailed explaination of the differences
 * between the 'loose' and 'strict' pasing modes) visit http://blog.stevenlevithan.com/archives/parseuri
 *
 * ---------------------------------------------------------------------------
 *
 * LICENCE:
 *
 * Released under a MIT Licence. See licence.txt that should have been supplied with this file,
 * or visit http://projects.allmarkedup.com/jquery_url_parser/licence.txt
 *
 * ---------------------------------------------------------------------------
 * 
 * EXAMPLES OF USE:
 *
 * Get the domain name (host) from the current page URL
 * jQuery.url.attr("host")
 *
 * Get the query string value for 'item' for the current page
 * jQuery.url.param("item") // null if it doesn't exist
 *
 * Get the second segment of the URI of the current page
 * jQuery.url.segment(2) // null if it doesn't exist
 *
 * Get the protocol of a manually passed in URL
 * jQuery.url.setUrl("http://allmarkedup.com/").attr("protocol") // returns 'http'
 *
 */

jQuery.url = function()
{
	var segments = {};
	
	var parsed = {};
	
	/**
    * Options object. Only the URI and strictMode values can be changed via the setters below.
    */
  	var options = {
	
		url : window.location, // default URI is the page in which the script is running
		
		strictMode: false, // 'loose' parsing by default
	
		key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], // keys available to query 
		
		q: {
			name: "queryKey",
			parser: /(?:^|&)([^&=]*)=?([^&]*)/g
		},
		
		parser: {
			strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,  //less intuitive, more accurate to the specs
			loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
		}
		
	};
	
    /**
     * Deals with the parsing of the URI according to the regex above.
 	 * Written by Steven Levithan - see credits at top.
     */		
	var parseUri = function()
	{
		str = decodeURI( options.url );
		
		var m = options.parser[ options.strictMode ? "strict" : "loose" ].exec( str );
		var uri = {};
		var i = 14;

		while ( i-- ) {
			uri[ options.key[i] ] = m[i] || "";
		}

		uri[ options.q.name ] = {};
		uri[ options.key[12] ].replace( options.q.parser, function ( $0, $1, $2 ) {
			if ($1) {
				uri[options.q.name][$1] = $2;
			}
		});

		return uri;
	};

    /**
     * Returns the value of the passed in key from the parsed URI.
  	 * 
	 * @param string key The key whose value is required
     */		
	var key = function( key )
	{
		if ( ! parsed.length )
		{
			setUp(); // if the URI has not been parsed yet then do this first...	
		} 
		if ( key == "base" )
		{
			if ( parsed.port !== null && parsed.port !== "" )
			{
				return parsed.protocol+"://"+parsed.host+":"+parsed.port+"/";	
			}
			else
			{
				return parsed.protocol+"://"+parsed.host+"/";
			}
		}
	
		return ( parsed[key] === "" ) ? null : parsed[key];
	};
	
	/**
     * Returns the value of the required query string parameter.
  	 * 
	 * @param string item The parameter whose value is required
     */		
	var param = function( item )
	{
		if ( ! parsed.length )
		{
			setUp(); // if the URI has not been parsed yet then do this first...	
		}
		return ( parsed.queryKey[item] === null ) ? null : parsed.queryKey[item];
	};

    /**
     * 'Constructor' (not really!) function.
     *  Called whenever the URI changes to kick off re-parsing of the URI and splitting it up into segments. 
     */	
	var setUp = function()
	{
		parsed = parseUri();
		
		getSegments();	
	};
	
    /**
     * Splits up the body of the URI into segments (i.e. sections delimited by '/')
     */
	var getSegments = function()
	{
		var p = parsed.path;
		segments = []; // clear out segments array
		segments = parsed.path.length == 1 ? {} : ( p.charAt( p.length - 1 ) == "/" ? p.substring( 1, p.length - 1 ) : path = p.substring( 1 ) ).split("/");
	};
	
	return {
		
	    /**
	     * Sets the parsing mode - either strict or loose. Set to loose by default.
	     *
	     * @param string mode The mode to set the parser to. Anything apart from a value of 'strict' will set it to loose!
	     */
		setMode : function( mode )
		{
			strictMode = mode == "strict" ? true : false;
			return this;
		},
		
		/**
	     * Sets URI to parse if you don't want to to parse the current page's URI.
		 * Calling the function with no value for newUri resets it to the current page's URI.
	     *
	     * @param string newUri The URI to parse.
	     */		
		setUrl : function( newUri )
		{
			options.url = newUri === undefined ? window.location : newUri;
			setUp();
			return this;
		},		
		
		/**
	     * Returns the value of the specified URI segment. Segments are numbered from 1 to the number of segments.
		 * For example the URI http://test.com/about/company/ segment(1) would return 'about'.
		 *
		 * If no integer is passed into the function it returns the number of segments in the URI.
	     *
	     * @param int pos The position of the segment to return. Can be empty.
	     */	
		segment : function( pos )
		{
			if ( ! parsed.length )
			{
				setUp(); // if the URI has not been parsed yet then do this first...	
			} 
			if ( pos === undefined )
			{
				return segments.length;
			}
			return ( segments[pos] === "" || segments[pos] === undefined ) ? null : segments[pos];
		},
		
		attr : key, // provides public access to private 'key' function - see above
		
		param : param // provides public access to private 'param' function - see above
		
	};
	
}();


/* Wayfarer Tooltip - used for Disclaimers 
 *
 * NOTE: Default Style settings hacked by Leland - commented out and using CSS instead!!!
 *		Don't just copy this into another site w/out knowing about that change first!!!
 *
 * Version 1.0.9
 * Author Abel Mohler
 * URI: http://www.wayfarerweb.com/wtooltip.php
 * Released with the MIT License: http://www.wayfarerweb.com/mit.php
 */
(function($){ //jQuery.noConflict()compliant
    $.fn.wTooltip = function(o, callback){
        o = $.extend({ //defaults, can be overidden
            content: null, //string content for tooltip.
            ajax: null, //path to content for tooltip
            follow: true, //does tooltip follow the cursor?
            auto: true, //If false, tooltip won't automatically transition, it must be manually shown/hidden
            fadeIn: 0, //fade in, in milliseconds ("fast, "slow", etc may also be used)
            fadeOut: 0, //fade out, in milliseconds ("fast, "slow", etc may also be used)
            appendTip: document.body, //should probably not need to be overridden, but could be useful if you require a tip that remains relative to an exact point
            degrade: false, //if true, in IE6 tooltip will degrade to a title attribute message
            offsetY: 10, //offsetY and offsetX properties designate position from the cursor
            offsetX: 1,
            style: {},
            className: null, //to style the tooltip externally, pass a className or id
            id: null,
            callBefore: function(tooltip, node, settings){
            }, //called when mouse enters the area
            callAfter: function(tooltip, node, settings){
            }, //called when mouse leaves the area (same as "callback" option)
            clickAction: function(tooltip, node){
                $(tooltip).hide();
            }, //called when the element is clicked, with access to tooltip
            delay: 0, //delay (in milliseconds)before tooltip appears and callBefore executes
            timeout: 0 //delay (in milliseconds)before tooltip transitions away, and callAfter executes
        }, o ||
        {});

        if (!o.style && typeof o.style != "object") {
            o.style = {};
            /*o.style.zIndex = "99999";*/
        }
        else {
            o.style = $.extend({ //the default style rules of the tooltip
                /*border: "1px solid #aaa",
                background: "#fff",
                color: "#000",
                padding: "10px",
                zIndex: "99999",
                textAlign: "left"*/
            }, o.style ||
            {});
        }

        if (typeof callback == "function")
            o.callAfter = callback || o.callAfter;

        o.style.display = "none", o.style.position = "absolute"; //permanent defaults
        //private settings
        var title, timeout, timeout2, iId, over = {}, firstMove = true, hovered = false, maxed = false, tooltip = document.createElement('div'), ie6 = (typeof document.body.style.maxWidth == "undefined") ? true : false, talk = (typeof $.talk == "function" && typeof $.listen == "function") ? true : false;

        if (o.id)
            tooltip.id = o.id;
        if (o.className)
            tooltip.className = o.className;

        o.degrade = (o.degrade && ie6) ? true : false; //only degrades if also IE6
        for (var p in o.style)//apply styles to tooltip
             tooltip.style[p] = o.style[p];

        function fillTooltip(condition){
            if (condition) {
                if (o.degrade)//replace html characters for proper degradation to title attribute
                    $(tooltip).html(o.content.replace(/<\/?[^>]+>/gi, ''));
                else //otherwise just fill the tooltip with content
                     $(tooltip).html(o.content);
            }
        }

        if (o.ajax) { //if o.ajax is selected, this will fill and thus override o.content
            $.get(o.ajax, function(data){
                if (data)
                    o.content = data;
                fillTooltip(o.content);
            });
        }

        function offConditions(that){
            function _offActions(that){
                if (title && !o.content) {
                    title = "";
                }
            }
            function _execute(){
                if (!hovered && o.auto) {
                    clearInterval(iId);
                    if (o.fadeOut) {
                        $(tooltip).fadeOut(o.fadeOut, function(){
                            _offActions(that);
                        });
                    }
                    else {
                        _offActions(that);
                        tooltip.style.display = "none";
                    }
                }
                if (typeof o.callAfter == "function")
                    o.callAfter(tooltip, that, o);
                if (talk)
                    o = $.listen(o);
            }
            if (o.timeout > 0) {
                timeout2 = setTimeout(function(){
                    _execute();
                }, o.timeout);
            }
            else {
                _execute();
            }
        }

        $(tooltip).hover(function(){
            hovered = true;
        }, function(){
            hovered = false;
            offConditions(over);
        });

        //initialize
        if (talk) { //A "channel" for plugins to "talk" to each other, and callbacks to manipulate settings
            o.key = tooltip;
            o.plugin = "wTooltip";
            o.channel = "wayfarer";
            $.talk(o);
        }

        fillTooltip(o.content && !o.ajax);
        $(tooltip).appendTo(o.appendTip);

        return this.each(function(){ //returns the element chain
            $(this).hover(function(){
                var that = this;
                clearTimeout(timeout2);
                if ((this.title || this.titleMemKeep) && !o.degrade && !o.content) {
                    title = this.title || this.titleMemKeep;
                    if(this.title) {
                        this.titleMemKeep = this.title;
                        this.title = "";
                    }
                }
                if (o.content && o.degrade)
                    this.title = tooltip.innerHTML;

                function _execute(){
                    if (typeof o.callBefore == "function")
                        o.callBefore(tooltip, that, o);
                    if (talk)
                        o = $.listen(o); //ping for new settings

                    var display;
                    if (o.content) {
                        if (!o.degrade)
                            display = "block";
                    }
                    else
                        if (title && !o.degrade) {
                            $(tooltip).html(unescape(title));
                            display = "block";
                            title = "";
                        }
                        else {
                            display = "none";
                        }
                    if (o.auto) {
                        if (display == "block" && o.fadeIn)
                            $(tooltip).fadeIn(o.fadeIn);
                        else
                            tooltip.style.display = display;
                    }
                }

                if (o.delay > 0) {
                    timeout = setTimeout(function(){
                        _execute();
                    }, o.delay);
                }
                else {
                    _execute();
                }
            }, function() {
                clearTimeout(timeout);
                var that = this;
                firstMove = true;
                if (!o.follow || maxed || ((o.offsetX < 0 && (0 - o.offsetX < $(tooltip).outerWidth())) && (o.offsetY > 0 && 0 - o.offsetY < $(tooltip).outerHeight()))) {
                    setTimeout(function(){
                        iId = setInterval(function(){
                            offConditions(that)
                        }, 1)
                    }, 1);
                }
                else {
                    offConditions(this);
                }
            });


            $(this).mousemove(function(e){
                over = this; //tracks the event trigger in the plugin-global "over"
                if (o.follow || firstMove) {
                    var scrollY = $(window).scrollTop(), scrollX = $(window).scrollLeft(), top = e.clientY + scrollY + o.offsetY, left = e.clientX + scrollX + o.offsetX, outerH = $(o.appendTip).outerHeight(), innerH = $(o.appendTip).innerHeight(), maxLeft = $(window).width() + scrollX - $(tooltip).outerWidth(), maxTop = $(window).height() + scrollY - $(tooltip).outerHeight();

                    top = (outerH > innerH) ? top - (outerH - innerH) : top; //if appended area (usually BODY) has a border on top, adjust
                    maxed = (top > maxTop || left > maxLeft) ? true : false;

                    if (left - scrollX <= 0 && o.offsetX < 0)
                        left = scrollX;
                    else
                        if (left > maxLeft)
                            left = maxLeft;
                    if (top - scrollY <= 0 && o.offsetY < 0)
                        top = scrollY;
                    else
                        if (top > maxTop)
                            top = maxTop;

                    tooltip.style.top = top + "px";
                    tooltip.style.left = left + "px";
                    firstMove = false;
                }
            });

            if (typeof o.clickAction == "function") {
                $(this).click(function(){
                    o.clickAction(tooltip, this);
                });
            }
        });
    }
})(jQuery);


/* jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

(function(jQuery){

	// We override the animation for all of these color styles
	jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
		jQuery.fx.step[attr] = function(fx){
			if ( fx.state == 0 ) {
				fx.start = getColor( fx.elem, attr );
				fx.end = getRGB( fx.end );
			}

			fx.elem.style[attr] = "rgb(" + [
				Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
			].join(",") + ")";
		}
	});

	// Color Conversion functions from highlightFade
	// By Blair Mitchelmore
	// http://jquery.offput.ca/highlightFade/

	// Parse strings looking for color tuples [255,255,255]
	function getRGB(color) {
		var result;

		// Check if we're already dealing with an array of colors
		if ( color && color.constructor == Array && color.length == 3 )
			return color;

		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
			return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
			return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
			return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
			return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

		// Otherwise, we're most likely dealing with a named color
		return colors[jQuery.trim(color).toLowerCase()];
	}
	
	function getColor(elem, attr) {
		var color;

		do {
			color = jQuery.curCSS(elem, attr);

			// Keep going until we find an element that has color, or we hit the body
			if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
				break; 

			attr = "backgroundColor";
		} while ( elem = elem.parentNode );

		return getRGB(color);
	};
	
	// Some named colors to work with
	// From Interface by Stefan Petre
	// http://interface.eyecon.ro/

	var colors = {
		aqua:[0,255,255],
		azure:[240,255,255],
		beige:[245,245,220],
		black:[0,0,0],
		blue:[0,0,255],
		brown:[165,42,42],
		cyan:[0,255,255],
		darkblue:[0,0,139],
		darkcyan:[0,139,139],
		darkgrey:[169,169,169],
		darkgreen:[0,100,0],
		darkkhaki:[189,183,107],
		darkmagenta:[139,0,139],
		darkolivegreen:[85,107,47],
		darkorange:[255,140,0],
		darkorchid:[153,50,204],
		darkred:[139,0,0],
		darksalmon:[233,150,122],
		darkviolet:[148,0,211],
		fuchsia:[255,0,255],
		gold:[255,215,0],
		green:[0,128,0],
		indigo:[75,0,130],
		khaki:[240,230,140],
		lightblue:[173,216,230],
		lightcyan:[224,255,255],
		lightgreen:[144,238,144],
		lightgrey:[211,211,211],
		lightpink:[255,182,193],
		lightyellow:[255,255,224],
		lime:[0,255,0],
		magenta:[255,0,255],
		maroon:[128,0,0],
		navy:[0,0,128],
		olive:[128,128,0],
		orange:[255,165,0],
		pink:[255,192,203],
		purple:[128,0,128],
		violet:[128,0,128],
		red:[255,0,0],
		silver:[192,192,192],
		white:[255,255,255],
		yellow:[255,255,0]
	};
	
})(jQuery);

