// prevent background image flicker in IE
try {
	document.execCommand("BackgroundImageCache", false, true);
} catch(err) {}

$(document).ready(function() {
	var start = new Date();
	
	// insert top shadow div
	$("#wrapper").before('<div id="shadow-top"></div>').css("marginTop", "0px");
	
	highlightNav = function(p) {
		$(p).addClass("on");
		$(p).parents("li").addClass("open");
		$(p).filter(":has(ul)").addClass("open");
	}

	// expand nav
	if($("body#prod-detail, body#brand").size()) {
		// product detail and brand pages: match brand ID on query string with brand ID in nav to highlight
		$("#nav a").not("[@href$='#']").each(function() {
			var h = this.href.toLowerCase();
			if(h.indexOf("brand=" + query.brand) != -1 && h.indexOf("cat=" + query.cat) != -1) {
				highlightNav($(this).parent());
			}
		});
	} else {
		// other pages: match page URL with left nav URL to highlight
		$("#nav a").not("[@href$='#']").each(function() {
			if(location.href.toLowerCase() == this.href.toLowerCase()) {
				highlightNav($(this).parent());
			}
		});
	}
	
	// set up level 2 nav expand/collapse
	var n = $("#nav a[@href$='#']");
	n.click(function() {$(this).parent().toggleClass("open"); this.blur(); return false;});
	n.focus(function() {window.status=" "; return true;});
	n.mouseover(function() {window.status=" ";return true;});
	
	// insert text sizer
	$("#search-global").after('<p id="text-sizer">text size <a href="#" id="font-small" title="small text">A</a> | <a href="#" id="font-medium" title="medium text">A</a> | <a href="#" id="font-large" title="large text">A</a></p>');
	$("#font-small").click(function(){fontSize('small'); this.blur(); return false;});
	$("#font-medium").click(function(){fontSize('medium'); this.blur(); return false;});
	$("#font-large").click(function(){fontSize('large'); this.blur(); return false;});
	
	// insert print link
	if(!$("#recipe-detail").size() && window.print) $("#tell-friend").after('<p id="print-page"><a href="#" onclick="window.print(); return false;">print this page</a></p>');
	
	// style related recipes list
	$("#related-recipes li:last-child").addClass("last");
	
	// style promotions list
	$("#promotion-list h2:first-child").addClass("first");
	
	// new css buttons
	$('.btn').each(function(){
		var b = $(this);
		var tt = b.html() || b.val();
		if ($(':submit,:button',this).length) {
			b = $('<a>').insertAfter(this). addClass(this.className).attr('id',this.id);
			$(this).remove();
		}
		b.html('<i></i><span>' + tt + '<i></i><span></span></span>').css({cursor:'pointer'});
		//b.html('').prepend('<i></i>').append($('<span>').html(tt).append('<i></i><span></span>'));
	});
	
	// init add to recipe box widget (wrapped in a function so we can call again when paging through search results)
	initAddRecipeBox = function() {
		$(".add-recipe a").bind("click", function() {
			var me = $(this);
				try {
					$.ajax({
						url: me.attr("href"),
						type: "GET",
						success: function(req) {
							if(req.trim() == 'true') {
								me.before("In your recipe box");
								$(me).parent().toggleClass("add-recipe-on");
								me.remove();
								monitorAjax("AJAX:Recipe Box - Add");
							} else {
								ajaxError();
							}
						},
						error: ajaxError
					});
				} catch(err) {ajaxError(err)}
				this.blur();
				return false;
		});
	};
	
	initAddRecipeBox();
	
	// init remove from recipe box widget
	$(".remove-recipe a").bind("click", function() {
		this.blur();
		$(this).parents("tr").children("td").css("background", "#ff9");
		if(window.confirm("Are you sure you want to remove this recipe?")) {
			var me = $(this);
			try {
				$.ajax({
					url: me.attr("href"),
					type: "GET",
					success: function(req) {
						if(req.trim() == 'true') {
							$(me).parents("tr").hide().remove();
							// if we removed the last recipe, show the empty box message
							if(!$("#table-recipe-box tbody tr").size()) {
								$("#recipe-box-empty").show();
								$("#table-recipe-box").hide();
							}
							monitorAjax("AJAX:Recipe Box - Remove");
						} else {
							ajaxError();
						}
					},
					error: ajaxError
				});
			} catch(err) {ajaxError(err)}
		} else {
			$(this).parents("tr").children("td").css("background", "#fff");
		}
		return false;
	});
	
	// hook up tab nav events
	bindSearchTabs = function() {
		$("#tabs a").unbind().bind("click", function() {
			this.blur();
			var cat = this.id.split("-");
			$("#tabs a").removeClass("on");
			$("#tab-" + cat[1]).addClass("on");
			$("div.results").hide();
			$("#results_" + cat[1]).show();
			return false;
		});
		$("#tabs").removeClass("disabled");
	}
	
	initSearchResults = function() {
		// style search results tables
		$("#search-results th:first").addClass("first");
		$("#search-results th:last").addClass("last");
		$("#search-results tbody tr").hover(function() {
			$(this).addClass("over");
		}, function() {
			$(this).removeClass("over");
		}).bind("click", function() {
			location.href = $(this).find("a")[0].href;
		});
		
		// add AJAX calls for next/previous
		$("p.search-nav a").each(function() {
			$(this).bind("click", function() {
				// disable the tabs while search content is loading
				$("#tabs a").unbind().bind("click", function() {return false;});
				var tabs = $("#tabs").addClass("disabled");
				var loading = $("#loading");
				loading.show();
				var href = $(this).attr("href");
				var container = $(this).parents("div.results");
				container.fadeTo(250, 0.01, function() {container.load(href, function() {
						container.fadeTo(250, 1.0, function() {
							loading.hide();
							bindSearchTabs();
						});
				//added for browser back functionality on advanced search pages only
						if (!tabs.size()) {
							dhtmlHistory.add(escape(href));
							currentLocation = href;
					}
				//
						initSearchResults();
						initAddRecipeBox();
					});
				});
				window.scrollTo(0, $("#search-results").offset().top);
				return false;
			});
		});
	}
	
	// search results page?
	if($("body#search, body#recipe-search").size()) {
		if (!$("#tabs").size()) {
			// initialize the DHTML History framework
			// on the advanced search pages only
			dhtmlHistory.initialize();
			
			historyChange = function(newLocation, historyData) {
				//try{console.log("cur: " + currentLocation); console.log("new: " + newLocation);} catch(err){};
				if(newLocation && newLocation != currentLocation) {
					$("#ajax-results").load(unescape(newLocation), function() {
						initSearchResults();
						initAddRecipeBox();
					});
				}
			};
			
			// subscribe to DHTML history change
			// events
			dhtmlHistory.addListener(historyChange);
			
			//added for browser back functionality
			// add a history entry if we're on page one of the results
			var href = $(".search-nav a");
			if (location.href.indexOf("#http") == -1 && href.size()) {
				href = href[0].href;
				href = href.replace(/page=2/, "page=1");
			dhtmlHistory.add(escape(href));
			var currentLocation = href;
			//try{console.log("cur: " + currentLocation); console.log("new: " + newLocation);} catch(err){};
		} else {
			var currentLocation = "";
		}
		}
		
		// init search results
		initSearchResults();
		// set up tabs on general search page
		var cat = query.cat || "general"; // show general tab by default
		$("#tabs").show();
		$("#tab-" + cat).addClass("on");
		$("#results_" + cat).show();
		bindSearchTabs();
	}
	
	// clean up promotion detail content
	try {
		$("#content-detail div.para > li").wrap("<ul></ul>");
	} catch(err) {}
	
	// style site map
	$("#content-sitemap > ul > li > a").append("<span>&nbsp;&raquo;</span>").addClass("first");
	$("#content-sitemap a[@href$='#']").each(function() {
		var h = $(this).html();
		$(this).before(h);
		$(this).remove();
	});
	
	// activate selected size style sheet
	var cookie = readCookie("kcomStyles");
	var title = cookie || "small";
	createCookie("kcomStyles", title, 365);
 	setActiveStyleSheet(title);
	
	// init form validation
	if($("form.validate").size()) initFormValidation();
	
	//alert(new Date() - start);
});

