var DHTML = (document.getElementById || document.all || document.layers);
var emptyString = /^\s*$/ ;
var global_valfield;	// retain valfield for timer thread
var invalid_zip = 0;
var nbsp = 160;		// non-breaking space char
var node_text = 3;	// DOM text node-type
var proceed = 2;


function smallwindow(url) {
	window.open(url, '_blank','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,copyhistory=no,width=600,height=800');
}


function trim(str) {
	return str.replace(/^\s+|\s+$/g, '');
}


function trimnondigits(str) {
	return str.replace(/[^\d]+/g, '');
}


function commonCheck(valfield, infofield, required) {
	if(!document.getElementById)
		return true;
	var elem = document.getElementById(infofield);
	if(!elem.firstChild || elem.firstChild.nodeType != node_text)
		return true;
	if(emptyString.test(valfield.value)) {
		if(required) {
			msg(infofield, "error", "(required)");
			valfield.className = 'fielderror';
			return false;
		} else {
			msg(infofield, "warn", "");
			return true;
		}
	}
	return proceed;
}


function validatePresent(valfield, infofield, oldclass) {
	var stat = commonCheck(valfield, infofield, true);
	if(stat != proceed)
		return stat;
	valfield.className = oldclass;
	msg(infofield, "warn", "");
	return true;
}


function validateSelectPresent(valfield, infofield, boxid, oldclass) {
	var elem = document.getElementById(boxid);
	if(emptyString.test(valfield.options[valfield.selectedIndex].value)) {
		elem.className = 'fielderror';
		msg(infofield, "error", "(required)");
		return false;
	} else {
		elem.className = oldclass;
		msg(infofield, "warn", "");
		return true;
	}
}


/** XHConn - Simple XMLHTTP Interface - bfults@gmail.com - 2005-04-08        **
 ** Code licensed under Creative Commons Attribution-ShareAlike License      **
 ** http://creativecommons.org/licenses/by-sa/2.0/                           **/
function XHConn() {
	var xmlhttp, bComplete = false;
	try {
		xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	}
	catch(e) {
		try {
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch(e) {
			try {
				xmlhttp = new XMLHttpRequest();
			}
			catch(e) {
				xmlhttp = false;
			}
		}
	}
	if(!xmlhttp)
		return null;
	this.connect = function(sURL, sMethod, sVars, fnDone,p1, p2, p3) {
		if(!xmlhttp)
			return false;
		bComplete = false;
		sMethod = sMethod.toUpperCase();
		try {
			if(sMethod == "GET") {
				xmlhttp.open(sMethod, sURL+"?"+sVars, true);
				sVars = "";
			} else {
				xmlhttp.open(sMethod, sURL, true);
				xmlhttp.setRequestHeader("Method", "POST "+sURL+" HTTP/1.1");
				xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			}
			xmlhttp.onreadystatechange = function() {
				if(xmlhttp.readyState == 4 && !bComplete) {
					bComplete = true;
					fnDone(xmlhttp, p1, p2, p3);
				}
			};
			xmlhttp.send(sVars);
		}
		catch(z) {
			return false;
		}
		return true;
	};
	return this;
}


function purgeModelTrim(e1, e2) {
	var element = document.getElementById(e1);
	var element2 = document.getElementById(e2);
	element.innerHTML = '<input onblur="validatePresent(this, \'e_model\', \'formtextfield\');" name="ff_model" class="formtextfield" size="30"  type="text" maxlength="255" value=""/>';
	element2.innerHTML = '<input onblur="validatePresent(this, \'e_trim\', \'formtextfield\');" name="ff_submodel" class="formtextfield" size="30"  type="text" maxlength="255" value=""/>';
}


function loadFragmentInToElement(fragment_url, param, element_id) {
	var element = document.getElementById(element_id);
	var theURL = fragment_url;
	var ajaxConn = new XHConn();
	ajaxConn.connect(theURL, "POST", param, processFragment, element_id );
	return false;
}


function processFragment(xmlhttp, element_id) {
	var element = document.getElementById(element_id);
	if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
		element.innerHTML = xmlhttp.responseText;
	} else
		element.innerHTML = '';
}


