/***************************************************
*                       Misc                       *
***************************************************/

function flip_it(){
	var temp;
	var form = document['order'];

	temp = form['p_name'].value;
	form['p_name'].value = form['d_name'].value;
	form['d_name'].value = temp;

	temp = form['p_street_address'].value;
	form['p_street_address'].value = form['d_street_address'].value;
	form['d_street_address'].value = temp;

	temp = form['p_city'].value;
	form['p_city'].value = form['d_city'].value;
	form['d_city'].value = temp;

	for(var i=0;i<form['p_state'].length;i++){
	 if(form['p_state'][i].selected == true){temp = i;}
	}
	for(var i=0;i<form['d_state'].length;i++){
	 if(form['d_state'][i].selected == true){form['p_state'][i].selected = true;}
	}
	form['d_state'][temp].selected = true;

	temp = form['p_zip'].value;
	form['p_zip'].value = form['d_zip'].value;
	form['d_zip'].value = temp;

	temp = form['p_non_us_address'].value;
	form['p_non_us_address'].value = form['d_non_us_address'].value;
	form['d_non_us_address'].value = temp;

	for(var i=0;i<form['p_country'].length;i++){
	 if(form['p_country'][i].selected == true){temp = i;}
	}
	for(var i=0;i<form['d_country'].length;i++){
	 if(form['d_country'][i].selected == true){form['p_country'][i].selected = true;}
	}
	form['d_country'][temp].selected = true;

	temp = form['p_phone'].value;
	form['p_phone'].value = form['d_phone'].value;
	form['d_phone'].value = temp;

	temp = form['p_cell'].value;
	form['p_cell'].value = form['d_cell'].value;
	form['d_cell'].value = temp;

	temp = form['p_altphone'].value;
	form['p_altphone'].value = form['d_altphone'].value;
	form['d_altphone'].value = temp;

	temp = form['p_fax'].value;
	form['p_fax'].value = form['d_fax'].value;
	form['d_fax'].value = temp;

	temp = form['p_contact'].value;
	form['p_contact'].value = form['d_contact'].value;
	form['d_contact'].value = temp;

	temp = form['p_email'].value;
	form['p_email'].value = form['d_email'].value;
	form['d_email'].value = temp;

	temp = form['p_residence'].checked;
	form['p_residence'].checked = form['d_residence'].checked;
	form['d_residence'].checked = temp;
}

function check_additional_charge(){
	if (document.getElementById('additional_charge').value != '') {
		document.getElementById('acd_container').style.display='block';
	}else{
		document.getElementById('acd_container').style.display='none';
	}
}

function getStyleClass (className) {
	if (document.styleSheets.length < 1) {
		return null;
	}
	if (document.styleSheets[0].cssRules) {
		var cssRules = 'cssRules';
	} else {
		var cssRules = 'rules';
	}
  for (var s = 0; s < document.styleSheets.length; s++) {
    for (var r = 0; r < document.styleSheets[s][cssRules].length; r++) {
      if (document.styleSheets[s][cssRules][r].selectorText == '.' + className) {
        return document.styleSheets[s][cssRules][r];
			}
		}
	}
  return null;
}

function check_bill_to(){
	if (document.getElementById('bill_to_b').checked == true) {
		getStyleClass('bill_to').style.display = '';
		validate_location(document.getElementById('bill_to_b')['form'], 'b');
	}else{
		getStyleClass('bill_to').style.display = 'none';
	}
}

function check_us_address(location){
	if (typeof location !== 'undefined' && location != '') {
		loc = location+'_';
	} else {
		loc = '';
	}
	var sel = document.getElementById(loc+'country');
	if (sel[sel.selectedIndex].value != 'UNITED STATES') {
		getStyleClass(loc+'non_us_addr').style.display = '';
		if (document.getElementById(loc+'non_us_address').value == '') {
			var city = document.getElementById(loc+'city').value;
			var state_sel = document.getElementById(loc+'state');
			var state = state_sel[state_sel.selectedIndex].value;
			var zip = document.getElementById(loc+'zip').value;
			var val = city;
			if (val != '' && (zip != '' || state != '')) {
				val += ', ';
			}
			val += state;
			if (val != '' && zip != '') {
				val += ' ';
			}
			val += zip;
			document.getElementById(loc+'non_us_address').value = val;
		}
		getStyleClass(loc+'us_addr').style.display = 'none';
	} else {
		getStyleClass(loc+'non_us_addr').style.display = 'none';
		getStyleClass(loc+'us_addr').style.display = '';
	}
	if (loc != '') {
		validate_location(sel['form'], location);
	}
}

function check_vehs_entered(desc_box){
	var desc = desc_box.value;
	var desc_arr = desc.split("\n");
	for (var i=0; i<desc_arr.length; i++) {
		if (desc_arr[i] == '') {
			desc_arr.splice(i,1);
			i--;
		}
	}
	var num_units = document.createTextNode(desc_arr.length);
	var display = document.getElementById('num_vehs_entered');
	while (display.childNodes[0]) {display.removeChild(display.childNodes[0]);}
	document.getElementById('num_vehs_entered').appendChild(num_units);
}

