/* global window document jQuery $ typeOf */
/* jslint browser: true, devel: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */

/*
	header.js
	Copyright 2010 AutoZone, Inc.
	Content is confidential to and proprietary information of
	AutoZone, Inc., its subsidiaries and affiliates.
*/

/*
AZPro Header Javascript file.

author slee
version %PCMS_HEADER_SUBSTITUTION_START%$Id: %PM% %PR% %PRT% %PO% %PS% $%PCMS_HEADER_SUBSTITUTION_END%
*/

var Core = {},
	applicationSettings = {
		constructorTimeout: ($.browser.msie) ? 1000 : 0,
		useSearchingLocalNetworkDialog: false
	};

var Configuration = (function () {
	"use strict";
	return {
		getSetting: function (name) {
			var value = applicationSettings[name];
			if (typeof value !== "undefined") {
				return value;
			}
			// If there's no configured setting with this name, it must be ok
			return true;
		}
	};
}());

// Shorcut for things that look like this:
//          something.click(function () { return false; });
// May also look like this:
//          something.click(False);
function False() {
	"use strict";
	return false;
}

// Shorcut for things that look like this:
//          something.click(function () { return true; });
// May also look like this:
//          something.click(True);
function True() {
	"use strict";
	return true;
}



// sprintf for javascript
// "Hello {0}, welcome to {1}".format("User", "this example");
String.prototype.format = function () {
	"use strict";
	var pattern = /\{\d+\}/g,
		args = arguments;
	return this.replace(pattern, function (capture) {
		return args[capture.match(/\d+/)];
	});
};

// is Numeric function
function isNumber(n) {
	"use strict";
	return !isNaN(parseFloat(n)) && isFinite(n);
}


Number.prototype.formatMoney = function (c, d, t) {
	"use strict";
	var n = this,
		s,
		i,
		j;
	c = isNaN(c = Math.abs(c)) ? 2 : c;
	d = d == undefined ? "." : d;
	t = t == undefined ? "," : t;
	s = n < 0 ? "-" : "";
	i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "";
	j = (j = i.length) > 3 ? j % 3 : 0;
	return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
};

function ATGResponse(object) {
	"use strict";
	if (typeof object === "object" && object.hasOwnProperty("atgResponse")) {
		return JSON.parse(object.atgResponse);
	}
	return {};
}

function CostColumnToggler(o) {
	"use strict";
	this.options = (typeof o === "object") ? o : {};

	var self = $(this),
		form = this.options.form,
		baseURL = "/rest/bean/autozone/pro/service/rest/UserService/";

	if (!form) {
		throw "Feed me a form";
	}

	var colors = ['red', 'blue'],
		colorIndex = 0;

	var toggleColumn = function (button, urlFragment, methodName) {
		var url = [baseURL, urlFragment, '/'].join(''),
			//tables = button.closest('body').find('table.item-list-table, table.totals-header-table, table.totals-for-quote-table, table.category-section-totals');
			selectors = [
				'table.item-list-table',
				'table.totals-header-table',
				'table.totals-for-quote-table',
				'table.category-section-totals',
				'table.order-history-detail-table'
			],
			tables = $(selectors.join(','));

		/*
		// Add a failsafe catch-all if tables is empty
		if (tables.length === 0) {
			//tables = button.closest('body').find('table.item-list-table, table.totals-header-table, table.totals-for-quote-table');
			tables = $('table.item-list-table, table.totals-header-table, table.totals-for-quote-table');
		}
		*/

		tables[methodName]('hide-cost-column');

		// Invert the show function to show the "show cost" column button
		if (methodName === "addClass") {
			methodName = "removeClass";
		} else {
			methodName = "addClass";
		}

		tables.find('span.show-hide-button.show')[methodName]('show-hide-element-hidden');




		// Let the server know about the new preference to show/hide the column
		$.ajax({
			type: 'POST',
			url: url,
			data: {'restful': 1},
			success: function (response) {

			},
			error: function (xhr) {
				console.dir(xhr);
			}
		});

		return false;
	};

	form.find('table thead span.show-hide-button.hide, table tbody span.show-hide-button.hide').live('click', function () {
		// Omniture
		omniture.st({events: 'event10'});
		// end Omniture
		Log.info('hide cost column');
		return toggleColumn($(this), 'hideCostColumn', 'addClass');
	});
	form.find('table thead span.show-hide-button.show, table tbody span.show-hide-button.show').live('click', function () {
		// Omniture
		omniture.st({events: 'event11'});
		// end Omniture
		Log.info('show cost column');
		return toggleColumn($(this), 'showCostColumn', 'removeClass');
	});
}

function QuoteSearcher(dataTable) {
	"use strict";
	this.dataTable = dataTable;

	var self = $(this),
		fakeSearchBox = $('#search-orders-value'),
		fakeGrayGoButton = $('#search-orders-button-gray'),
		fakeOrangeGoButton = $('#search-orders-button-orange'),
		fakeGrayResetButton = $('#search-orders-reset-button-gray'),
		realBox = $('#quote-table_filter input:text');

	if (fakeSearchBox.length === 0
			|| fakeGrayGoButton.length === 0
			|| fakeOrangeGoButton.length === 0
			|| fakeGrayResetButton.length === 0
			|| realBox.length === 0) {
		alert("Missing a required element to search quotes");
	}
	var originalValue = fakeSearchBox.val(),
		makeFormSubmittable = function () {
			$.each([fakeGrayGoButton], function () {
				$(this).hide();
			});
			$.each([fakeOrangeGoButton], function () {
				$(this).show();
			});
		},
		makeFormNotSubmittable = function () {
			$.each([fakeGrayGoButton], function () {
				$(this).show();
			});
			$.each([fakeOrangeGoButton], function () {
				$(this).hide();
			});
		},
		resetForm = function () {
			makeFormNotSubmittable();
			fakeSearchBox.val(originalValue);
		};

	fakeOrangeGoButton.click(function (e) {
		e.preventDefault();
		realBox.val(fakeSearchBox.val());
		realBox.triggerHandler("keyup");
		fakeGrayResetButton.show();
	});


	fakeSearchBox.focus(function () {
		$(this).val("");
	}).keyup(function (e) {
		if ($(this).val().length > 0) {
			makeFormSubmittable();
			if (e.keyCode === 13) {
				fakeOrangeGoButton.click();
			}
		} else {
			makeFormNotSubmittable();
		}
	}).blur(function () {
		if ($(this).val().match(/\s+/)) {
			$(this).val(originalValue);
		}
	});

	fakeGrayResetButton.click(function (e) {
		e.preventDefault();
		resetForm();
		realBox.val('').triggerHandler("keyup");
		fakeGrayResetButton.hide();
	});

}