function sendUrl(url, param) {
	//initialize XHConn (if XHConn isn't created successfully,
	//the client doesnt' support Ajax)
	var ajaxConn = new XHConn();

	//post to mypage.php with args foo and baz
	ajaxConn.connect(url, "POST", param,handleCallback);
}


function handleCallback(receiveReq) {
	if(receiveReq.readyState == 4) {
		if(receiveReq.responseText) {
			var myObject = eval('(' + receiveReq.responseText + ')');
			if(myObject.do_zip) {
				document.getElementById('e_citystate').innerHTML = myObject.zip;
				if(myObject.invalid_zip) {
					invalid_zip = 1;
					validateZip(document.forms[1].ff_zip, 'e_zip', true, '', true);
				} else {
					invalid_zip = 0;
					validateZip(document.forms[1].ff_zip, 'e_zip', true, '', true);
				}
			}
		}
	}
}


function dyn_addDependent() {
	var ni = document.getElementById('dyn_dependents');
	var numi = document.getElementById('ff_depcount');
	var num = (document.getElementById("ff_depcount").value -1)+ 2;
	show2('dyn_heading');
	numi.value = num;
	var divIdName = "dyn_dependents"+num;
	var newdiv = document.createElement('div');
	newdiv.setAttribute("id",divIdName);
	var newbit = dynbit_dependent;
	var bitremove = "<a href=\"javascript:;\" onclick=\"dyn_removeDependent(\'"+divIdName+"\')\">[X]</a>";
	newbit = newbit.replace(/GBGBINDEX/gi, num);
	newbit = newbit.replace(/GBGBREMOVE/gi, bitremove);
	var relation = "Child";
	if(num == 1) {
		relation = "Spouse";
	}
	newbit = newbit.replace(/GBGBRELATIONSHIP/gi, relation);
	newdiv.innerHTML = newbit;
	ni.appendChild(newdiv);
	var anchor = document.getElementById('dyn_addlink');
	anchor.innerHTML = "Add another person";
}


function dyn_removeDependent(divNum) {
	var d = document.getElementById('dyn_dependents');
	var olddiv = document.getElementById(divNum);
	d.removeChild(olddiv);
}


// namespace
var lk;
if(typeof(lk) == 'undefined') {
	lk = {};
}


// Create a function with o (object) and method closures suitable for
// registering callbacks on events.
lk.Callback = function(o, method) {
	return function() {
		return o[method].apply(o, arguments);
	};
}


lk.findNode = function(node, predicate) {
	var n = node;
	for(; n; n = n.parentNode) {
		if(predicate(n)) {
			break;
		}
	}
	return n;
}


lk.getElementXPath = function(node) {
	var path = "";
	for(; node && node.nodeType == 1; node = node.parentNode) {
		var count = 1;
		for(var sibling = node.previousSibling; sibling; sibling = sibling.previousSibling) {
			if(sibling.nodeType == 1 && sibling.tagName == node.tagName) {
				count++
			}
		}
		var rpath = node.tagName;
		if(count > 1) {
			rpath += "[" + count + "]";
		}
		path = "/" + rpath + path;
	}
	return path;
}


lk.getCommonParent = function() {
	if(!arguments.length) {
		return null
	} else if(arguments.length == 1) {
		return arguments[0];
	} else if(arguments.length == 2) {
		// 2 digit counting algorithm exploiting the termination
		// condition that eventually parentNode becomes null
		var node0;
		for(node0 = arguments[0]; node0; node0 = node0.parentNode) {
			if(lk.findNode(arguments[1], function(n1) { var n0 = node0; return n0 == n1; })) {
				break;
			}
		}
		return node0;
	} else {
		var tail = [ lk.getCommonParent(arguments[0], arguments[1]) ];
		for(var i = 2; i < arguments.length; ++i) {
			tail.push(arguments[i]);
		}
		return lk.getCommonParent.apply(this, tail);
	}
}