/***************************************************
*                 Validation Stuff                 *
***************************************************/
/**
 * Used to make sure an HTMLInputElement isn't empty.  If it is, it turns it red
 * and returns false.  If it's NOT, it turns it white, and returns true.
 *
 * @param {HTMLInputElement} el
 *
 * @return {bool}
 */
function validate_not_empty(el) {
	if (el.value=='') {
		el.style.backgroundColor='#FCC';
		return false;
	} else {
		el.style.backgroundColor='#FFF';
		return true;
	}
}

/**
 * Used to make sure the value of an HTMLInputElement contains a valid zip code.
 * If it doesn't, it turns it red and returns false.  If it does, it turns it
 * white and returns true.
 *
 * @param {HTMLInputElement} el
 *
 * @return {bool}
 */
function validate_zip(el) {
	if (!isValidZip(el)) {
		el.style.backgroundColor='#FCC';
		return false;
	} else {
		el.style.backgroundColor='#FFF';
		return true;
	}
}

/**
 * Used to make sure the value of an HTMLInputElement contains a valid phone
 * number.  If it doesn't, it turns it red and returns false.  If it does, it
 * turns it white and returns true.
 *
 * If the optional parameter is set to true, it will consider '' to be valid,
 * but if the HTMLInputElement is not empty, it MUST be a valid phone number.
 *
 * @param {HTMLInputElement} el
 * @param {bool} optional
 *
 * @return {bool}
 */
function validate_phone(el, optional) {
	optional = (typeof optional == undefined)? false:Boolean(optional);

	formatPhone(el);
	if (isValidPhone(el) || (optional && el.value == '')) {
		el.style.backgroundColor='#FFF';
		return true;
	} else {
		el.style.backgroundColor='#FCC';
		return false;
	}
}

/**
 * Used to make sure the value of an HTMLInputElement contains a valid email
 * address.  If it doesn't, it turns it red and returns false.  If it does, it
 * turns it white and returns true.
 *
 * If the optional parameter is set to true, it will consider '' to be valid,
 * but if the HTMLInputElement is not empty, it MUST be a valid email address.
 *
 * @param {HTMLInputElement} el
 * @param {bool} optional
 *
 * @return {bool}
 */
function validate_email(el, optional) {
	optional = (typeof optional == undefined)? false:Boolean(optional);

	if (isValidEmail(el.value) || (optional && el.value == '')) {
		el.style.backgroundColor='#FFF';
		return true;
	} else {
		el.style.backgroundColor='#FCC';
		return false;
	}
}

/**
 * Used to make sure the value of an HTMLInputElement contains a valid date
 * (mm/dd/yyyy).  If it doesn't, it turns it red and returns false.  If it does,
 * it turns it white and returns true.
 *
 * If the optional parameter is set to true, it will consider '' to be valid,
 * but if the HTMLInputElement is not empty, it MUST be a valid date.
 *
 * @param {HTMLInputElement} el
 * @param {bool} optional
 *
 * @return {bool}
 */
function validate_date(el, optional) {
	optional = (typeof optional == undefined)? false:Boolean(optional);

	if (isValidDate(el) || (optional && el.value == '')) {
		el.style.backgroundColor='#FFF';
		return true;
	} else {
		el.style.backgroundColor='#FCC';
		return false;
	}
}

/**
 * Used to make sure the value of an HTMLInputElement contains a valid assigned
 * to string.  If it doesn't, it turns it red and returns false.  If it does,
 * it turns it white and returns true.
 *
 * If the optional parameter is set to true, it will consider '' to be valid,
 * but if the HTMLInputElement is not empty, it MUST be valid.
 *
 * @param {HTMLInputElement} el
 * @param {bool} optional
 *
 * @return {bool}
 */
function validate_assigned_to(el, optional) {
	optional = (typeof optional == undefined)? false:Boolean(optional);

	if (isValidAssignedTo(el.value) || (optional && el.value == '')) {
		el.style.backgroundColor='#FFF';
		return true;
	} else {
		el.style.backgroundColor='#FCC';
		return false;
	}
}

/**
 * Used to make sure the value of an HTMLInputElement contains a valid number of
 * units.  If it doesn't, it turns it red and returns false.  If it does, it
 * turns it white and returns true.
 *
 * @param {HTMLInputElement} el
 *
 * @return {bool}
 */
function validate_num_units(el) {
	el.value = formatDecimal(el.value);
	if (isValidNumUnits(el.value)) {
		el.style.backgroundColor='#FFF';
		return true;
	} else {
		el.style.backgroundColor='#FCC';
		return false;
	}
}

/**
 * Used to make sure the value of an HTMLInputElement contains a valid dollar
 * amount.  If it doesn't, it turns it red and returns false.  If it does, it
 * turns it white and returns true.
 *
 * If the optional parameter is set to true, it will consider '' to be valid,
 * but if the HTMLInputElement is not empty, it MUST be a valid dollar amount.
 *
 * @param {HTMLInputElement} el
 *
 * @return {bool}
 */