ajaxError = function(req) {
	//monitorAjax("Error");
	alert("Sorry, the server was unable to process your request. Please try again.");
	//alert(req);
}

goToSite = function() {
	var u = $("#selSites")[0].value;
	if(u) window.open(u);
	return false;
}

// sidebar featured content object
var rotator = {
	init: function(options) {
		rotator.current = 0;
		rotator.loaded = -1;
		rotator.animating = false;
		rotator.paused = false;
		rotator.container = options.container;
		rotator.content = options.content;
		rotator.elements = new Array();
		rotator.last = rotator.content.length - 1;
		rotator.delay = options.delay || 5000;
		rotator.fade = options.fade || 1000;
		rotator.textPrev = options.textPrev || "&laquo; prev";
		rotator.textNext = options.textNext || "next &raquo;";
		rotator.imagePrev = options.imagePrev || "";
		rotator.imageNext = options.imageNext || "";
		
		// remove original banner
		$(rotator.container).find("a").remove();
		
		//load all banners
		$.each(rotator.content, function() {
			var a = $("<a></a>").appendTo(rotator.container).attr("href", rotator.stripEntities(this.url));
			if(this.url.indexOf("http") > -1) {
				a.attr("target", "_blank");
			}
			a.css("position", "absolute").hide(); // removed title because of unwanted mouseout events when cursor touches tooltip in FF .attr("title", this.alt)
			rotator.elements.push(a);
			$("<img>").appendTo(a).load(rotator.check).attr("src", this.image); // removed title because of unwanted mouseout events when cursor touches tooltip in IE .attr("alt", this.alt)
		});
	},
	
	check: function() {
		rotator.loaded += 1;
		if(rotator.loaded == rotator.last) {
			rotator.insertNav();
			rotator.start();
		}
	},
	
	insertNav: function() {
		var p = $("<p>").insertAfter(rotator.container);
		// prev link
		var a = $('<a id="rotator-prev"></a>').appendTo(p).attr("href", "#").click(function() {
			this.blur();
			if(rotator.animating) rotator.stop();
			rotator.prev();
			return false;
		});
		if(rotator.imagePrev) {
			$("<img>").appendTo(a).attr("src", rotator.imagePrev);
		} else {
			a.html(rotator.textPrev)
		}
		// next link
		var a = $('<a id="rotator-next"></a>').appendTo(p).attr("href", "#").click(function() {
			this.blur();
			if(rotator.animating) rotator.stop();
			rotator.next();
			return false;
		});
		if(rotator.imageNext) {
			$("<img>").appendTo(a).attr("src", rotator.imageNext);
		} else {
			a.html(rotator.textNext)
		}
	},
	
	prev: function() {
		$(rotator.elements[rotator.current]).fadeOut(rotator.fade);
		rotator.current = rotator.current==0 ? rotator.last : rotator.current-1;
		$(rotator.elements[rotator.current]).fadeIn(rotator.fade);
	},
	
	next: function() {
		$(rotator.elements[rotator.current]).fadeOut(rotator.fade);
		rotator.current = rotator.current==rotator.last ? 0 : rotator.current+1;
		$(rotator.elements[rotator.current]).fadeIn(rotator.fade);
	},
	
	pause: function (e) {
		if (!rotator.animating || rotator.paused) return;
		rotator.paused = true;
		window.clearInterval(rotator.timer);
	},
	
	resume: function (e) {
		if (!rotator.paused || !rotator.animating) return;
		rotator.paused = false;
		rotator.animating = true;
		rotator.timer = window.setInterval(rotator.next, rotator.delay);
		rotator.next();
	},
	
	start: function() {
		$(rotator.elements[rotator.current]).show();
		rotator.animating = true;
		rotator.timer = window.setInterval(rotator.next, rotator.delay);
	},
	
	stop: function(e) {
		rotator.animating = false;
		window.clearInterval(rotator.timer);
	},
	
	stripEntities: function(str) {
		str = str.replace(/&amp;/g, "&");
		str = str.replace(/&gt;/g, ">");
		return str;
	}
};