//opens links in new windows
lk.popup = function() {
	$('a.popup').each(function(i) {
		$(this).click(function() {
			window.open(this.href);
			return false;
		});
	})
};


// Validator plug-in method to show the user result of validation
lk.showFeedback = function(names, success, message) {
	var feedback;

	var rule_controls = {};
	for(var i = 0; i < names.length; ++i) {
		var name_controls = this.controls[names[i]];
		for(var j = 0; j < name_controls.length; ++j) {
			rule_controls[lk.getElementXPath(name_controls[j])] = name_controls[j];
		}
	}

	var controls = [];
	for(i in rule_controls) {
		controls.push(rule_controls[i]);
	}

	feedback = controls.length == 1 ? controls[0] : lk.getCommonParent.apply(this, controls);
	while(feedback.tagName in {'SELECT': 1, 'TBODY': 1, 'TR': 1} || (feedback.type && feedback.type in {'checkbox': 1})) {
		feedback = feedback.parentNode;
	}

	var path = lk.getElementXPath(feedback);
	if(this.classNames[path] == undefined) {
		this.classNames[path] = feedback.className;
	}
	feedback.className = success ? this.classNames[path] : 'fielderror';

	if(message) {
		var span;
		for(var node = feedback; node; node = node.nextSibling) {
			if(node.tagName == 'SPAN') {
				span = node;
				break;
			}
			if(!node.getElementsByTagName) {
				continue;
			}
			var spans = node.getElementsByTagName('SPAN');
			if(spans.length) {
				span = spans[0];
				break;
			}
		}
		if(span) {
			span.className = success ? '' : 'error';
			if(!span.firstChild) {
				var empty = document.createTextNode('');
				span.appendChild(empty);
			}
			span.firstChild.nodeValue = (success ? '' : message);
		}
	}
	return success;
}

// Validator2 plug-in method to show the user result of validation
lk.showFeedback2 = function(names, success, message) {
	var feedback;

	var rule_controls = {};
	for(var i = 0; i < names.length; ++i) {
		var name_controls = this.controls[names[i]];
		for(var j = 0; j < name_controls.length; ++j) {
			rule_controls[lk.getElementXPath(name_controls[j])] = name_controls[j];
		}
	}

	var controls = [];
	for(i in rule_controls) {
		controls.push(rule_controls[i]);
	}

	feedback = controls.length == 1 ? controls[0] : lk.getCommonParent.apply(this, controls);
	while(feedback.tagName in {'SELECT': 1,'INPUT' : 1} || (feedback.type && feedback.type in {'checkbox': 1})) {
		feedback = feedback.parentNode;
	}

	var path = lk.getElementXPath(feedback);
	if(this.classNames[path] == undefined) {
		this.classNames[path] = feedback.className;
	}
	feedback.className = success ? this.classNames[path] : 'fielderror';

	return success;
}


// Validator implements an interface to make it easy to check forms, and
// guide user to fill out forms.
lk.Validator = function(show, name_regex, test_mode) {
	this.show = show;
	this.name_regex = name_regex;
	this.test_mode = !!test_mode;

	// name to controls mapping
	this.controls = {};

	//name to className mapping
	this.classNames = {};

	// name to [names, events, predicate, message] mapping
	this.rules = {};

	// preliminary check on obj first load, but have to wait for dom (and window.onload is too early,
	// and jquery might not be loaded):
	var x = this;
	setTimeout(function(){x.checkAllControls(null, true);}, 2500);
}