function validate_money(el, optional) {
	el.value = formatDecimal(el.value);
	optional = (typeof optional == undefined)? false:Boolean(optional);

	if (isValidMoney(el.value) || (optional && el.value == '')) {
		el.style.backgroundColor='#FFF';
		return true;
	} else {
		el.style.backgroundColor='#FCC';
		return false;
	}
}

/**
 * Used to make sure one of the HTMLInputElements contains a valid dollar
 * amount, and the other one is blank.  If they don't, meet these requirements,
 * it turns them red and returns false.  If they do, it turns them white and
 * returns true.
 *
 * @param {HTMLInputElement} el1
 * @param {HTMLInputElement} el2
 *
 * @return {bool}
 */
function validate_one_price(el1, el2) {
	el1.value = formatDecimal(el1.value);
	el2.value = formatDecimal(el2.value);
	if ((isValidMoney(el1.value) && el2.value == '') || (isValidMoney(el2.value) && el1.value == '')) {
		el1.style.backgroundColor='#FFF';
		el2.style.backgroundColor='#FFF';
		return true;
	} else {
		el1.style.backgroundColor='#FCC';
		el2.style.backgroundColor='#FCC';
		return false;
	}
}

/**
 * Used to make sure that a radio button has been selected.
 * If it hasn't, it turns it red and returns false.  If it has, it turns it
 * white and returns true.
 *
 * @param {HTMLInputElement} el
 *
 * @return {bool}
 */
function validate_radio_checked(el) {
	if (!isRadioChecked(el)) {
		setRadioBG(el, '#FCC');
		return false;
	} else {
		setRadioBG(el, '#FFF');
		return true;
	}
}

/**
 * Used to make sure that a phone number AND/OR email address has been specified
 * If it hasn't, it turns it red and returns false.  If it has, it turns it
 * white and returns true.
 *
 * @param {HTMLInputElement} phEl
 * @param {HTMLInputElement} emEl
 *
 * @return {bool}
 */
function validate_phone_or_email(phEl, emEl) {
	var return_value = true;
	if (!validate_phone(phEl, true)) {
		return_value = false;
	}

	if (!validate_email(emEl, true)) {
		return_value = false;
	}

	if (phEl.value == '' && emEl.value == '') {
		phEl.style.backgroundColor='#FCC';
		emEl.style.backgroundColor='#FCC';
		return_value = false;
	}

	if (return_value) {
		phEl.style.backgroundColor='#FFF';
		emEl.style.backgroundColor='#FFF';
	}

	return return_value;
}

function validate_location(order_form, loc) {
	if (loc == 'b' && order_form.bill_to[2].checked != true) {
		order_form.b_name.style.backgroundColor='#FFF';
		order_form.b_street_address.style.backgroundColor='#FFF';
		order_form.b_city.style.backgroundColor='#FFF';
		order_form.b_state.style.backgroundColor='#FFF';
		order_form.b_zip.style.backgroundColor='#FFF';
		order_form.b_non_us_address.style.backgroundColor='#FFF';
		order_form.b_contact.style.backgroundColor='#FFF';
		order_form.b_phone.style.backgroundColor='#FFF';
		order_form.b_cell.style.backgroundColor='#FFF';
		order_form.b_altphone.style.backgroundColor='#FFF';
		order_form.b_fax.style.backgroundColor='#FFF';
		order_form.b_email.style.backgroundColor='#FFF';
		return true;
	}
	var return_value = true;

	//Validate Location info
	if (!validate_not_empty(order_form[loc + '_name'])) {
		return_value = false;
	}

	if (!validate_not_empty(order_form[loc + '_street_address'])) {
		return_value = false;
	}

	if (order_form[loc + '_country'].value == 'UNITED STATES') {
		if (!validate_not_empty(order_form[loc + '_city'])) {
			return_value = false;
		}

		if (!validate_not_empty(order_form[loc + '_state'])) {
			return_value = false;
		}

		if (!validate_zip(order_form[loc + '_zip'])) {
			return_value = false;
		}
	} else {
		if (!validate_not_empty(order_form[loc + '_non_us_address'])) {
			return_value = false;
		}
	}

	if (!validate_not_empty(order_form[loc + '_contact'])) {
		return_value = false;
	}

	if (!validate_phone(order_form[loc + '_phone'])) {
		return_value = false;
	}

	if (!validate_phone(order_form[loc + '_cell'], true)) {
		return_value = false;
	}

	if (!validate_phone(order_form[loc + '_altphone'], true)) {
		return_value = false;
	}

	if (!validate_phone(order_form[loc + '_fax'], true)) {
		return_value = false;
	}

	if (!validate_email(order_form[loc + '_email'], true)) {
		return_value = false;
	}

	switch (loc) {
		case 'p':
			var date_name = 'vehs_avail';
			break;
		case 'd':
			var date_name = 'deliver_by';
			break;
	}

	if (loc != 'b') {
		if (!validate_date(order_form[date_name], true)) {
			return_value = false;
		}
		if (!validate_radio_checked(order_form[loc + '_residence'])) {
			return_value = false;
		}
	}

	return return_value;
}