function ProductDetailOverlay(link, options) {
	"use strict";
	this.link = link;
	this.options = (typeof options === "object") ? options : {};

	var self = $(this),
		id = link.attr('id'),
		params = id.split(':|:'),
		html,
		data,
		selector = '#product-detail',
		after = this.options.after;

	if (after) {
		if (typeOf(after) !== "array") {
			after = [after];
		}
	} else {
		after = [];
	}


	$(selector).remove();

	data = {
		skuId: params[0],
		prodId: params[1],
		id: QueryString.get('id'),
		skuType: params[4],
		productName: params[5]
	};

	$.get('/search/productDetailOverlay.jsp', data, function (response) {
		html = $('<div>').attr('id', 'product-detail').html(response);
		html.dialog({
			autoOpen: true,
			dialogClass: 'modal-wrapper',
			width: 760,
			height: 703,
			modal: true,
			draggable: false,
			resizable: false,
			title: 'Product Detail'
		});
		//omniture.getProducts("azpro:product details");
		omniture.loadPage("azpro:product details");
		// Show/hide cost function, if it has been supplied
		var form = $('#addToQuoteOverlayForm');
		setTimeout(function () {
			new CostColumnToggler({form: form});
		}, 1000);

		// Functionality for detail and enlarged thumbs
		$("div.thumb").click(function () {
			var smallThumb, largeThumb, resultChild, resultURL;
			// Reset active thumbnails and add active class to current image
			$("div.thumb").each(function () {
				$(this).removeClass("active");
			});

			$(this).addClass('active');

			if ($(this).hasClass('detailed')) {
				smallThumb = ($(this).attr("id").slice(10));
				$("#enlarge_pic" + smallThumb).addClass("active");
			} else {
				largeThumb = ($(this).attr("id").slice(11));
				$("#detail_pic" + largeThumb).addClass("active");
			}

			// Get URL of image to be loaded
			resultChild = $(this).children();
			resultURL = (resultChild).attr("src");

			// Slice and Load new url for large and small image
			$("#detail-image").attr("src", (resultURL.slice(0, -2) + "2/"));
			$("#enlarged-image").attr("src", (resultURL.slice(0, -2) + "8/"));
		});

		// Prepare links for swapping between details and enlarged
		$("#link-enlarge").click(function () {
			$("#show-enlarged").show();
			$("#show-details").hide();
			$("#product-detail").css('height', '873px');
			// Omniture
			//omniture.getProducts("azpro:product details:enlarge image");
			omniture.loadPage("azpro:product details:enlarge image");
			// end Omniture
		});

		$(".back-to-details").click(function () {
			$("#show-enlarged").hide();
			$("#show-details").show();
			$("#product-detail").css('height', '703px');
		});

		// Prepare data for printing
		$(".print-data").click(function () {
			var printResult = $(this).parents('div.print-results');
			$(printResult).print();
			// Omniture
			//omniture.getProducts("azpro:product details:print");
			omniture.loadPage("azpro:product details:print");
			// end Omniture
			return false;
		});


		$("#overlay-show").click(function () {
			hideColumn();
			// Omniture
			omniture.st({events: 'event11'});
			// end Omniture
		});

		$("#overlay-hide").click(function () {
			showColumn();
			// Omniture
			omniture.st({events: 'event10'});
			// end Omniture
		});

		// Form submit listener
		html.find('form').submit(function () {
			var input = $(this).find('input.json'),
				json = JSON.parse(input.val());
			return false;
		});
	});




	return {
		remove: function () {
			html.remove();

		}
	};
}