// Specific which events the predicate should be considered, and optional
// message on error (when predicate is false).
lk.Validator.prototype.addRule = function(events, predicate, message, form_fields) {
	// support perl regex notation
	predicate = predicate.replace(/\s*=~\s*(\/[^\/]*\/[igm]*)/g, ".search($1) != -1");
	predicate = predicate.replace(/\s*!~\s*(\/[^\/]*\/[igm]*)/g, ".search($1) == -1");

	var names;
	if(form_fields) {
		names = form_fields;
	} else {
		names = predicate.match(this.name_regex);
	}
	var names2 = {};
	for(var i = 0; names && i < names.length; ++i) {
		var name = names[i];
		if(i > 0 && names[i-1] == name) {
			continue;
		}

		// easy way to get distinct set of names
		names2[name] = 1;

		if(!this.rules[name]) {
			this.rules[name] = [];
		}
	}

	for(var name in names2) {
		this.rules[name].push([names, events, predicate, message]);
	}
}


// Replace with DOM 2 Event model when browser support permits
lk.Validator.prototype.addEvents = function() {
	for(var name in this.rules) {
		var controls = document.getElementsByName(name);
		this.controls[name] = controls;
		for(var i = 0; i < this.rules[name].length; ++i) {
			var rule = this.rules[name][i];
			var events = rule[1];
			for(var j = 0; j < controls.length; ++j) {
				for(var k = 0; k < events.length; ++k) {
					var e = events[k];
					controls[j][e] = lk.Visitor(controls[j][e] || undefined, lk.Callback(this, 'checkControlEvent'));
				}
			}
		}
	}

	if(this.test_mode) {
		return;
	}

	// assume single form and that the first registered event is for that form
	for(var name in this.rules) {
		document.getElementsByName(name)[0].form.onsubmit = lk.Callback(this, "checkAllControls");
		break;
	}
}


// onsubmit
lk.Validator.prototype.checkAllControls = function(e, suppressVisuals) {
	var failures = 0;
	lk.submitted = {};
	var errors = [];
	for (var name in this.rules) {
		try {
			failures += !this.checkControl(name, suppressVisuals, errors);
			lk.submitted[document.getElementsByName(name)[0].form.name] = 1;
		} catch(e) {
			// ok, if there was any unexpected runtime error, we'll trap it to report it to the server,
			// but we won't block letting the form submit (we won't increment failures):
			errors.push("Unexpected form failure: " + e.message);
		}
	}

	if(failures && !suppressVisuals) {
		var error_box = $("#error_box");
		if(error_box && (error_box.length > 0)) {
			error_box.toggleClass("display_none");
			$(document).scrollTop(0);
		}
		else {
			alert('Please correct the field(s) outlined in red to receive free quotes');
		}
	}

	// tell the server about what happened:
	if(failures && !suppressVisuals) {
		reportEvents(errors);
	}

	return failures ? false : true;
}


lk.Validator.prototype.checkControl = function(name, suppressVisuals, errors) {
	for(var i = 0; i < this.rules[name].length; ++i) {
		var rule = this.rules[name][i];
		var names = rule[0];
		var values = {};
		for(var j = 0; j < names.length; ++j) {
			var name2 = names[j];
			if(values[name2] == undefined) {
				var controls = this.controls[name2];
				for(var k = 0; k < controls.length; ++k) {
					var control = controls[k];
					if((control.type != 'radio' && control.type != 'checkbox') || control.checked) {
						values[name2] = control.value;
					}
				}
				if(values[name2] == undefined) {
					values[name2] = '';
				}
			}
		}

		var predicate = rule[2];
		var message = rule[3]
		with(values) {
			var success = 0;
			try {
				success = eval(predicate);
				if(!suppressVisuals) {
					if(errors instanceof Array) {
						errors.push(predicate);
					}
					this.show(names, success, message);
				}
			} catch(error) {
				alert(error + ': ' + predicate);
			}
			if(!success)
				break;
		}
	}

	return success ? true : false;
}