function validate_order(order_form, alrt){
	var return_value = true;

	//Validate name of person placing order
	if (!validate_not_empty(order_form['o_contact'])) {
		return_value = false;
	}

	//Validate contact info of person placing order
	if (!validate_phone_or_email(order_form['o_phone'],order_form['o_email'])) {
		return_value = false;
	}

	//validate Pickup Location info
	if (!validate_location(order_form, 'p')){
		return_value = false;
	}

	//validate Delivery Location info
	if (!validate_location(order_form, 'd')){
		return_value = false;
	}

	//make sure a location has been chosen as a bill to location
	if (!validate_radio_checked(order_form.bill_to)) {
		return_value = false;
	}

	//validate Bill To Location info
	if (!validate_location(order_form, 'b')){
		return_value = false;
	}

	//Validate General Information Section
	if (!validate_num_units(order_form['num_units'])) {
		return_value = false;
	}

	if (!validate_one_price(order_form['price_per_load'], order_form['price_per_unit'])) {
		return_value = false;
	}

	if (!validate_money(order_form['additional_charge'], true)) {
		return_value = false;
	}

	if (!validate_radio_checked(order_form['run_drive'])) {
		return_value = false;
	}

	if (!validate_not_empty(order_form['desc_vehs'])) {
		return_value = false;
	}

	if (!validate_assigned_to(order_form['assigned_to'], true)) {
		return_value = false;
	}

	if (order_form['assigned_to'].value != ''){
		if (validate_date(order_form['assigned_to_date'])) {
			return_value = false;
		}
	}

	if(order_form.from_region && order_form.to_region){
		if(order_form.from_region.tagName == 'SELECT'){
			if (!validate_not_empty(order_form['from_region'])) {
				return_value = false;
			}
		} else {
			if (!validate_radio_checked(order_form['from_region'])) {
				return_value = false;
			}
		}
		if(order_form.to_region.tagName == 'SELECT'){
			if (!validate_not_empty(order_form['to_region'])) {
				return_value = false;
			}
		} else {
			if (!validate_radio_checked(order_form['to_region'])) {
				return_value = false;
			}
		}
	}

	if(!return_value && alrt != false){alert('Please check the red colored items.');}

	return return_value;
}

/***************************************************
*                  Validate Funcs                  *
***************************************************/
function isValidDate(date){
	date.value=date.value.replace(/[\\\.\-\s]/g,"/");
	date.value=date.value.replace(/^(\d\d)(\d\d)(\d\d)$/,"$1/$2/$3");
	date.value=date.value.replace(/^(\d\d)(\d\d)(\d\d\d\d)$/,"$1/$2/$3");
	date.value=date.value.replace(/^(\d\d)\/(\d\d)\/(\d\d)$/,"$1/$2/20$3");

	validDate = /^(0?[1-9]|1[012])\/(0?[1-9]|[12][0-9]|3[01])\/((20)?(19)?\d{2})$/;
	var feb = 28;
	if(!date.value.match(validDate)){return false;};
	if((RegExp.$3 % 4 == 0) && ((RegExp.$3 % 100 != 0) || (RegExp.$3 % 400 == 0))){feb = 29};
	if((RegExp.$1==1 || RegExp.$1==3 || RegExp.$1==5 || RegExp.$1==7 || RegExp.$1==8 || RegExp.$1==10 || RegExp.$1 == 12) && RegExp.$2<=31)
	{return true;}
	if((RegExp.$1==4 || RegExp.$1==6 || RegExp.$1==9 || RegExp.$1==11) && RegExp.$2<=30)
	{return true;}
	if(RegExp.$1==2 && RegExp.$2<=feb){return true;}
	return false;
}

function isValidZip(zip){
	validZip = /^(\d{5})-?(\d{4})?$/;
	if(!zip.value.match(validZip)){return false;}
	if(zip.value.match(/^(\d{5})(\d{4})$/)){zip.value=RegExp.$1+"-"+RegExp.$2;}
	return true;
}

function isRadioChecked(radioGroup){
	var checked = false;
	for(i=0;i<radioGroup.length;i++){
		if(radioGroup[i].checked==true){checked=true;}
	}
	return checked;
}

function setRadioBG(radioGroup,bgcolor){
	for(i=0;i<radioGroup.length;i++){
		radioGroup[i].parentNode.style.backgroundColor=bgcolor;
	}
}

function isValidPhone(phoneNumber){
	var temp=phoneNumber.value.replace(/\D/g,'');
	temp=temp.replace(/^[01]*/,'');
	if(!temp.match(/^([2-9]\d{2})([2-9]\d{2})(\d{4})$/)){return false;}
	phoneNumber.value=RegExp.$1+'-'+RegExp.$2+'-'+RegExp.$3;
	return true;
}