function SimplePaginator(node, o) {
	"use strict";
	if (!node) {
		throw "SimplePaginator: {node: HTMLElement} must be specified.";
	}


	this.node = node;
	this.options = o || {};

	var maxItemsPerView = this.options.maxItemsPerView || 7,
		afterPaginating = this.options.afterPaginating,
		paginator = $(this),
		table = node.find('table:first'),
		tbody = table.find('tbody:first'),
		tbodies = table.find('tbody'),
		useTbodies = (tbodies.length > 1),
		originalTbody = tbody.clone(true),
		rows = tbody.find('tr'),
		display = node.find('div.pagination:first'),
		status = display.find('div.pagination-status:first'),
		oneOf = status.find('span:eq(0)'),
		ofTen = status.find('span:eq(1)'),
		ofAll = status.find('span:eq(2)'),
		pager = display.find('div.pagination-page:first'),
		links = display.find('div.pagination-links:first'),
		pageOneOf = pager.find('select:first'),
		ofPages = pager.find('span:last'),
		testMode = (typeOf(QueryString.get("test"))  === "string"),
		curtain = this.options.curtain,
		i,
		j,

		// Utility functions to aid in paginating things
		util = {

			// Gets the total number of pages for this result set.
			getTotalPages: function () {
				var selector = ":not(.filtered-out)",
					collection = (useTbodies) ? tbodies : rows;

				return Math.ceil(collection.filter(selector).length / maxItemsPerView);
			},

			// Returns all rows, visible or not.
			getAllItems: function () {
				return (useTbodies) ? tbodies : rows;
			},

			// Returns all rows that have not been filtered out. This is more useful than getAllItems.
			getItems: function () {
				var selector = ":not(.filtered-out)";
				if (useTbodies) {
					return tbodies.filter(selector);
				}
				return rows.filter(selector);
			},

			// Returns the length of all rows, visible or not.
			getTotalItems: function () {
				return (useTbodies) ? tbodies.length : rows.length;
			},

			// Returns the index of the first visible row.
			getFirstVisibleIndex: function () {
				var item = this.getFirstVisibleItem(),
					selector = (useTbodies) ? "tbody" : "tr";
				return item.parent().children(selector).index(item);
			},

			// Returns the first visible item.
			getFirstVisibleItem: function () {
				var selector = ':not(.paged-out, .filtered-out):first',
					collection = (useTbodies) ? tbodies : rows;

				return collection.filter(selector);
			},

			// Returns the index of the last visible item.
			getLastVisibleIndex: function () {
				var item = this.getLastVisibleItem();
				return item.parent().children().index(item);
			},

			// Returns the last visible item.
			getLastVisibleItem: function () {
				var selector = ':not(.paged-out, .filtered-out):last',
					collection = (useTbodies) ? tbodies : rows;

				return collection.filter(selector);
			},

			// Returns a collection of all visible items.
			getVisibleItems: function () {
				var selector = ":not(.paged-out, .filtered-out)",
					collection = (useTbodies) ? tbodies : rows;

				var a = collection.filter(selector);

				return collection.filter(selector);
			},

			getUnfilteredItems: function () {
				var selector = ":not(.filtered-out)",
					collection = (useTbodies) ? tbodies : rows;
				return collection.filter(selector);
			},

			// Returns the current page number.
			getCurrentPage: function () {
				var first = this.getFirstVisibleItem(),
					index = first.parent().children().index(first);

				return Math.floor((index / maxItemsPerView) + 1);
			},

			// Determines whether there are more pages to show after this one.
			hasMorePages: function () {
				var lastVisible = this.getLastVisibleItem(),
					index = this.getLastVisibleIndex(),
					siblings = lastVisible.siblings(),
					morePages = [];

				siblings.each(function (i) {
					var sibling = $(this);
					if (i > index && !sibling.hasClass('filtered-out')) {
						morePages.push(sibling);
					}
				});

				return morePages.length > 0;
			},

			// Determines whether there are previous pages to show prior to this one.
			hasPreviousPages: function () {
				var firstVisible = this.getFirstVisibleItem(),
					index = this.getFirstVisibleIndex(),
					siblings = firstVisible.siblings(),
					morePages = [];

				siblings.each(function (i) {
					var sibling = $(this);
					if (i < index && !sibling.hasClass('filtered-out')) {
						morePages.push(sibling);
					}
				});

				return morePages.length > 0;
			},

			// Show the next page.
			showNextPage: function () {
				var pivot = this.getLastVisibleItem(),
					index = 0;

				if (useTbodies) {
					index = pivot.parent().children('tbody').index(pivot);
					tbodies = table.find('tbody');

					//Log.info("Filtering out items with an index less than " + (index + 1));
					tbodies.filter([':lt(', index + 1, ')'].join('')).addClass('paged-out');
					tbodies.filter(function (i) {
						if (i > index) { // Only consider the tbodies that are after the previous pivot point
							return (!$(this).hasClass('filtered-out'));
						}
					}).slice(0, maxItemsPerView).removeClass('paged-out');
				} else {
					index = pivot.parent().children('tr').index(pivot);
					rows.filter([':lt(', index + 1, ')'].join('')).addClass('paged-out');
					rows.filter(function (i) {
						if (i > index) { // Only consider the rows that are after the previous pivot point
							return (!$(this).hasClass('filtered-out'));
						}
					}).slice(0, maxItemsPerView).removeClass('paged-out');
				}
				paginator.triggerHandler("updateDisplay");
			},

			// Show the previous page.
			showPreviousPage: function () {
				var pivot = this.getFirstVisibleItem(),
					index = 0;

				if (useTbodies) {
					index = pivot.parent().children('tbody').index(pivot);
					tbodies.filter([':gt(', index - 1, ')'].join('')).addClass('paged-out');
					tbodies.filter(function (i) {
						if (i < index) {
							return (!$(this).hasClass('filtered-out'));
						}
					}).slice(-maxItemsPerView).removeClass('paged-out');
				} else {
					index = pivot.parent().children('tr').index(pivot);
					rows.filter([':gt(', index - 1, ')'].join('')).addClass('paged-out');
					rows.filter(function (i) {
						if (i < index) {
							return (!$(this).hasClass('filtered-out'));
						}
					}).slice(-maxItemsPerView).removeClass('paged-out');
				}
				paginator.triggerHandler("updateDisplay");
			},

			// Shows a specific page based on the first visible <tr> index.
			showPage: function (index) {
				if (useTbodies) {
					tbodies.addClass('paged-out');
					tbodies.filter([':lt(', index, ')'].join('')).addClass('paged-out');
					tbodies.filter(function (i) {
						if (i >= index) { // Only consider the rows that are after the previous pivot point
							return (!$(this).hasClass('filtered-out'));
						}
					}).slice(0, maxItemsPerView).removeClass('paged-out');
				} else {
					rows.addClass('paged-out');
					rows.filter([':lt(', index, ')'].join('')).addClass('paged-out');
					rows.filter(function (i) {
						if (i >= index) { // Only consider the rows that are after the previous pivot point
							return (!$(this).hasClass('filtered-out'));
						}
					}).slice(0, maxItemsPerView).removeClass('paged-out');
				}
				paginator.triggerHandler("updateDisplay");
			}
		},

		// Event handler to call when selecting a page number from the dropdown.
		handleDropdownChange = function () {
			var select = $(this),
				page = select.val(),

				// This is just an algebraic form of the same equation used to determine which is the current page.
				index = (page - 1) * maxItemsPerView;


			util.showPage(index);
			return false;
		},

		// Event handler for clicking 'prev' or 'next' on the paginator.
		handleLinkClick = function (e) {
			e.preventDefault();

			var link = $(this),
				index = link.parent().children().index(link); // Find out which link was clicked

			if (index > 0) { // You clicked the 'next' link
				if (util.hasMorePages()) {
					util.showNextPage();
				} else {
					console.warn("There are no further pages.");
				}
			} else { // You clicked the 'prev' link
				if (util.hasPreviousPages()) {
					util.showPreviousPage();
				} else {
					Log.info("There are no previous pages.");
				}

			}
			return false;
		},
		// Event handler for clicking 'Reset All' on the product filter.
		handleResetAll = function () {
			var link = $(this);

			return false;
		},

		// Sets things to 1 and other default values
		initializeDisplay = function () {
			var i = 1,
				j,
				totalPages = util.getTotalPages();
			// display defaults
			oneOf.text('1');
			ofTen.text(util.getVisibleItems().length);
			ofAll.text(util.getItems().length);
			ofPages.text(totalPages);
			pageOneOf.empty();
			for (i = 1; i <= totalPages; i += 1) {
				pageOneOf.append($('<option>').val(i).text(i));
			}

			// Show the prev/next links if there is more than one page.
			if (totalPages > 1) {
				links.show();
			}

			// Attach event handlers to the dropdown and the prev/next links
			pageOneOf.bind('change', handleDropdownChange);
			links.find('a').bind('click', handleLinkClick);

			if (afterPaginating.length > 0) {
				for (i = 0, j = afterPaginating.length; i < j; i += 1) {
					afterPaginating[i].apply(paginator);
				}
			}

		},

		// Event handler to update the pagination display area.
		updateDisplay = function () {
			paginator.triggerHandler("hide");
			var item1 = util.getFirstVisibleIndex() + 1,
				totalPages = util.getTotalPages(),
				i = 1,
				j = 0,
				unfilteredItems = util.getUnfilteredItems();

			// Where is the first visible item in the collection of unfiltered items?
			var firstVisible = unfilteredItems.filter(':not(.paged-out):first'),
				firstVisibleIndex = unfilteredItems.index(firstVisible) + 1,
				lastVisible = unfilteredItems.filter(':visible:last'),
				lastVisibleIndex = unfilteredItems.index(lastVisible) + 1;

			oneOf.text(firstVisibleIndex);
			ofTen.text(lastVisibleIndex);
			ofAll.text(util.getItems().length);
			ofPages.text(totalPages);
			pageOneOf.empty();
			for (i = 1; i <= totalPages; i += 1) {
				pageOneOf.append($('<option>').val(i).text(i));
			}

			pageOneOf.val(Math.floor(firstVisibleIndex / maxItemsPerView) + 1);

			paginator.triggerHandler("show");

			if (afterPaginating.length > 0) {
				for (i = 0, j = afterPaginating.length; i < j; i += 1) {
					afterPaginating[i].apply(paginator);
				}
			}

		},

		// Event handler to slice the table up into visible rows and rows that have a class of .paged-out, which are invisible.
		paginate = function () {
			if (useTbodies) {
				// Hide all rows beyond the first page
				table.find(['tbody:not(.filtered-out):gt(', maxItemsPerView - 1, ')'].join('')).addClass('paged-out');
			} else {
				// Hide all rows beyond the first page
				tbody.find(['tr:not(.filtered-out):gt(', maxItemsPerView - 1, ')'].join('')).addClass('paged-out');
			}
			// Update the paginator's display area
			paginator.triggerHandler('initializeDisplay');
		},

		// Event handler to slice the table up into visible rows and those that have been .filtered-out. The remainder are then .paged-out.
		repaginate = function () {
			if (useTbodies) {
				tbodies = table.find('tbody');
				tbodies.removeClass('paged-out');
			} else {
				rows = tbody.find('tr');
				rows.removeClass('paged-out');
			}
			paginator.triggerHandler('paginate');
		},

		// Reset the display
		reset = function () {
			if (!useTbodies) {
				tbody.replaceWith(originalTbody);
				tbody = table.find('tbody:first');
				originalTbody = tbody.clone(true);
				rows = tbody.find('tr');
			}
			paginator.triggerHandler("paginate");
			return false;
		},

		hide = function () {
			if (!useTbodies) {
				if (curtain) {
					//Log.info("Using curtain to hide content.");
					curtain.hide();
				} else {
					//Log.info("Hiding tbody");
					tbody.hide();
				}
			}
		},

		show = function () {
			if (!useTbodies) {
				if (curtain) {
					//Log.info("Using curtain to show content.");
					curtain.show();
				} else {
					//Log.info("Showing tbody");
					tbody.show();
				}
			}
		};

	if (typeOf(afterPaginating) !== "array") {
		if (afterPaginating) {
			afterPaginating = [afterPaginating];
		} else {
			afterPaginating = [];
		}

	}


	if (afterPaginating) {
		for (i = 0, j = afterPaginating.length; i < j; i += 1) {
			if (typeof afterPaginating[i] !== "function") {
				console.error("afterPaginating[{0}] must be a function type, but it is a {1} type".format(i, typeOf(afterPaginating[i])));
			}
		}
	}

	// Bind events to the paginator object;
	paginator.events({
		paginate: paginate,
		repaginate: repaginate,
		updateDisplay: updateDisplay,
		initializeDisplay: initializeDisplay,
		reset: reset,
		hide: hide,
		show: show
	});

	// Run immediately.
	(function () {
		if (testMode) {
			util.testMode();
		}
		paginator.triggerHandler("paginate");
	}());
}