lk.Validator.prototype.checkControlEvent = function(e) {
	// IE work-around
	var e2 = e || window.event;
	if(!e2.target)
		e2.target = e2.srcElement;

	e2.cancelBubble = true;
	if(e2.stopPropagation)
		e2.stopPropagation();
	if(e2.target.name)
		this.checkControl(e2.target.name);
}


// Work-around for IE 5, 5.5, and 6 memory leak
// (http://support.microsoft.com/kb/830555)
lk.Validator.prototype.removeEvents = function() {
	for(var name in this.rules) {
		var control = this.controls[name];
		for(var i = 0; i < this.rules[name].length; ++i) {
			var rule = this.rules[name][i];
			var events = rule[1];
			for(var j = 0; j < events.length; ++j) {
				control[events[j]] = '';
			}
		}
	}

	// assume single form and that the first registered event is for that form
	for(var name in this.rules) {
		document.getElementsByName(name)[0].form.onsubmit = '';
		break;
	}
}


// Visitor pattern using function chaining
lk.Visitor = function(e, f, override) {
	if(!e || override) {
		return f;
	} else {
		return function() { e.apply(this, arguments); f.apply(this, arguments); }
	}
}


lk.Zip = function(callback) {
	this.callback = callback;
	this.zip = null;
	this.result = null;
}


lk.Zip.prototype.callbackHandler = function(m) {
	this.result = true;
	if(m.readyState == 4 && m.responseText) {
		var o = eval('(' + m.responseText + ')');
		if(o.invalid_zip) {
			this.result = false;
		} else {
			this.result = true;
		}
		this.callback(o.zip, o.cityname, o.statecode);
	}
}


lk.Zip.prototype.check = function(zip) {
	if(this.zip == zip) {
		return this.result;
	}
	this.zip = zip;
	this.result = null;

	var c = new XHConn();
	c.connect('/rss-1html-2ajax.html', 'POST', 'zip=' + this.zip, lk.Callback(this, 'callbackHandler'));

	return this.result;
}


lk.Auto = function(callback) {
	this.callback = callback;
	this.year = null;
	this.make = null;
	this.model = null;
	this.trim = null;
	this.result = null;
	this.input_type_changed = 0;
}


lk.Auto.prototype.createInput = function(opt, s, initSelect) {
	s.options.length = 0;
	var list = opt.split(",");
	if(list.length == 1) {
		s.options[0] = new Option(list[0], list[0], true, true);
		return;
	}
	s.options[0] = new Option(initSelect, '');
	for(var i = 0; i < list.length; i++) {
		s.options[i + 1] = new Option(list[i], list[i]);
	}
}


lk.Auto.prototype.callbackHandler = function(m) {
	this.result = true;
	if(m.readyState == 4 && m.responseText) {
		if(this.model) {
			var opt = m.responseText;
			var s = document.getElementById('ff_submodelsel');
			this.createInput(opt, s, '--Submodel--');

			document.getElementById("ff_submodel").style.display='none';
			document.getElementById("ff_submodelsel").style.display='inline';

			this.callback('ff_modelsel');
		}
		else if(this.make) {
			var opt = m.responseText;
			var s = document.getElementById('ff_modelsel');
			this.createInput(opt, s, '--Model--');

			document.getElementById("ff_model").style.display='none';
			document.getElementById("ff_modelsel").style.display='inline';

			this.callback('ff_make');
		}
		else if(this.year) {
			var opt = m.responseText;
			var s = document.getElementById('ff_makesel');
			this.createInput(opt, s, '--Make--');
			this.callback('ff_year');
		}
	}
}