function formatPhone(phone){
	phone.value=phone.value.replace(/\D/g,'');
	phone.value=phone.value.replace(/^1*/g,'');
	phone.value=phone.value.replace(/^(\d\d\d)1*/g,"$1");

	if (phone.value.length >= 6) {
		phone.value.match(/^(\d{3})(\d{3})(\d*)/);
		phone.value=RegExp.$1+'-'+RegExp.$2+'-'+RegExp.$3;
	} else if (phone.value.length >= 3) {
		phone.value.match(/^(\d{3})(\d*)/);
		phone.value=RegExp.$1+'-'+RegExp.$2;
	}
}

function getKey(e) {
	if (e.keyCode) return String.fromCharCode(e.keyCode);
	if (e.which) return String.fromCharCode(e.which);
}

function formatZip(e,zip){
	var keyCode = e.which ? e.which : e.keyCode;
	if(keyCode == 8 || (keyCode >= 35 && keyCode <= 40) || keyCode == 46){
		return false;
	}
	zip.value=zip.value.replace(/\D/g,'');
	if(zip.value.length >= 6){zip.value.match(/^(\d{5})(\d*)/);zip.value=RegExp.$1+'-'+RegExp.$2;}
}

function formatDate(date,e){
	if (typeof e !== 'undefined') {
		var keyCode = e.which ? e.which : e.keyCode;
		if(keyCode == 8 || (keyCode >= 35 && keyCode <= 40) || keyCode == 46){
			return false;
		}
	}
	date.value=date.value.replace(/\D/g,'');
	if(date.value.length >= 4){date.value.match(/^(\d{2})(\d{2})(\d*)/);date.value=RegExp.$1+'/'+RegExp.$2+'/'+RegExp.$3;}
	else if(date.value.length >= 2){date.value.match(/^(\d{2})(\d*)/);date.value=RegExp.$1+'/'+RegExp.$2;}
}

function isValidEmail(email){
	validEmail = /^[a-z0-9][a-z0-9._%-]*@([a-z0-9_%-]+\.)(([a-z]){2,3}\.)?[a-z]{2,4}$/i;
	return email.match(validEmail);
}

function formatDecimal(num){
	return num.replace(/[^\d.]/g,'');
}

function isValidNumUnits(numUnits){
	validNumUnits = /^\d{1,3}(\.((5)|(0)|(25)|(75))?)?$/;
	return numUnits.match(validNumUnits);
}

function isValidMoney(money){
	validMoney = /^\d{1,7}(\.[\d]{0,2})?$/;
	return money.match(validMoney);
}

function isValidAssignedTo(assignedTo){
	validAssignedTo = /^\w+(\/\w+)*[\/\*]?$/;
	return assignedTo.match(validAssignedTo);
}

/***************************************************
*                  Calendar Stuff                  *
***************************************************/
/**
 * Calendar Class
 */
function Calendar(){
	//default date format to use (based on PHP's date function)
	this.dateFormat = 'm/d/Y';

	//Build the div that contains the calendar, and attach it to the document body
	this.calendarContainer = document.createElement("div");
	this.calendarContainer.id = 'calendarContainer';
	this.calendarContainer.style.position = 'absolute';
	this.calendarContainer.style.visibility = 'hidden';
	this.calendarContainer.style.zIndex = '99';
	document.body.appendChild(this.calendarContainer);

	//The today var will be used to highlight "today"
	this.today = new Date();

	//Default the current month/year to todays month/year
	this.current = new Date();
};

/**
 * Used to display the calendar. in the correct position, and set the current
 * date info to whatever is already in the input
 *
 * @param HTMLInputObject target - reference to the input that gets filled
 *
 * @return void
 */
Calendar.prototype.showCal = function (target) {
	this.stopHideCal();
	this.target = target;
	var position = this.getElementPosition(this.target);
	var parentHeight = this.target.offsetHeight;

	this.target.value = this.interpretDate(this.target.value);
	this.selected = new Date(this.target.value);

	if (this.selected.getMonth() >=0 && this.selected.getMonth() <= 11) {
		this.current.setMonth(this.selected.getMonth());
	}

	//Throw in a little logic to see that the year is within 100 years of today...
	//so that we don't have people start at 0001 or something crazy
	if (Math.abs(this.selected.getFullYear()-this.today.getFullYear()) <= 100) {
		this.current.setFullYear(this.selected.getFullYear());
	}

	var thisCal = this;
	this.blurfunc = this.addEvent(this.target, 'blur', function(e) {thisCal.hideCal();});

	this.calendarContainer.style.left = position.left+10+'px';
	this.calendarContainer.style.top = position.top+this.target.offsetHeight+'px';
	this.calendarContainer.style.visibility = 'visible';
	this.buildCalendar();
};

/**
 * Used to set the format of the date string inserted into the text input.  Uses
 * formatting from PHP's date function
 *
 * @param {String} dateFormat
 *
 * @return void
 */