// A function that can make the browser look busy.
//
// Call pause(f) to make the browser show a "wait" cursor pointer. Optionally pass a function f to run after the icon has
// been changed.
// Call unpause() to remove the busy indicator.
function PauseIndicator(node) {
	"use strict";
	node = node || $('body:first');
	var className = 'pause';

	node.removeClass(className);

	return {
		pause: function (after) {
			node.addClass(className);
			if (after && typeof after === "function") {
				after();
			}
		},
		unpause: function () {
			node.removeClass(className);
		}
	};
}

function ArgumentMap(arg) {
	"use strict";
	var object = {},
		array = [],
		string = '',
		type = typeof arg,
		i,
		j,
		k;

	if (type === "string") {
		array = arg.split('&');
		for (i = 0, j = array.length; i < j; i += 1) {
			var chunks = array[i].split('=');
			for (k in chunks) {
				object[k] = chunks[k];
			}
		}

	} else if (type === "object") {
		for (i in arg) {
			object[i] = arg[i];
			array.push([i, arg[i]].join('='));
		}
		string = array.join('&');
	}
	return {
		get: function (key) {
			return object[key];
		},
		toString: function () {
			return string;
		}
	};
}

var StringUtils = (function () {
	"use strict";
	// A quick lookup of stored key values.
	var cache = {
		age: new Date(),
		words: {}
	},

		// The max age of the cache in milliseconds. After this age it should be discarded.
		maxAge = 100,

		// Return the cache object to its original state.
		resetCache = function () {
			cache = {
				age: new Date(),
				words: {}
			};
		},

		// Returns a formatted word from the cache based on the inbound string key, or false if the key was not found.
		// checkCache("myStringValue") will return either "My String Value" or false.
		checkCache = function (str) {
			var date = new Date(),
				val;
			if ((date.getTime() - cache.age.getTime()) > maxAge) {
				resetCache();
			}
			val = cache.words[str];
			return (typeOf(val) !== "undefined") ? val : false;
		};

	return {

		// Turns a camelCasedString into a Camel Cased String if the camelCasedString is longer than 0 characters.
		deCamelCase: function (str) {
			if (str.length > 0) {
				var word = null,
					string = [str.substring(0, 1).toUpperCase(), str.substring(1)].join(''),
					a = string.split(''),
					buffer = [],
					words = [],
					len = a.length,
					A9 = /[A-Z1-9]/,
					label = "",
					i = 0;

				// See if the word is in the cache.
				if ((word = checkCache(str)) !== false) {
					//Log.info("Found [{0}: {1}] in the cache.".format(str, word));
					return word;
				}


				if (len > 0) {

					for (i = 0; i < len; i += 1) {
						if (a[i].match(A9)) {
							// Write out the current buffer to the words array.
							words.push(buffer.join(''));
							buffer = [];
						}
						buffer.push(a[i]);
					}
					words.push(buffer.join(''));
					label = $.trim(words.join(" "));
					// Store the input string for faster lookups
					cache.words[str] = label;
					return label;
				}
			}
			return str;
		}
	};
}());