lk.Auto.prototype.check = function(year, make, model, trim) {
	if((this.year == year) && (this.make == make) && (this.model == model) && trim) {
		if(this.trim == trim) {
			//return this.result;
			return true;
		}
		document.getElementById("ff_submodel").value = trim;
		this.result = true;
	}
	else if((this.year == year) && (this.make == make) && model) {
		if(this.model == model) {
			return this.result;
		}
		document.getElementById("ff_model").value = model;

		var c = new XHConn();
		this.result = null;
		this.model = model;
		this.trim = null;
		c.connect('/rss-1html-2ajax-3auto.html',
			'POST',
			'year=' + this.year + '&make=' + encodeURIComponent(this.make) + '&model=' + encodeURIComponent(this.model),
			lk.Callback(this, 'callbackHandler'),
			'ff_submodelsel'
		);
	}
	else if((this.year == year) && make) {
		if(this.make == make) {
			return this.result;
		}

		var s = document.getElementById('ff_submodelsel');
		s.options[0] = new Option('--Submodel--', '');

		document.getElementById("ff_make").value = make;

		var c = new XHConn();
		this.result = null;
		this.make = make;
		this.model = null;
		this.trim = null;
		c.connect('/rss-1html-2ajax-3auto.html',
			'POST',
			'year=' + this.year + '&make=' + encodeURIComponent(this.make),
			lk.Callback(this, 'callbackHandler'),
			'ff_modelsel'
		);
	}
	else if(year) {
		if(this.year == year) {
			return this.result;
		}

		if(year < 1981) {
			document.getElementById("ff_makesel").style.display='none';
			document.getElementById("ff_modelsel").style.display='none';
			document.getElementById("ff_submodelsel").style.display='none';
			document.getElementById("ff_make").style.display='inline';
			document.getElementById("ff_model").style.display='inline';
			document.getElementById("ff_submodel").style.display='inline';

			this.result = true;
			return this.result;
		}
		var s = document.getElementById('ff_makesel');
		s.options[0] = new Option('--Make--', '');
		var s = document.getElementById('ff_modelsel');
		s.options[0] = new Option('--Model--', '');
		var s = document.getElementById('ff_submodelsel');
		s.options[0] = new Option('--Submodel--', '');

		var c = new XHConn();
		this.result = null;
		this.year = year;
		this.make = null;
		this.model = null;
		this.trim = null;
		c.connect('/rss-1html-2ajax-3auto.html',
			'POST',
			'year=' + this.year,
			lk.Callback(this, 'callbackHandler'),
			'ff_make'
		);
	}
	return this.result;
}


function openPopup(url, name, keys, values) {
	var popup = window.open('/page-blank.html', name, "newwindow=yes,scrollbars=yes");
	if(!popup)
		return false;
	var html = "";
	html += "<html><head></head><body><form id='formid' name='formenv' method='post' action='" + url + "'>";
	if(keys && values && (keys.length == values.length)) {
		for (var i=0; i < keys.length; i++) {
			html += "<input type='hidden' name='" + keys[i] + "' value='" + values[i] + "'/>";
		}
	}
	html += "</form><scr";
	html += "ipt type=\'text/javascript\'>document.getElementById(\"formid\").submit()</scr";
	html += "ipt></body></html>";
	try {
		popup.document.write(html);
	} catch(e) {
		// Catch IE6 being STUPID and throwing an error
	}
	return popup;
}


function getCookieValue(cookieName) {
	var c = document.cookie;
	if(c) {
		var cookies = (c.indexOf(';') == -1) ? [c] : c.split(/\s*;\s*/);
		for(var i = 0, j = cookies.length; i < j; i++) {
			var keyvalue = cookies[i].split('=');
			if(keyvalue[0] == cookieName) {
				return keyvalue[1];
			}
		}
	}
	return '';
}


function reportEvents(events, event_type, ai) {
	if(!events) {
		return;
	}
	// convert events array into hash delim list:
	events = events.join('#');
	var url = '/rss-1html-2ajax-3clierr.html';
	var cook = getCookieValue('gbapx');
	var data = {
		'events': events,
		'event_type': event_type || 'error',
		'ai': ai || cook || ''
	};
	$.post(url, data, function(data){ /* this just silently captures responses, since failure is OK */ });
}