Calendar.prototype.setDateFormat = function (dateFormat) {
	this.dateFormat = dateFormat;
}

/**
 * Used to build the actual calendar, and attach it to the calendarContainer div
 *
 * @return void
 */
Calendar.prototype.buildCalendar = function () {
	var thisCal = this;
	var start_month = this.current;
	start_month.setDate(1);
	var start_month_day = start_month.getDay();


	var count = 0;
	var day_class = "";
	var calendarTable = document.createElement("table");
	calendarTable.className = "cal";
	calendarTable.cellPadding = 0;
	calendarTable.cellSpacing = 0;

	var thead = document.createElement("thead");
	var tr = document.createElement("tr");

	//Change Year DOWN button
	var td = document.createElement("td");
	var btn = document.createElement("button");
	this.addEvent(btn, 'click', function() {thisCal.changeMonth(-12);});
	btn.appendChild(document.createTextNode('<<'));
	td.appendChild(btn);
	tr.appendChild(td);

	//Change Month DOWN button
	var td = document.createElement("td");
	var btn = document.createElement("button");
	this.addEvent(btn, 'click', function() {thisCal.changeMonth(-1);});
	btn.appendChild(document.createTextNode('<'));
	td.appendChild(btn);
	tr.appendChild(td);

	//Show month Year
	var td = document.createElement("td");
	td.colSpan = 3;
	td.appendChild(document.createTextNode(this.current.format('M Y')));
	tr.appendChild(td);

	//Change Month UP button
	var td = document.createElement("td");
	var btn = document.createElement("button");
	this.addEvent(btn, 'click', function() {thisCal.changeMonth(1);});
	btn.appendChild(document.createTextNode('>'));
	td.appendChild(btn);
	tr.appendChild(td);

	//Change Year UP button
	var td = document.createElement("td");
	var btn = document.createElement("button");
	this.addEvent(btn, 'click', function() {thisCal.changeMonth(12);});
	btn.appendChild(document.createTextNode('>>'));
	td.appendChild(btn);
	tr.appendChild(td);

	thead.appendChild(tr);

	//Display the days of the week
	var tr = document.createElement("tr");
	tr.className = 'dow';
	for (i=0; i<7; i++) {
		var td = document.createElement("td");
		td.appendChild(document.createTextNode(Date.prototype.dayNames[i].substr(0,2)));
		tr.appendChild(td);
	}
	thead.appendChild(tr);
	calendarTable.appendChild(thead);

	//Display the "Show Today" Link.
	var tfoot = document.createElement("tfoot");
	var tr = document.createElement("tr");
	var td = document.createElement("td");
	td.colSpan = 7;
	var btn = document.createElement("button");
	this.addEvent(btn, 'click', function() {thisCal.showToday();});
	btn.appendChild(document.createTextNode('Show Today'));
	td.appendChild(btn);
	tr.appendChild(td);
	tfoot.appendChild(tr);
	calendarTable.appendChild(tfoot);

	//Create the actual days
	var tbody = document.createElement("tbody");
	var tr = document.createElement("tr");
	//Add calls containing only a hard-space until the day we start on
	for (i=0;i<start_month_day;i++) {
		var td = document.createElement("td");
		td.appendChild(document.createTextNode("\xA0"));
		tr.appendChild(td);
		count++;
	}

	for (i=1;i<=this.current.getDaysInMonth();i++) {
		//adjust this.current
		this.current.setDate(i);
		if (count < 7) {
			day_class = "";
			if (this.current.format('Ym')+this.current.pad(i) == this.today.format('Ymd')) {
				day_class = "today";
			}
			//See if the day we are processing is the "selected" day (currently IN the
			//target input).
			if (this.current.format('Ym')+this.current.pad(i) == this.selected.format('Ymd')) {
				if(day_class != ''){day_class += ' ';}
				day_class += "selected";
			}

			var td = document.createElement("td");

			var btn = document.createElement("button");
			btn.className = day_class;
			//This is part of a closure to allow it to use the correct date...and not
			//the last date in the loop
			var clickFunc = thisCal.getFunction(i);
			this.addEvent(btn, 'click', clickFunc);
			btn.appendChild(document.createTextNode(i));
			td.appendChild(btn);
			count++;
			tr.appendChild(td);
		} else {
			tbody.appendChild(tr);
			var tr = document.createElement("tr");
			count = 0;
			i--;
		}
	}
	//Add calls containing only a hard-space until the end
	for(count=count;count<7;count++) {
		var td = document.createElement("td");
		td.appendChild(document.createTextNode("\xA0"));
		tr.appendChild(td);
	}
	tbody.appendChild(tr);
	calendarTable.appendChild(tbody);

	//remove all children from the calendar container, and then append the new table
	while (this.calendarContainer.childNodes[0]) {
		this.calendarContainer.removeChild(this.calendarContainer.childNodes[0]);
	}
	this.calendarContainer.appendChild(calendarTable);
};