var BrowserUtils = (function () {
	"use strict";
	var screenWidth,
		screenHeight,
		isStandardsBasedScreenDimensions;

	isStandardsBasedScreenDimensions = (function () {
		if (typeof window.innerWidth !== "undefined") { // Standards
			screenWidth = window.innerWidth;
			screenHeight = window.innerHeight;
		} else if (typeof document.documentElement !== "undefined" && typeof document.documentElement.clientWidth !== "undefined" && document.documentElement.clientWidth !== 0) {
			screenWidth = document.documentElement.clientWidth;
			screenHeight = document.documentElement.clientHeight;
		} else { // Old IE
			screenWidth = document.getElementsByTagName('body')[0].clientWidth;
			screenHeight = document.getElementsByTagName('body')[0].clientHeight;
		}
	}());

	return {
		getScreenWidth: function () {
			return screenWidth;
		},
		getScreenHeight: function () {
			return screenHeight;
		}
	};
}());

// This block will add custom extensions to jQuery. It runs in an anonymous function that runs immediately.
(function ($) {
	"use strict";
	// Get/set the id attribute of a node.
	$.fn.ident = function (id) {
		if (id) {
			this.attr('id', id);
			return this;
		} else {
			return this.attr('id');
		}
	};

	// Returns a boolean that indicates whether or not a node is present. Optionally runs another function if the
	// node does exist.
	$.fn.exists = function (func) {
		if (this.length > 0 && typeof func === "function") {
			func(this);
			return this;
		}
		return this.length > 0;
	};

	// Enables a form element.
	$.fn.enable = function () {
		return this.each(function () {
			this.disabled = false;
		});
	};

	// Disables a form element.
	$.fn.disable = function () {
		return this.each(function () {
			this.disabled = true;
		});
	};

	// Marks a checkbox or radio button.
	$.fn.check = function () {
		return this.each(function () {
			this.checked = true;
		});
	};

	// Unmarks a checkbox or radio button.
	$.fn.uncheck = function () {
		return this.each(function () {
			this.checked = false;
		});
	};

	// Inverts a checkbox or radio button's marked state. If it was checked, it will now be unchecked.
	$.fn.toggleCheck = function () {
		return this.each(function () {
			this.checked = !this.checked;
		});
	};

	// Gets the action attribute value from a form.
	$.fn.getURL = function () {
		if (this.attr('nodeName').toLowerCase() === 'form') {
			return this.attr('action');
		}
	};

	// Gets the href attribute value from an anchor.
	$.fn.href = function () {
		if (this.attr('nodeName').toLowerCase() === 'a') {
			return this.attr('href');
		}
	};

	// Gets the node name of an element in lowercase.
	$.fn.nodeName = function () {
		return this[0].nodeName.toLowerCase();
	};

	$.fn.nodeNameIs = function (nodeName, func) {
		if (this.nodeName() === nodeName && typeOf(func) === 'function') {
			func();
		}
	};

	$.fn.highlight = function () {
		this.css({
			border: '5px solid red'
		});
	};

	/*
	if (!$.browser.msie) {
		jQuery.fn.bind = function (bind) {
			return function () {
				console.count("jquery bind count");
				console.log("jquery bind %o", this);
				return bind.apply(this, arguments);
			};
		}(jQuery.fn.bind);
	}
	*/


	$.extend({
		// Turns "This SENTENCE sure is INTERESTING!" into "thissentencesureisinteresting!". Useful for string comparisons.
		squashString: function (s) {
			return $.trim(['', s].join('')).toLowerCase().replace(/\s/g, '');
		},
		pack: function (a) {
			if (typeOf(a) === "array") {
				return a.join('');
			}
			return a;
		},
		reloadWindow: function () {
			var path = window.location.pathname,
				href,
				search = window.location.search,
				hash = window.location.hash;
			if (path.substring(0, 1) !== '/') {
				path = ['/', path].join('');
			}
			if (search.length > 0) {
				//search = [search, ['reload', new Date().getTime()].join('=')].join('&');
				href = [path, search].join('');
			} else {
				href = path;
			}
			//Log.debug("Reloading window to {0}".format(href));
			window.location.reload(href);
			return false;
		},
		guid: function (seed) {
			var a = [],
				i,
				j;
			seed = seed || new Date().getTime();
			function S4() {
				return (((1 + Math.random(seed)) * 0x10000) | 0).toString(16).substring(1);
			}
			for (i = 0, j = 6; i < j; i += 1) {
				switch (i) {
				case 0:
					a.push(S4());
					a.push(S4());
					break;
				case 1:
				case 2:
				case 3:
				case 4:
					a.push('-');
					a.push(S4());
					break;
				default:
					a.push(S4());
					a.push(S4());
					a.push(S4());
				}
			}
			return a.join('');
		},
		number: function (input) {
			var type = typeof input,
				string;
			if (type === "string") {
				string = input;
			} else if (type === "object" && input.length) {
				string = input.text();
			}
			return Number($.trim(string));
		}
	});

	$.fn.events = function (obj) {
		var i;
		for (i in obj) {
			this.bind(i, obj[i]);
		}
		return this;
	};


}(jQuery)); // These extensions are now available to any following jquery code.

// Douglas Crockford's typeOf function
function typeOf(value) {
	"use strict";
	var s = typeof value;
	if (s === 'object') {
		if (value) {
			if (value instanceof Array) {
				s = 'array';
			}
		} else {
			s = 'null';
		}
	}
	return s;
}

/**
 * Pick out individual parameters in a query string.
 *
 * URL: http://www.com?id=1&name=Fred
 * Script: QueryString.get("name") ==> "Fred"
 */