// handle missing images
imageMissing = function(i) {
	if (!i.src.match(/www2\.kelloggs\.com/i)) {
		// look for image on production server
		i.src = i.src.replace(/\/[^\/]+\//, "/www2.kelloggs.com/");
	} else {
		// can't find the image anywhere
		i.src = "/images/image_not_available.gif";
	}
}

// utility functions
////////////////////////////////////////

setActiveStyleSheet = function(title) {
	if(document.getElementById && document.createTextNode) {
		var i, a;
		for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
			if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
			 	a.disabled = true;
				if(a.getAttribute("title") == title) a.disabled = false;
			}
		}
		$("#text-sizer").find("a").each(function() {$(this).removeClass("on");});
		$("#font-" + title).addClass("on");
	}
}

fontSize = function(fs) {
	createCookie("kcomStyles", fs, 365);
	setActiveStyleSheet(fs);
}

createCookie = function(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

readCookie = function(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

parseQuery = function() {
	var returnVals = new Array();
	qString = new String(window.location);
	var queryStart = qString.indexOf('?');
	if (queryStart==-1) {
		return returnVals;
	}
	var query = qString.substring(queryStart + 1, qString.length);
	var parts = query.split("&");
	for (var i=0; i<parts.length; i++) {
		bits = parts[i].split("=");
		if(bits[1]) {
			subbits = bits[1].split("#"); // added by T.D. to handle fragment identifier in URL
			returnVals[bits[0].toLowerCase()] = bits[1]; // query[] indexes are now lowercase!
		}
	}
	return returnVals;
}

var query = parseQuery();

// validation prototypes
////////////////////////////////////////

String.prototype.trim = function () {
	return this.replace(/^\s+|\s+$/g, "");
}

String.prototype.isEmpty = function() {
	return ((this == null) || (this.length == 0) || /^\s+$/.test(this));
}

String.prototype.isProfane = function() {
	var badwords = ["69", "666", "ahole", "anal", "anarchist", "anarchists", "anarchy", "anus", "aryan", "aryans", "ash0le", "ash0les", "asholes", "ass", "ass hoe", "ass lick", "Ass Monkey", "asses", "Assface", "assh0le", "assh0lez", "asshole", "assholes", "assholz", "asskisser", "asswipe", "azzhole", "babe", "babes", "baby batter", "balls", "banging", "bangle", "bassterds", "bastard", "Bastard", "bastards", "bastardz", "basterds", "basterdz", "beaner", "beastial", "beastiality", "beastility", "beaver", "beer", "belly whacker", "bestial", "bestiality", "Biatch", "bible fucker", "bitch", "bitcher", "bitchers", "bitches", "bitchin", "bitching", "Blow Job", "blow job", "blowjob", "blowjobs", "blumpkin", "boffing", "bonehead", "boner", "boob", "box", "brain banger", "breasted", "breasts", "brown eye", "browneye", "browntown", "bucket cunt", "buff", "bugger", "bukakke", "bull dyke", "bull shit", "bullshit", "bum", "bung hole", "butch", "butt", "butt breath", "butt fucker", "butt hair", "butt head", "buttface", "buttfuck", "buttfucker", "butthead", "butthole", "buttpicker", "butts", "buttwipe", "byotch", "c0ck", "c0cks", "c0k", "camel hump", "camel jockey", "camel toe", "cannabis", "carpet muncher", "Carpet Muncher", "cawk", "cawks", "chicken head", "chink", "christ", "cigs", "circle jerk", "circumcise", "clam", "cleveland steamer", "Clit", "clit", "clit clitoris", "cnts", "cntz", "cobia", "cock", "cock sucker", "cockhead", "cock-head", "cockpenis", "cocks", "cocksuck", "cocksucked", "CockSucker", "cocksucker", "cock-sucker", "cocksucking", "cocksucks", "coon", "cootch", "cooter", "cornhole", "crack", "crap", "cum", "cummer", "cumming", "cums", "cumshot", "cunilingus", "cunillingus", "cunnilingus", "cunt", "cuntlick", "cuntlicker", "cuntlicking", "cunts", "cuntvagina", "cuntz", "cyberfuc", "cyberfuck", "cyberfucked", "cyberfucker", "cyberfuckers", "cyberfucking", "damn", "damnation", "darkie", "dead", "dick", "dickhead", "dickpenis", "died", "dik", "dike", "dild0", "dild0s", "dildo", "dildos", "dilld0", "dilld0s", "dingleberry", "dink", "dinks", "dipshit", "dirty", "Dirty Sanchez", "dominatricks", "dominatrics", "dominatrix", "dong", "donkey punch", "douche", "douche bag", "dumbass", "dune coon", "dutch oven", "dyke", "ejaculate", "ejaculated", "ejaculates", "ejaculating", "ejaculatings", "ejaculation", "enema", "enemas", "f u c k", "f u c k e r", "fag", "fag1t", "faget", "fagg1t", "fagget", "fagging", "faggit", "faggot", "faggs", "fagit", "fagot", "fagots", "fags", "fagz", "faig", "faigs", "fantasies", "fart", "farted", "farting", "fartings", "farts", "farty", "fatass", "fatso", "felatio", "fellatio", "fetish", "fingerfuck", "fingerfucked", "fingerfucker", "fingerfuckers", "fingerfucking", "fingerfucks", "fist", "fist fuck", "fistfuck", "fistfucked", "fistfucker", "fistfuckers", "fistfucking", "fistfuckings", "fistfucks", "flagellate", "flesh", "flipping the bird", "frigid", "f u c k", "f.u.c.k.", "fuck", "fuck stick", "fucked", "fucker", "fuckers", "fuckin", "fucking", "fuckings", "fuckme", "fucks", "fudge packer", "Fudge Packer", "fuk", "Fukah", "Fuken", "fuker", "Fukin", "Fukk", "Fukkah", "Fukken", "Fukker", "Fukkin", "fuks", "furburger", "g00k", "gangbang", "gangbanged", "gangbangs", "gash", "gay", "gayboy", "gaygirl", "gays", "gaysex", "gayz", "gazongers", "geisha", "giz", "goatse", "goddamn", "God-damned", "gonads", "gook", "gringo", "guinne", "gun", "guns", "h00r", "h0ar", "h0re", "hard on", "hardcoresex", "hash", "hells", "hiv", "hoar", "homo", "honky", "hooker", "hoor", "hoore", "horniest", "horny", "hot carl", "hotsex", "hussy", "hustler", "hymen", "jack off", "jackass", "jacking off", "jackoff", "jack-off", "jap", "japs", "jerk", "jerkoff", "jerk-off", "jesus", "jesus christ", "jew", "jews", "jiggaboo", "jisim", "jism", "jiss", "jiz", "jizm", "jizz", "jugs", "jungle bunny", "kike", "kill", "killer", "killing", "kinky", "kkk", "klan", "klux", "knives", "knob", "knobs", "knobz", "kock", "kondum", "kondums", "kraut", "kum", "kummer", "kumming", "kums", "kunilingus", "kunt", "kunts", "kuntz", "latex", "Lesbian", "lesbian", "lesbians", "lesbo", "Lezzian", "lingerie", "Lipshits", "Lipshitz", "loser", "love mayo", "lsd", "lust", "lustful", "lusting", "lusty", "mace", "madame", "mafia", "marijuana", "masochist", "masokist", "massterbait", "masstrbait", "masstrbate", "masterbaiter", "masterbate", "masterbates", "masturbate", "masturbating", "Masturbation", "masturbation", "merde", "mistress", "money shot", "moon cricket", "moose knuckle", "Motha Fucker", "Motha Fuker", "Motha Fukkah", "Motha Fukker", "mothafuck", "mothafucka", "mothafuckas", "mothafuckaz", "mothafucked", "mothafucker", "mothafuckers", "mothafuckin", "mothafucking", "mothafuckings", "mothafucks", "mother fucker", "Mother Fucker", "Mother Fukah", "Mother Fuker", "Mother Fukkah", "Mother Fukker", "motherfuck", "motherfucked", "motherfucker", "mother-fucker", "motherfuckers", "motherfuckin", "motherfucking", "motherfuckings", "motherfucks", "mound", "muff", "muff diving", "munitions", "murder", "murderer", "Mutha Fucker", "Mutha Fukah", "Mutha Fuker", "Mutha Fukkah", "Mutha Fukker", "mutilation", "n1gr", "naked", "nakedness", "nastt", "nasty", "naughty", "nazi", "nazis", "negligee", "nerd", "nigga", "nigger", "nigger", "niggers", "nigur", "niiger", "niigr", "nipple", "nob", "nobhead", "nude", "nudity", "nymph", "orafis", "orgasim", "orgasim", "orgasims", "orgasm", "orgasms", "orgasum", "oriface", "orifice", "orifiss", "packi", "packie", "packy", "paki", "pakie", "paky", "panties", "panty", "papist", "pcp", "pecker", "peeenus", "peeenusss", "peenus", "peinus", "pen1s", "penas", "penetration", "penis", "penis-breath", "penises", "penus", "penuus", "perforate the colon", "pervert", "perverted", "phonesex", "Phuc", "Phuck", "Phuk", "phuk", "phuked", "Phuker", "phuking", "phukked", "Phukker", "phukking", "phuks", "phuq", "pimp", "pink sock", "piss", "pissed", "pisser", "pissers", "pisses", "pissin", "pissing", "pissoff", "playmate", "playmates", "polac", "polack", "polak", "Poonani", "Poonanni", "poontang", "porch monkey", "porn", "porno", "pornography", "pornos", "pr1c", "pr1ck", "pr1k", "prairie nigger", "prick", "prickpenis", "pricks", "prostitute", "punk", "puss", "pusse", "pussee", "pussies", "pussy", "pussys", "puuke", "puuker", "queef", "queer", "queers", "queerz", "quickie", "qweers", "qweerz", "qweir", "raghead", "rape", "recktum", "rectum", "rectus", "retard", "rifle", "rifles", "rim job", "rogue", "rum", "rusty trombone", "sadist", "sand nigger", "satan", "satanism", "scank", "schlong", "screw", "screwing", "semen", "sensual", "sensuous", "sex", "sexual", "sexuality", "sexually", "sexy", "Sh!t", "sh1t", "sh1ter", "sh1ts", "sh1tter", "sh1tz", "sheister", "shit", "shit face", "shited", "shitfeces", "shitfull", "shiting", "shitings", "shits", "shitted", "shitter", "shitters", "shitting", "shittings", "Shitty", "shitty", "Shity", "shitz", "shocker", "Shyt", "Shyte", "Shytty", "Shyty", "skanck", "skank", "skankee", "skankey", "skanks", "Skanky", "skeet", "skin flute", "slag", "slant", "slave", "slaves", "slay", "slayer", "sleaze", "slut", "slutprostitute", "sluts", "Slutty", "slutz", "smack", "smut", "snatch", "snowball", "snuff", "son-of-a-bitch", "spank", "spank the monkey", "spanked", "spanking", "Spaz", "sperm", "spic", "spik", "spunk", "strip", "strippers", "striptease", "studs", "suck", "sucker", "sucking", "suicide", "supremacy", "swinger", "swingers", "taint", "taste the waste", "teabagging", "testicle", "testicles", "thc", "tip drill", "tit", "titbreast", "tits", "toss the salad", "towel head", "turd", "twat", "twot", "underwear", "va1jina", "vag1na", "vagiina", "vagina", "vaginas", "vaj1na", "vajina", "vart", "virginity", "virgins", "vullva", "vulva", "w0p", "wanker", "wench", "wenches", "wetback", "Wetback", "wh00r", "wh0re", "whipped", "whiskey", "White Cracker", "Whitey", "whore", "wine", "witchcraft", "wog", "wop", "xrated", "xxx"];
	var lowerCaseCheck = this.toLowerCase(), bl = badwords.length, me = this, clean = "####################";
	RegExp.multiline = true;
	for(var i=0;i<bl;i++) {
		if(lowerCaseCheck.indexOf(badwords[i]) != -1) {
			me = me.replace(new RegExp("" + badwords[i] + "", "gi"), clean.substring(0, badwords[i].length));
		}
	}
	return me;
}

String.prototype.isEmail = function() {
	return /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(this);
}

String.prototype.isZIP = function() {
	return (/^[0-9]{5}$/.test(this));
}

// validation functions
////////////////////////////////////////

initFormValidation = function() {
	var start = new Date();
	
	var foc; // where to put focus on form load
	
	// hide empty error spans
	$("span.error").each(function(){
		if(this.innerHTML == "") {
			$(this).hide();
		} else {
			// error condition, so place focus on first error field
			if(!foc) {
				foc = $(this).siblings("input")[0];
				if(!foc) foc = $(this).siblings("select")[0];
			}
		}
	});
	
	// add validation handlers to forms
	$("form.validate").submit(function(e) { 
		return validateForm(this);
	});
	
	// set tab index, disable autocomplete
	var tab = 1;
	$("form.validate input, form.validate select, form.validate textarea").each(function() {
		$(this).addClass("tabme");
	});
	$("form.validate .tabme").each(function() {
		if(this.type != "hidden") {
			this.setAttribute("autocomplete", "off");
			this.tabIndex = tab;
			if(tab == 1 && !foc) {
				foc = this;
			}
			tab++;
		}
	});
	
	// show form
	$("form.validate").css("visibility", "visible");
	
	// focus first input or first error input
	if(foc) foc.focus();
	
 //alert(new Date() - start);
}

validateForm = function(f) {
	// validate required fields
	var result = $.map($(f).find(".required").not("span"), function(el) {
		return testField(el, true) ? null : false;
	});
	
	// validate optional fields
	var result2 = $.map($(f).find(".optional"), function(el) {
		return testField(el, false) ? null : false;
	});
	
	if(result[0] == false || result2[0] == false) {
		// focus on first error field
		var errfield = $(".errorfield")[0];
		if(errfield) {
			errfield.focus();
		}
		return false;
	}
	
	return true;
}

testField = function(el, required) {
	var id = el.id;
	
	switch(id) {
		
		case "email":
		case "femail":
			var v = $(el).val();
			var eid = $("#" + id + "_error");
			if(required) {
				if(v.isEmpty()) {
					showErr(el, eid, "Please type an e-mail address.");
					return false;
				}
			}
			if(!v.isEmpty()) {
				if(!v.isEmail()) {
					showErr(el, eid, "Please type an e-mail address in the following format: yourname@example.com");
					return false;
				}
			}
			hideErr(el, eid);
			break;
			
		case "fname":
		case "ffname":
			var v = $(el).val();
			var eid = $("#" + id + "_error");
			if(required) {
				if(v.isEmpty()) {
					showErr(el, eid, "Please enter first name.");
					return false;
				} 
			}
			//if(!v.isEmpty()) {
			//	 var vp = v.isProfane();
			//	 if(v != vp) {
			//		$(el).val(vp);
			//		showErr(el, eid, "Some information may be incorrect or inappropriate. Please try again.");
			//		return false;
			//	}
			//}
			hideErr(el, eid);
			break;
			
		case "message":
			var v = $(el).val();
			var eid = $("#" + id + "_error");
			if(required) {
				if(v.isEmpty()) {
					showErr(el, eid, "Please enter a message.");
					return false;
				} 
			}
			//if(!v.isEmpty()) {
			//	 var vp = v.isProfane();
			//	 if(v != vp) {
			//		$(el).val(vp);
			//		showErr(el, eid, "Some information may be incorrect or inappropriate. Please try again.");
			//		return false;
			//	}
			//}
			hideErr(el, eid);
			break;
			
		case "txtKeyword":
			var v = $(el).val();
			var eid = $("#" + id + "_error");
			if(required) {
				// part of a validation group? (product and promo advanced search)
				if($(el).parents("fieldset.validate-group").size()) {
					if(v.isEmpty()) { // validate the additional fields in the group
						var result = false;
						$(el).parents("fieldset.validate-group").find(".group").each(function() {
							if(testField(this, false)) result = true;
						});
						if(!result) {
							showErr(el, eid, "Please select or enter at least one search criterion.");
							return false;
						}
					}
				} else if(v.isEmpty()) {
					showErr(el, eid, "Keyword is required.");
					return false;
				}
			}
			hideErr(el, eid);
			break;
			
		case "ddlCategories":
		case "ddlBrands":
		case "ddlTypes":
			var v = $(el).val();
			if(v.isEmpty()) {
				return false;
			}
			break;
			
		case "zip":
			var v = $(el).val();
			var eid = $("#" + id + "_error");
			if(required) {
				if(v.isEmpty()) {
					showErr(el, eid, "Please type a ZIP code.");
					return false;
				}
			}
			if(!v.isEmpty()) {
				 if(!v.isZIP()) {
					showErr(el, eid, "Please type a valid 5-digit U.S. ZIP code.");
					return false;
				}
			}
			hideErr(el, eid);
			break;
	}
	return true;
}

hideErr = function(input, el) {
	$(input).removeClass("errorfield");
	el.hide();
	el.html("");
}

showErr = function(input, el, msg) {
	$(input).addClass("errorfield");
	el.hide();
	el.html(msg);
	el.fadeIn(1000);
}

/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 */
/**
 * This returns an object with top, left, width, height, borderLeft,
 * borderTop, marginLeft, marginTop, scrollLeft, scrollTop, 
 * pageXOffset, pageYOffset.
 *
 * The top and left values include the scroll offsets but the
 * scrollLeft and scrollTop properties of the returned object
 * are the combined scroll offets of the parent elements 
 * (not including the window scroll offsets). This is not the
 * same as the element's scrollTop and scrollLeft.
 * 
 * For accurate readings make sure to use pixel values.
 *
 * @name offset	
 * @type Object
 * @param HTMLElement refElement The offset returned will be relative to this elemen.
 * @cat DOM
 * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 */
jQuery.fn.offset = function(refElem) {
	if (!this[0]) throw 'jQuery.fn.offset requires an element.';

	refElem = (refElem) ? jQuery(refElem)[0] : null;
	var x = 0, y = 0, elem = this[0], parent = this[0], sl = 0, st = 0;
	do {
		if (parent.tagName == 'BODY' || parent.tagName == 'HTML') {
			// Safari and IE don't add margin for static and relative
			if ((jQuery.browser.safari || jQuery.browser.msie) && jQuery.css(parent, 'position') != 'absolute') {
				x += parseInt(jQuery.css(parent, 'marginLeft')) || 0;
				y += parseInt(jQuery.css(parent, 'marginTop'))	|| 0;
			}
			break;
		}

		x += parent.offsetLeft || 0;
		y += parent.offsetTop	|| 0;

		// Mozilla and IE do not add the border
		if (jQuery.browser.mozilla || jQuery.browser.msie) {
			x += parseInt(jQuery.css(parent, 'borderLeftWidth')) || 0;
			y += parseInt(jQuery.css(parent, 'borderTopWidth'))	|| 0;
		}

		// Need to get scroll offsets in-between offsetParents
		var op = parent.offsetParent;
		do {
			sl += parent.scrollLeft || 0;
			st += parent.scrollTop	|| 0;
			parent = parent.parentNode;
		} while (parent != op);
	} while (parent);

	if (refElem) {
		var offset = jQuery(refElem).offset();
		x = x - offset.left;
		y = y - offset.top;
		sl = sl - offset.scrollLeft;
		st = st - offset.scrollTop;
	}

	// Safari and Opera do not add the border for the element
	if (jQuery.browser.safari || jQuery.browser.opera) {
		x += parseInt(jQuery.css(elem, 'borderLeftWidth')) || 0;
		y += parseInt(jQuery.css(elem, 'borderTopWidth')) || 0;
	}

	return {
		top: y - st,
		left: x - sl,
		width: elem.offsetWidth,
		height: elem.offsetHeight,
		borderTop:	parseInt(jQuery.css(elem, 'borderTopWidth')) || 0,
		borderLeft: parseInt(jQuery.css(elem, 'borderLeftWidth')) || 0,
		marginTop:	parseInt(jQuery.css(elem, 'marginTopWidth')) || 0,
		marginLeft: parseInt(jQuery.css(elem, 'marginLeftWidth')) || 0,
		scrollTop:	st,
		scrollLeft: sl,
		pageYOffset: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,
		pageXOffset: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0
	};
};