/**
 * A closure used to create a function for inserting the date into the field.
 * Month and Year are already known to this instance of Calendar, so we simply
 * pass in the day of the month (1-31)
 *
 * @param {int} i
 *
 * @return function
 */
Calendar.prototype.getFunction = function(i) {
	var thisCal = this;
	function tempFunc() {
		thisCal.fillDate(i);
		//If there is an onkeyup action set, run it.  This will let you attach
		//validation functions to the onkeyup
		if (typeof thisCal.target.onkeyup === 'function') {
			thisCal.target.onkeyup();
		}
	};
	return tempFunc;
};

/**
 * Used to hide the calendar, with a 200ms delay.  This way the calendar is
 * still there to receive a click, and does not disappear and reappear when we
 * change month or year.
 *
 * @return void
 */
Calendar.prototype.hideCal = function() {
	var thisCal = this;
	this.timeout_id = setTimeout(function() {thisCal.hideCalendar();}, 200);
};

/**
 * Can stop a request to hide the calendar
 *
 * @return void
 */
Calendar.prototype.stopHideCal = function () {
	if (this.timeout_id) {
		clearTimeout(this.timeout_id);
	}
};

/**
 * Hides the calendar and removes the blur event we attached to the text input
 *
 * @return void
 */
Calendar.prototype.hideCalendar = function() {
	this.remEvent(this.target, 'blur', this.blurfunc);
	this.calendarContainer.style.visibility = 'hidden';
}

/**
 * Put the correct date into the target text input formatted according to
 * this.dateFormat.  Then hide the calendar.
 *
 * @param {int} i - day of the month (1-31)
 *
 * @return void
 */
Calendar.prototype.fillDate = function(i) {
	this.current.setDate(i);
	this.target.value = this.current.format(this.dateFormat);
	this.hideCalendar();
};

/**
 * Changes the month of the calendar.  The only parameter is an integer to
 * adjust the month by (Usually -1 to go back one month, 1 to go forward one
 * month, -12 to go back one year, or 12 to go forward one year.  However, it
 * should be able to handle any integer value)
 * @param {int} adj
 */
Calendar.prototype.changeMonth = function (adj) {
	this.stopHideCal();
	this.current.setDate(1);
	this.current.setMonth(this.current.getMonth()+adj);
	this.buildCalendar();
};

Calendar.prototype.showToday = function() {
	this.stopHideCal();
	this.current = new Date();
	this.buildCalendar();
};

Calendar.prototype.getElementPosition = function(elemID) {
	var offsetTrail = elemID;
	var offsetLeft = 0;
	var offsetTop = 0;
	while (offsetTrail) {
		offsetLeft += offsetTrail.offsetLeft;
		offsetTop += offsetTrail.offsetTop;
		offsetTrail = offsetTrail.offsetParent;
	}
	if (navigator.userAgent.indexOf("Mac") != -1 &&
		typeof document.body.leftMargin != "undefined") {
		offsetLeft += document.body.leftMargin;
		offsetTop += document.body.topMargin;
	}
	return {left:offsetLeft, top:offsetTop};
};

Calendar.prototype.pad_zero = function(num) {
	return ((num <= 9) ? ("0" + num) : num);
};

Calendar.prototype.interpretDate = function(date) {
	date=date.replace(/[\\\.\-\s]/g,"/");
	date=date.replace(/^(\d\d)(\d\d)(\d\d)$/,"$1/$2/$3");
	date=date.replace(/^(\d\d)(\d\d)(\d\d\d\d)$/,"$1/$2/$3");
	date=date.replace(/^(\d\d)\/(\d\d)\/(\d\d)$/,"$1/$2/20$3");
	return date;
};

Calendar.prototype.addEvent = function (el, ev, f) {
  if (el.addEventListener) {
    el.addEventListener(ev, f, false);
	} else if(el.attachEvent) {
    el.attachEvent("on" + ev, f);
	} else {
    el['on' + ev] = f;
	}
	return f;
};

//make this available statically
Calendar.addEvent = Calendar.prototype.addEvent;

function calInit() {
	cal = new Calendar();
}

//Start the calendar onload
Calendar.addEvent(window, 'load', calInit);

Calendar.prototype.remEvent = function (el, ev, f) {
  if (el.removeEventListener) {
    el.removeEventListener(ev, f, false);
	} else if(el.detachEvent) {
    el.detachEvent("on" + ev, f);
	} else {
    el['on' + ev] = null;
	}
};



String.leftPad = function (s, len, ch) {
	var str = new String(s);
	if (ch == null) {
		ch = " ";
	}
	while (str.length < len) {
		str = ch + result;
	}
	return str;
}

/**
 * Date formatting Stuff
 */
Date.prototype.dayNames = new Array(
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday"
);

Date.prototype.monthNames = new Array(
	"January",
	"February",
	"March",
	"April",
	"May",
	"June",
	"July",
	"August",
	"September",
	"October",
	"November",
	"December"
);

Date.prototype.daysInMonths = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