var QueryString = (function () {
	'use strict';
	return {
		get: function (key, url) {
			key = key.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
			var regexS = "[\\?&]" + key + "=([^&#]*)",
				regex = new RegExp(regexS),
				results = null,
				search = null;

			if (url) {
				search = url.split('?');
				if (search.length > 1) {
					results = regex.exec(['?', search[1]].join(''));
				}
			} else {
				results = regex.exec(window.location.search);
			}
			if (results && typeof results === 'object' && results.length > 1) {
				return results[1];
			}
		},
		append: function (url, key, val) {
			var str = [key, val].join('=');
			if (url.indexOf('?') > -1) {
				url = [url, str].join('&');
			} else {
				url = [url, str].join('?');
			}
			return url;
		},
		update: function (url, key, value) {
			if (!QueryString.get(key)) {
				return QueryString.append(url, key, value);
			} else {
				key = key.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
				var regexS = key + "=([^&#]*)",
					regex = new RegExp(regexS),
					results = null;
				if (url) {
					url = url.replace(regex, [key, value].join('='));
				}
				return url;
			}
		}
	};
}());

var GUID = function (seed) {
	seed = seed || new Date().getTime();
	function S4() {
		return (((1 + Math.random(seed)) * 0x10000)|0).toString(16).substring(1);
	}
	var a = [];
	for (var i = 0, j = 6; i < j; i += 1) {
		switch (i) {
			case 0:
				a.push(S4());
				a.push(S4());
				break;
			case 1:
			case 2:
			case 3:
			case 4:
				a.push('-');
				a.push(S4());
				break;
			default:
				a.push(S4());
				a.push(S4());
				a.push(S4());
		}
	}
	return a.join('');
};

var Log = (function () {

	if (typeof console !== 'undefined' && !$.browser.msie) {
		return {
			group: function (s) { console.group(s); },
			groupEnd: function (s) { console.groupEnd(s); },
			debug: function (s) { console.debug(s); },
			warn: function (s) { console.warn(s); },
			dir: function (o) { console.dir(o); },
			dirxml: function (o)  { console.dirxml(o); },
			error: function (s) { console.error(s); },
			info: function (s) { console.info(s); },
			log:function (s) { console.log(s); },
			time: function (s) { console.time(s); },
			timeEnd: function (s) { console.timeEnd(s); }
		};
	} else {
		return {
			group: function (s) {},
			groupEnd: function (s) {},
			dirxml: function (s) {},
			debug: function (s) {},
			warn: function (s) {},
			dir: function (s) {},
			error: function (s) {},
			info: function (s) {},
			log: function (s) {},
			time: function (s) {},
			timeEnd: function (s) {}

		};
	}
}());

if (!window.console || !console.firebug) {
	var names = [
			'log',
			'debug',
			'info',
			'warn',
			'error',
			'assert',
			'dir',
			'dirxml',
			'group',
			'groupEnd',
			'time',
			'timeEnd',
			'count',
			'trace',
			'profile',
			'profileEnd'
	];
	window.console = {};
	for (var i = names.length - 1; i > -1; i--) {
		window.console[names[i]] = function () {};
	}
}



var Form = (function () {
	return {
		serialize: function (form, responseFormat) {
			var array = [], obj = {};

			form.find(':input').each(function () {
				var input = $(this),
					name = input.attr('name'),
					chunks = [],
					val = '',
					obj = {};

				if (name.match(/_/)) {
					return;
				}
				chunks = name.split(/\./);
				chunks.shift();
				if (chunks.length > 1) {
					chunks[0] = [chunks[0], '.'].join('');
				}
				name = chunks.join('');
				//name = name.split(/\./)[1];
				val = input.val();
				obj = {
					'name': name,
					'value': val
				};
				array.push(obj);
			});

			responseFormat = (responseFormat === null) ? 'json' : responseFormat;
			obj = {
				'name': 'format',
				'value': responseFormat

			};
			array.push(obj);
			return array;
		},

		clean: function (form) {
			// Get rid of the inputs whose name starts with a _ character.
			form.find(':input[name^=_]').each(function () {
				$(this).remove();
			});
		},

		// Finds the first <ul class="error-area"> within a form. If it is not there then it will be created and prepended
		// as the first item in the form. It is then cleared out.
		clearErrors: function (form) {
			var list = form.find('.error-area:first');
			if (!list) {
				list = $('<ul class="error-area">');
				form.prepend(list);
			}
			list.empty();
		},

		// finds the first <ul class="error-area"> within a form. If it is not there then it will be created and prepended
		// as the first item in the form. Then the error message is appended to the list.
		addError: function (form, error) {
			var list = form.find('.error-area:first'),
				li;
			if (!list) {
				list = $('<ul class="error-area">');
				form.prepend(list);
			}
			li = $(['<li>', error, '</li>'].join(''));
			list.append(li);
		}
	};
}());

function TableSorter(node, o) {
	this.name = "TableSorter";
	Log.time(this.name);
	this.node = node;
	this.options = o || {};

	//Log.debug("This sorter's node id is {0}".format(node.attr('id')));

	var self = this,
		paginator = this.options.paginator,
		filter = this.options.filter,
		validator = this.options.validator,
		sorter = $(this),
		useCustomTextExtraction = (typeOf(this.options.customTextExtraction) === "object"),
		cell,
		expressions,

		handleLinkClick = function () {
			var link = $(this),

				isAscending = function () {
					// Note that we reverse the data field because we're catching it mid-click
					if (this.parents('tr').find('a').hasClass('descending')) {
						this.data('asc', true);
					} else if (this.parents('tr').find('a').hasClass('ascending')) {
						this.data('asc', false);
					}
					return this.data('asc');
				},
				flip = function () {
					var val = !this.data('asc');
					this.data('asc', val);
					this.parents('tr').find('a').removeClass('descending ascending');
					this.addClass((val) ? 'descending' : 'ascending');
				},
				sortAscending = function (a, b) {
					if (typeof a.key === "string" && typeof b.key === "string") {
						a = a.key.toLowerCase();
						b = b.key.toLowerCase();
					} else if (typeof a.key === "number" && typeof b.key === "number") {
						a = a.key;
						b = b.key;
					}

					if (a < b) {
						return 1;
					}
					if (a > b) {
						return -1;
					}
					return 0;
				},
				sortDescending = function (a, b) {
					if (typeof a.key === "string" && typeof b.key === "string") {
						a = a.key.toLowerCase();
						b = b.key.toLowerCase();
					} else if (typeof a.key === "number" && typeof b.key === "number") {
						a = a.key;
						b = b.key;
					}

					if (a > b) {
						return 1;
					}
					if (a < b) {
						return -1;
					}
					return 0;
				},
				getTextValue = function (n, useTbodies) {
					var index = n.parents(':first').find(n.nodeName()).index(n);
					if (useCustomTextExtraction && typeOf(self.options.customTextExtraction[index]) === "function") {
						return self.options.customTextExtraction[index].apply(n);
					}
					return $.squashString(n.text());
				};

			if (!link.hasClass('sortable')) {
				return false;
			}

			// Get all prices if this is the availability, list, or cost col
			cell = link.closest('th');
			expressions = /^(availability|list|cost)(.*?)$/i;

			if (cell.attr('class').match(expressions)) {
				//Log.info("Cell class matches expressions that should trigger getting all prices");
				var p = $(paginator);
				p.triggerHandler("hide");
				p.triggerHandler("getPrices", ['getAllPrices']);
				p.triggerHandler("show");
			}




			var index = link.closest('tr').find('a').index(link),
				array = [],
				sortedArray = [],
				table = link.closest('table'),
				tbodies = table.find('tbody'),
				useTbodies = tbodies.length > 1,
				sortFunction = (isAscending.apply(link) ? sortAscending : sortDescending);

			if (useTbodies) {
				tbodies.each(function (i, tbody) {
					$(tbody).find('tr:first').each(function (i, row) {
						row = $(row);
						row.find('td').eq(index).each(function (i, cell) {
							array.push({
								key: getTextValue($(cell), useTbodies),
								tbody: tbody
							});
						});
					});
				});
				array.sort(sortFunction);
				flip.apply(link);

				table.find('tbody').remove();
				$.each(array, function (i, obj) {
					table.append(obj.tbody);
				});
			} else {
				var tbody = tbodies; // This branch only needs one tbody, so rename it to be a bit clearer
				tbody.find('tr').each(function (i) {
					var row = $(this);
					row.find('td').eq(index).each(function (j, cell) {
						array.push({
							key: getTextValue($(cell), useTbodies),
							row: row
						});
					});
				});
				array.sort(sortFunction);
				flip.apply(link);
				tbody.empty();

				$.each(array, function (i, obj) {
					tbody.append(obj.row);
				});
			}
			sorter.triggerHandler("repaginate");
			sorter.triggerHandler("refresh");
			sorter.triggerHandler("reprice");

			return false;
		},

		// Event handler to repaginate the interface. This will only work if the new TableSorter object has been assigned
		// a ProductPaginator object in its options object.
		repaginate = function () {
			//Log.info("TableSorter.paginate[{0}] calling local productPaginator.paginate[{1}]".format(self.node, 'dip'));
			$(paginator).triggerHandler("repaginate");
		},

		refresh = function () {
			// validator is not a jquery object and does not support event handling
			if (validator != null) {
				validator.refresh();
			}
		},

		reprice = function () {
			$(paginator).triggerHandler("getPrices");
		},

		setup = function () {
			 this.find('thead th a').bind('click', handleLinkClick).removeClass('ascending descending').data('asc', false);
		};

	sorter.events({
		repaginate: repaginate,
		refresh: refresh,
		reprice: reprice
	});

	if (!node) {
		throw "You must specify a start node from which to sort tables.";
	}

	(function () {
		if (node.nodeName() === "table" && node.hasClass("sortable")) {
			setup.apply(node);
		} else {
			node.find('table.sortable').each(function (i, table) {
				setup.apply($(table));
			});
		}

		if (o.defaults && o.defaults.columnIndex) {
			var dir = 'ascending';
			if (o.defaults.dir) {
				dir = (o.defaults.dir === "asc") ? "descending" : "ascending";
			}
			node.find('th:eq(' + o.defaults.columnIndex + ') a').addClass(dir);
		}
	}());
	Log.timeEnd(this.name);
}

function LazyImageLoader(node, o) {
	this.node = node;
	this.firstRun = (typeof this.firstRun === "undefined") ? true : false;

	var self = this,
		loader = $(this),
		options = (typeOf(o) === "object") ? o : {},
		targetSelector = 'tr.product-row:visible',
		selector = '',
		attributes = options.attributes || {},
		loadImages = function () {
			if (this.firstRun) {
				// Only load 10 images or so on the first run
				selector = [targetSelector, ':lt(10)'].join('');
				this.firstRun = false;
			} else {
				selector = targetSelector;
				Log.debug("Lazy image loader has already been run at least once for this current view");
			}
			// Only find rows that do not have images that have already been lazily loaded
			var nodes = self.node.find(selector).filter(':not(.lazy-image-loaded)');
			Log.info("Loading images for {0} visible rows".format(nodes.length));
			nodes.each(function () {
				var row = $(this),
					input = row.find('input.lazy-image-load'), // Find the input in this row that has the src value for the image
					width = (typeof attributes.width === "number") ? attributes.width : 70,
					height = (typeof attributes.height === "number") ? attributes.height : 70,
					img = new Image(width, height);

				img.src = input.val();
				img.row = row;
				row.find('.product-image:first').append(img).end().addClass('lazy-image-loaded');

				/*
				img.onload = function () {
					Log.info("Adding lazy-image-loaded to {0}".format(img.src));
					this.row.find('.product-image:first').append(this).end().addClass('lazy-image-loaded');
				};
				*/
			});
		},
		constructor = function () {
			loader.triggerHandler("loadImages");
		};

	loader.events({
		loadImages: loadImages
	});

	setTimeout(constructor, 10000);

	return {
		reload: function () {
			//Log.info("Reloading lazy images");
			loader.triggerHandler("loadImages");
		}
	};
}

/**
 * logs a user out of the site if the customer file account is not setup.
 * @return
 */
function logoutUser() {
	$("#logoutForm").submit();
}

$(window).load(function () {

	/**
	 * Function needed to set user's current vehicle from the vehicle select box
	 */
	$("select#current-vehicle-select").change(function () {

		$("input#set-current-vehicle-submit").click();

	});


	if($('input#password-txt').length > 0){// element exists
		if($('input#password-txt').val().length > 0){ // has value
			$('input#password-txt').css({opacity:1});
		}
		$('input#password-txt').focus(function (e) {
			$(this).fadeTo('slow', 1);
		});
		$('input#password-txt').blur(function (e) {
			if($(this).val().length === 0){
				$(this).fadeTo('slow', .5);
			}
		});
	}
	if($('input#username-txt').length > 0){
		$('input#username-txt').val('User name');
		$('input#username-txt').focus(function (e) {
			if ($("input.validate-username").val() === 'User name') {
				$('input.validate-username').val('');
			}
		});
		$('input#username-txt').blur(function (e) {
			if ($("input.validate-username").val() === '') {
				$('input.validate-username').val('User name');
			}
		});
	}
	$("#loginForm input").bind("keydown", function (e) {
		if (e.keyCode === 13) {
			$('#btn-go').click();
			if ($.browser.msie) {
				return false;
			}
		}
	});

	$("#searchForm input").bind("keydown", function (e) {
		if (e.keyCode === 13) {
			$('#search-btn-go').click();
			if ($.browser.msie) {
				return false;
			}
		}
	});

	$("#decoder").bind("keydown", function (e) {
		if ($("#decoder").val().length >= 17) {
			if (e.keyCode === 13) {
				return ymme.lookupVIN();
			}
		} else {
			if (e.keyCode === 13) {
				return false;
			}
		}
	});
	/*
	 * Set focus on brands when loading the brand page
	 */
	$("#alpha-strip a.link").each(function (){
		$(this).attr('href',$(this).attr('href')+'#alpha-strip');
	});
});