Date.prototype.isLeapYear = function () {
	return (this.getFullYear() % 4 == 0) && ((this.getFullYear() % 100 != 0) || (this.getFullYear() % 400 == 0));
}

Date.prototype.pad = function (num) {
	if (Math.abs(num) <= 9) {
		if (num < 0) {
			return '-0'+Math.abs(num);
		} else {
			return '0'+num;
		}
	} else {
		return String(num);
	}
	return ((Math.abs(num) <= 9) ? ("0" + num) : num);
}

Date.prototype.format = function(format) {
	format = String(format).split("");
	var dateStr = '';

	for (var i = 0; i < format.length; i++) {
		switch (format[i]) {
			case 'd':
				dateStr += this.pad(this.getDate());
				break;
			case 'D':
				dateStr += this.dayNames[this.getDay()].substr(0,3);
				break;
			case 'j':
				dateStr += this.getDate();
				break;
			case 'l':
				dateStr += this.dayNames[this.getDay()];
				break;
			case 'N':
				dateStr += (this.getDay() == 0)? '7':this.getDay();
				break;
			case 'S':
				dateStr += this.getSuffix();
				break;
			case 'w':
				dateStr += this.getDay();
				break;
			case 'z':
				dateStr += this.getDayOfYear();
				break;
/*
			case 'W':
				dateStr += '*W*';
				break;
*/
			case 'F':
				dateStr += this.monthNames[this.getMonth()];
				break;
			case 'm':
				dateStr += this.pad(this.getMonth()+1);
				break;
			case 'M':
				dateStr += this.monthNames[this.getMonth()].substr(0,3);
				break;
			case 'n':
				dateStr += this.getMonth()+1;
				break;
			case 't':
				dateStr += this.getDaysInMonth();
				break;
			case 'L':
				dateStr += (this.isLeapYear())? 1:0;
				break;
/*
			case 'o':
				dateStr += '*o*';
				break;
*/
			case 'Y':
				dateStr += this.getFullYear();
				break;
			case 'y':
				dateStr += String(this.getFullYear()).substr(-2);
				break;
			case 'a':
				dateStr += this.getAmPm().toLowerCase();
				break;
			case 'A':
				dateStr += this.getAmPm().toUpperCase();
				break;
			case 'B':
				dateStr += this.getSwatchTime();
				break;
			case 'g':
				dateStr += (this.getHours()<= 12)? this.getHours():this.getHours()-12;
				break;
			case 'G':
				dateStr += this.getHours();
				break;
			case 'h':
				var hour = (this.getHours()<= 12)? this.getHours():this.getHours()-12;
				dateStr += this.pad(hour);
				break;
			case 'H':
				dateStr += this.pad(this.getHours());
				break;
			case 'i':
				dateStr += this.pad(this.getMinutes());
				break;
			case 's':
				dateStr += this.pad(this.getSeconds());
				break;
/*
			case 'e':
				dateStr += '*e*';
				break;
*/
			case 'I':
				dateStr += this.getDST();
				break;
			case 'O':
				dateStr += (this.pad(this.getTimezoneOffset()/60*-1)+'00');
				break;
			case 'P':
				dateStr += (this.pad(this.getTimezoneOffset()/60*-1)+':00');
				break;
/*
			case 'T':
				dateStr += '*T*';
				break;
*/
			case 'Z':
				dateStr += this.getTimezoneOffset()*60*-1;
				break;
			case 'c':
				dateStr += this.format('Y-m-d\\TH:i:sP');
				break;
			case 'r':
				dateStr += this.format('D, d M Y H:i:s O');
				break;
			case 'U':
				dateStr += Math.floor(this.getTime()/1000);
				break;
			case '\\':
				i++;
			default:
				dateStr += format[i];
		}
	}
	return dateStr;
}
Date.prototype.getDaysInMonth = function () {
	if (this.getMonth() == 1) {
		this.daysInMonths[1] = (this.isLeapYear())? 29:28;
	}
	return this.daysInMonths[this.getMonth()];
}
Date.prototype.getDayOfYear = function () {
	var start = Date.UTC(this.getFullYear(), 0, 0);
	var end = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate());
	return Math.floor((end - start) / (1000 * 60 * 60 * 24));
}
Date.prototype.getSuffix = function () {
	d = this.getDate();
	if (d >=11 && d <= 13) {
		return 'th';
	} else {
		switch(String(d).substr(-1)) {
			case '1':
				return 'st';
			case '2':
				return 'nd';
			case '3':
				return 'rd';
			default:
				return 'th';
		}
	}
}

Date.prototype.getSwatchTime = function () {
	return String.leftPad(Math.floor((((this.getTime()/1000/60/60/24)%1)+(1/24))*1000), 3, '0');
}

Date.prototype.getDST = function () {
	var start = new Date(this.getFullYear(), 0, 1);
	return (this.getTimezoneOffset() != start.getTimezoneOffset()) ? '1':'0';
}

Date.prototype.getAmPm = function () {
	return (this.getHours() < 12)? 'am':'pm';
}