function setErrorCSS(property) {
	var $ = jQuery;
	$('#' + property).addClass('error');
}

// ATG won't accept a form with an <input type="image"> in it if the request query string doesn't contain X/Y
// coordinates of the mouse click.
// This takes any name of a button and adds hidden inputs with fake data.
var ATGImageInputs = (function () {
	return {
		addXYPair: function (input) {
			var form = input.closest('form');
			$.each(['x', 'y'], function (i, ch) {
				var builder = ['<input type="hidden" name="', input.attr('name'), '.', ch, '" value="1" />'].join('');
				form.append($(builder));
			});
		}
	};
}());

(function ($) {

	Core.requireModules = function (modules, callback) {

		if (typeOf(modules) !== "array") {
			modules = [modules];
		}

		var modulesWanted = modules.length,
			library = {
				modulesLoaded: 0
			};

		$.each(modules, function (i, moduleName) {
			moduleName = ['/js/modules/', moduleName, '.js'].join('');
			$.getScript(moduleName, function () {
				library.modulesLoaded += 1;
				if (modulesWanted === library.modulesLoaded) {
					if (typeof callback === "function") {
						callback();
					}
				}
			});
		});
	};


var ChangeActiveShopFilter = function (form) {
	this.form = form;
		if (!this._i) {
			this.validate = function () {
				// Form logic
				//if (window.location.href.match(/manageJobs/)) {
					//return false;
				//}
				return true;
			};

			this.showNotice = function () {
				var form = this.form;
				$('#dialog-exit-create-manage-jobs').each(function () {
					$(this).data("form", form);
					$(this).dialog('open');

				});//END OF EACH FUNCTION
			}; //END showNotice
			this._i = 1;
		}
	};


	$(window).load(function ()  {

		// This is a bucket of functions that will be run if certain names or conditions are present on a page.
		// See FormLoader
		var Loader = (function () {
			return {
				// Submits the form in the header when the active shop dropdown changes.
				selectShopForm: function (form) {
					// disable form in manageJobs directory
					//if (window.location.href.match(/manageJobs/)) {
					//	form.find('select').attr('disabled','disabled');
					//}
					form.find('select').change(function () {
						var filter = new ChangeActiveShopFilter(form);
						if (filter.validate()) {
							// Omniture and form submission. Record the event, then submit the form.
							//omniture.st({events: 'event14'});
							form.submit();
						} else {
							filter.showNotice();
						}
					});
				},

				// Store form field values for this form in case of server-side error such as not passing a
				// password integrity rule.
				addUserForm: function (form) {
					var cookieName = 'addUserForm';

					// cache object contains a json representation of the form. It's either in a cookie or an empty map.
					var cache = $.cookies.get(cookieName);
					if (!cache) {
						cache = {};
					}

					// This will be true if a form was submitted and there was an error.
					var hasErrors = form.find('.error-message').length > 0;
					if (hasErrors) {
						// fill the form fields with the value stored in the cache.
						$.each(cache, function (k, v) {
							var id = ['#', k].join('');
							form.find(id).val(v);
						});
					} else {
						$.cookies.set(cookieName, null);
					}

					// Store each form field as part of a json object.
					form.submit(function () {
						$(this).find(':text').each(function () {
							var id = $(this).ident();
							cache[id] = $(this).val();
						});
						$.cookies.set(cookieName, cache);
					});
				},

				logoutForm: function (form) {

					var doLogout = function () {
						$('form#logoutForm').each(function () {
							Log.info("Logging out.");
							$(this).submit();
						});
					};

					// Incercept clicks to the logout button and determine on the server whether or not a
					// confirmation message needs to be shown informing the user that he can save his
					// quote or not.
					form.find('#btnLogout').click(function () {
						var p = new PauseIndicator();
						p.pause();

						$.ajax({
							type: 'GET',
							url: '/rest/bean/autozone/pro/service/rest/LogoutInterceptor/message/',
							data: {},
							success: function (response) {
								try {
									// ATG does not return a properly quoted JSON string, so parse the important part again on the next line
									var message = JSON.parse(response.message);

									if (message.hasUnsavedItems === true) {
										// Show a dialog informing the user that he can save his quote before actually logging out.
										var dialog = $('#dialog-logout-intercept-unsaved-items');
										if (dialog.length > 0) {
											dialog.dialog("open");
										}
									} else {
										// It's okay to log out.
									 // Make sure we don't log the user out if in jobs
										if (!window.location.href.match("/manageJobs/")) {
											doLogout();
										}

									}
								} catch (e) {
									// Response isn't JSON; assume that it's okay to log out. There's nothing else to do.
									//Prevent user from automatically logging out from jobs when Window presented modally
									if (!window.location.href.match("/manageJobs/")) {
										doLogout();
									}
								}
							},
							error: function (xhr) {

							}
						});
						return false;
					});
				}
			};
		}()),

		// This function iterates across each form on the page. It attempts to find a named function in the Loader
		// function that matches the form iteration's id. If it's there and it's a function, then it will be run.
		FormLoader = function () {
			$('form').each(function () {
				var form = $(this);
				var id = form.attr('id');
				if (typeof Loader[id] === 'function') {
					Loader[id](form);
				}
			});
		},

		// A list of functions that should be run at each page load.
		functions = [
				FormLoader
		];

		// Run each function.
		$.each(functions, function () {
			this();
		});
	});
}(jQuery)); // Run immediately.

/* If a link with btn-back class exists reload previous page */
$(document).ready(function (){
	$('a.btn-back').live('click',function () {
		history.back(-1);
		return false;
	});
});

