//$Id: order.js 3667 2009-09-21 22:45:42Z ssundheim $

// Yes -- I am aware JavaScript associative arrays are technically objects, but we are not iterating over these, 
// we're referring directly to keys. If, however, you need to iterate over these first few arrays, you will
// need to figure something else out because it will not work.

// Enter any fields that have minimum lengths here
var minLengths = new Array();
minLengths['username'] = 5;
minLengths['password'] = 5;
minLengths['site_subdomain'] = 3;
minLengths['custom_domain'] = 6;

// Enter any fields that have maximum lengths here. Although the regular form field length limit should suffice, this is just added protection
var maxLengths = new Array();
maxLengths['first_name'] = 128;
maxLengths['last_name'] = 128;
maxLengths['username'] = 50;
maxLengths['email'] = 200;
maxLengths['password'] = 50;
maxLengths['site_name'] = 200;
maxLengths['site_subdomain'] = 50;
maxLengths['site_tld'] = 128;
maxLengths['custom_domain'] = 200;
maxLengths['card_number'] = 20;
maxLengths['cardholder_name'] = 120;
maxLengths['zip'] = 50;

// Enter any elements that need regex checks done on them here
var elementRegexes = new Array();
elementRegexes['username'] = '^[A-Za-z0-9_\\.\\-]+$';
elementRegexes['site_subdomain'] = '^[A-Za-z0-9-]+$';
elementRegexes['custom_domain'] = '^[A-Za-z0-9-\\.]+\\.([a-zA-Z0-9\\.]{2,6})$';
elementRegexes['email'] = "^[a-zA-Z0-9_\\+-]+(\\.[a-zA-Z0-9_\\+-]+)*@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.([a-zA-Z]{2,4})$";
elementRegexes['first_name'] = '^[A-Za-z \\.]+$';
elementRegexes['last_name'] = '^[A-Za-z \\.]+$';
elementRegexes['cardholder_name'] = '^[A-Za-z \\.]+$';
elementRegexes['credit_cardvisa'] = "^4[0-9]{12}([0-9]{3})?$";
elementRegexes['credit_cardamex'] = "^3[47][0-9]{13}$";
elementRegexes['credit_cardmc'] = "^5[1-5][0-9]{14}$";

// Restricted words
var restrictedWords = new Array('grupthink', 'grupthinkpro', 'feedbackcommunity', 'gamerfeedback', 'socialmindscape', 'xxx', 'fuck', 'dick', 'twat', 'pussy', 'bitch', 'cunt', 'nigger', 'penis', 'vagina', 'tits', 'shit', 'piss', 'cock', 'porn', 'asshole', 'bastard', 'motherfuck', 'shitty');

// Restricted subdomains
var restrictedSubdomains = new Array('mail', 'system', 'www', 'admin', 'test', 'testing', 'shell', 'mail', 'rt', 'support', 'news', 'blog', 'wiki', 'files', 'data', 'pictures', 'images', 'static', 'info', 'sales', 'feedback', 'community', 'insights', 'ideas', 'suggestions', 'think', 'groupthink', 'contact', 'ns', 'adm', 'daemon', 'data', 'dev', 'backup', 'help', 'mysql', 'db', 'pgsql', 'psql', 'operator', 'panel', 'pop', 'imap', 'pop3', 'root', 'router', 'reboot', 'sendmail', 'shutdown', 'maintenance', 'stats', 'subdomain', 'suck', 'switch', 'sys', 'temp', 'tools', 'toolbox', 'vhost', 'web', 'webadmin', 'phpmyadmin', 'php', 'wusage', 'demo', 'example', 'vps');


// Restricted domains
var restrictedDomains = new Array('example.com', 'example.org', 'example.net');

// Enter the required fields that will be used for each given step
var requiredFields = new Array();
requiredFields[1] = new Array('site_name'); // This is dynamic based on their domain selection
requiredFields[2] = new Array('first_name', 'last_name', 'username', 'email', 'password', 'password_confirm', 'card_type', 'card_number', 'cardholder_name', 'expiration_month', 'expiration_year', 'card_type');
requiredFields[3] = new Array();
requiredFields[4] = new Array();

// This array holds information about which errors are set on the form
var errorDivNames = new Array();

// This holds the current step
var currentStep = 1;

// This holds the current cost
var currentPlanPrice = 0.00;

// This holds the current number of additional grups
var currentGrupAdditions = 0;

// This holds the current number of additional topics
var currentTopicAdditionsValue = 0;

// This holds the applied promotional codes
var appliedPromotionalCodesPercentage = new Array();
var appliedPromotionalCodesFixed = new Array();

// This function will add commas to values since JavaScript doesn't have a built-in
function addCommas(numberString) {
	// Make sure we've got a string
	numberString += '';
	
	// Make sure we only add commas before the decimal
	x = numberString.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';

	// Look for a 1 or more numbers followed by 3 digits
	var rgx = /(\d+)(\d{3})/;

	// Rock it and replace it
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}

	// Return it	
	return x1 + x2;
}

// This function checks to be sure there is a length to each of the required fields
function checkRequiredFields(stepNumber) {
	var returnValue = true;

	// Grab our required fields
	var thisRequiredFields = requiredFields[stepNumber];

	// Loop through them ensuring there is something set in the field
	for (var ii = 0; ii < thisRequiredFields.length; ii++) {
		var formValue = document.getElementById(thisRequiredFields[ii]).value;
		if (formValue.length <= 0) {
			displayError(thisRequiredFields[ii], 'This is a required field.');
			returnValue = false;
		}
	}

	return returnValue;
}

// This function will go through and check for the restricted subdomains. It will also check
// for variations on the restricted subdomains that contains numbers eg. 23948grupthink and 2348grupthink2384 and grupthink2348
function checkRestrictedSubdomains(inputName) {
	var subdomainToCheck = document.getElementById(inputName).value;
	if (subdomainToCheck == null || subdomainToCheck == '') {
		return true;
	}

	for (var ii = 0; ii < restrictedSubdomains.length; ii++) {
		var restrictedSubdomainToCheck = restrictedSubdomains[ii];
		var regexToUse = '^([0-9])?'+restrictedSubdomainToCheck+'([0-9])?$';
		var regexObject = new RegExp(regexToUse);
		if (regexObject.test(subdomainToCheck.toLowerCase())) {
			displayError(inputName, "That subdomain is not valid. A subdomain with the word '"+restrictedSubdomainToCheck+"' and only numbers in it, is reserved.. Please remove it and try again.");
			return false;
		}
	}

	return true;
}

// This function will go through the restricted words to be sure there are none
function checkRestrictedWords(elementName) {
	var stringToMatch = document.getElementById(elementName).value;
	if (stringToMatch == null || stringToMatch == '') {
		return true;
	}

	for (var ii = 0; ii < restrictedWords.length; ii++) {
		var wordToUse = restrictedWords[ii];
		if (stringToMatch.toLowerCase().indexOf(wordToUse) != -1) {
			displayError(elementName, "There is a restricted word in your input ("+wordToUse+"). Please remove it and try again.");
			return false;
		}
	}
	return true;
}

// This function will go through the restricted domains to be sure they aren't using one
function checkRestrictedDomains(elementName) {
	var stringToMatch = document.getElementById(elementName).value;
	if (stringToMatch == null || stringToMatch == '') {
		return true;
	}

	for (var ii = 0; ii < restrictedDomains.length; ii++) {
		var wordToUse = restrictedDomains[ii];
		if (stringToMatch.toLowerCase().indexOf(wordToUse) != -1) {
			displayError(elementName, "That domain is not allowed. Please try again.");
			return false;
		}
	}
	return true;
}

// This function checks to see if a particular input has a minimum length setting. If there is no setting for that element, it just returns true.
function checkMinLength(elementName) {
	// Grab our minimum length requirements for this field
	var minLength = minLengths[elementName];
	if (minLength == null || !minLength) {
		return true;
	} else {
		// If there is a minimum length requirement, check it and throw an error accordingly
		if (document.getElementById(elementName).value.length < minLength) {
			displayError(elementName, 'This field must be at least '+minLength+' characters long.');
			return false;
		}
	}
	
	return true;
}

// This function checks to see if a particular input has a maximum length setting. If there is no setting for that element, it just returns true.
function checkMaxLength(elementName) {
	// Grab our maximum length requirements for this field
	var maxLength = maxLengths[elementName];
	if (maxLength == null || !maxLength) {
		return true;
	} else {
		// If there is a maximum length requirement, check it and throw an error accordingly
		if (document.getElementById(elementName).value.length > maxLength) {
			displayError(elementName, 'This field can only be '+maxLength+' characters long.');
			return false;
		}
	}

	return true;
}

// This function will check the regex restrictions on a given element name if they exist
function checkRegex(elementName) {
	// If we are dealing with credit card number regex, then we need to find the card type to determine which regex to use
	if (elementName == 'card_number') {
		var cardType = document.getElementById('card_type').value;
		var regexToUse = elementRegexes['credit_card'+cardType];
	} else {
		var regexToUse = elementRegexes[elementName];
	}

	// If there is no regex restrictions, then we're fine
	if (regexToUse == null || !regexToUse) {
		return true;
	} else {
		// Otherwise, we'll need to grab the value in the field
		var elementValue = document.getElementById(elementName).value;

		// If this is a credit card check, we're going to remove anything that is not a number before doing the regex check
		if (elementName == 'card_type') {
			elementValue = elementValue.replace(/\D/g, '');
		}

		// Create our regex object and test it against the value in the form
		var regexObject = new RegExp(regexToUse);

		// Provide the appropriate error given the name of the input
		if (!regexObject.test(elementValue)) {
			if (elementName == 'email') {
				errorMessage = 'This email address does not appear to be valid. Please enter an email address that matches this example: emailaddress@example.com';
			} else if (elementName == 'first_name' || elementName == 'last_name' || elementName == 'cardholder_name') {
				errorMessage = 'There should only be letters in your name.';
			} else if (elementName == 'card_number') {
				errorMessage = 'This card number does not match the format for the card type provided. Please check that both the card type and number are correct.';
			} else if (elementName == 'custom_domain') {
				errorMessage = 'This domain does not appear to be valid. Please enter a domain name that matches one of these examples: example.com mysite.example.com';
			} else {
				errorMessage = 'This does not match the character restrictions for this field. Please review them and try again.';
			}
			displayError(elementName, errorMessage);
			return false;
		}
	}

	return true;
}

// Runs the Luhn algorithm on the credit card number to be sure it's valid
function validateCreditCardNumber(creditCardNumber) {
	// Remove any non-digits
	var ccNumber = creditCardNumber.replace(/\D/g, '');

	// Get our parity
	var ccParity = ccNumber.length % 2;

	// Total up our numbers
	var total = 0;
	for (var ii = 0; ii < ccNumber.length; ii++) {
		var digit = ccNumber.charAt(ii);
		if (ii % 2 == ccParity) {
			digit = digit * 2;
			if (digit > 9) {
				digit = digit - 9;
			}
		}
		total = total + parseInt(digit);
	}

	// Make sure they pass our Luhn algorithm
	if (total % 10 == 0) {
		return true;
	} else {
		displayError('card_number', 'This card number is not valid. Please review it and try again.');
		return false;
	}
}

// This will take the error divs listed in errorDivNames and remove them
function clearErrorDivs() {
	// Grab the names of the different error divs that have been shown
	for (var ii = 0; ii < errorDivNames.length; ii++) {
		var fieldName = errorDivNames[ii];
		var inputDiv = document.getElementById('formdiv'+fieldName);
		if (inputDiv != null) {
			// Remove the errors in the div
			for (jj = 0; jj < inputDiv.childNodes.length; jj++) {
				if (inputDiv.childNodes[jj].className == 'formerrordiv') {
					inputDiv.removeChild(inputDiv.childNodes[jj]);
				}
			}
		}
	}

	errorDivNames = new Array();
	return true;
}

// This function checks to be sure the two password fields match
function checkPasswordsMatch() {
	// Grab out div that the password is in
	var inputDiv = document.getElementById('formdivpassword');
	if (inputDiv != null) {
		inputDiv.className = 'row';
		// Remove any error that might be there
		if (inputDiv != null) {
			for (var ii = 0; ii < inputDiv.childNodes.length; ii++) {
				if (inputDiv.childNodes[ii].className == 'formerrordiv') {
					inputDiv.removeChild(inputDiv.childNodes[ii]);
				}
			}
		}
	}

	// Run our tests
	var checkSpan = document.getElementById('checkspanpassword');
	var checkImgSrc = '/images/nocheck.png';
	if (!checkMinLength('password', document.getElementById('password').value)) {
		if (inputDiv != null) {
			inputDiv.className = 'inputfail';
		}
	} else if (document.getElementById('password').value != document.getElementById('password_confirm').value) {
		displayError('password', 'Your passwords must match.');
		if (inputDiv != null) {
			inputDiv.className = 'inputfail';
		}
	} else {
		checkImgSrc = '/images/check.png';
	}
		
	// Clear out and append the appropriate checkbox image
	var checkImg = document.createElement('img');
	checkImg.src = checkImgSrc;
	if (checkSpan != null) {
		while (checkSpan.hasChildNodes()) {
			checkSpan.removeChild(checkSpan.firstChild);
		}
		checkSpan.appendChild(checkImg);
	}

	return true;
}

// This checks to make sure the credit card expiration date they selected is in the future
function checkDateInFuture() {
	// Grab our input div
	var inputDiv = document.getElementById('formdivexpiration_month');
	if (inputDiv != null) {
		inputDiv.className = 'row';
		// Remove any error that might be there
		if (inputDiv != null) {
			for (var ii = 0; ii < inputDiv.childNodes.length; ii++) {
				if (inputDiv.childNodes[ii].className == 'formerrordiv') {
					inputDiv.removeChild(inputDiv.childNodes[ii]);
				}
			}
		}
	}

	// Grab our check image span and remove any check images that might be there
	var checkSpan = document.getElementById('checkspanexpiration_month');
	if (checkSpan != null) {
		while (checkSpan.hasChildNodes()) {
			checkSpan.removeChild(checkSpan.firstChild);
		}
	}
	var checkImgSrc = '/images/nocheck.png';

	// Grab the entered month and year
	var userMonth = parseInt(document.getElementById('expiration_month').value);
	var userYear = parseInt(document.getElementById('expiration_year').value);

	// Grab today's month and year
	var todaysDate = new Date();
	var currentMonth = todaysDate.getMonth() + 1;
	var currentYear = todaysDate.getFullYear();

	var dateError = false;
	// If they entered a year beyond ours, we're finished
	if (userYear < currentYear) {
		dateError = true;
	} else if (userYear == currentYear) {
		// Otherwise we need to check the month
		if (userMonth <= currentMonth) {
			dateError = true;
		}
	} 

	// Display errors/successes appropriately
	if (dateError) {
		displayError('expiration_month', "You must choose an expiration date that is in the future.");
		var checkImg = document.createElement('img');
		checkImg.src = checkImgSrc;
		if (checkSpan != null) {
			checkSpan.appendChild(checkImg);
		}
		if (inputDiv != null) {
			inputDiv.className = 'inputfail';
		}
		return false;
	} else {
		var checkImg = document.createElement('img');
		checkImgSrc = '/images/check.png';
		checkImg.src = checkImgSrc;
		if (checkSpan != null) {
			checkSpan.appendChild(checkImg);
		}
		return true;
	}
}

// This will display an error in the correct area and add the error to the errorDivNames array
function displayError(elementName, message) {
	var thisElementDiv = document.getElementById('formdiv'+elementName);
	if (thisElementDiv != null) {
		var thisErrorDiv = document.createElement('div');
		thisErrorDiv.className = 'formerrordiv';
		thisErrorDiv.appendChild(document.createTextNode(message));
		thisElementDiv.appendChild(thisErrorDiv);
		errorDivNames.push(elementName);
	}
	return true;
}

// This will turn steps of the form on or off
function toggleFormDisable(stepNumber, disableOrEnable) {
	// Make sure we've got a div to work with
	var formDiv = document.getElementById('step'+stepNumber+'div');
	if (formDiv == null) {
		alert('There is no form div to work with.');
		return false;
	}

	// If it is step number 1, we have to work with this differently because there are some hidden input elements
	if (stepNumber == 1) {
		var thisRequiredFields = new Array('site_name', 'site_subdomain', 'site_tld', 'custom_domain');
	} else {
		var thisRequiredFields = requiredFields[stepNumber];
	}

	// Go through and enable/disable the form elements
	for (var ii = 0; ii < thisRequiredFields.length; ii++) {
		var inputElement = document.getElementById(thisRequiredFields[ii]);
		if (inputElement != null) {
			if (disableOrEnable) {
				inputElement.disabled = true;
			} else {
				inputElement.disabled = false;
			}
		}
	}
}

// This will check over the elements of a particular step of the form
function checkFormStep(stepNumber) {
	// First, we'll clear any existing error divs
	clearErrorDivs();

	// Check to make sure we have a valid step to work with
	if (stepNumber > 4 || stepNumber < 1) {
		alert('Invalid step number.');
		return false;
	}

	// First we'll disable the form elements on the step they are on
	toggleFormDisable(stepNumber, true);

	// If this is step number 1, we have dynamic required fields based on what they've chosen for their domain
	if (stepNumber == 1) {
		if (document.getElementById('site_tld').value == 'custom') {
			requiredFields[1] = new Array('site_name', 'custom_domain');
		} else {
			requiredFields[1] = new Array('site_name', 'site_subdomain');
		}
	}

	// Check our required fields
	if (!checkRequiredFields(stepNumber)) {
		toggleFormDisable(stepNumber, false);
		return false;
	}

	// Grab our div to check our inputs
	var stepDiv = document.getElementById('step'+stepNumber+'div');
	if (stepDiv == null) {
		alert('There is no form div to work with.');
		toggleFormDisable(stepNumber, false);
		return false;
	}

	// Go through our fields and perform tests on them
	var thisRequiredFields = requiredFields[stepNumber];
	for (var ii = 0; ii < thisRequiredFields.length; ii++) {
		var inputName = thisRequiredFields[ii];

		// Check minimum length requirements
		if (!checkMinLength(inputName)) {
			toggleFormDisable(stepNumber, false);
			return false;
		}

		// Check maximum length restrictions
		if (!checkMaxLength(inputName)) {
			toggleFormDisable(stepNumber, false);
			return false;
		}

		// Check regex restrictions
		if (!checkRegex(inputName)) {
			toggleFormDisable(stepNumber, false);
			return false;
		}

		// Check the restricted words
		if (!checkRestrictedWords(inputName)) {
			toggleFormDisable(stepNumber, false);
			return false;
		}

		// If we're dealing with a particular inputName, we have to do AJAXified ifExistsChecks
		if (inputName == 'username' || inputName == 'custom_domain' || inputName == 'site_subdomain') {
			doCheckIfExists(inputName, document.getElementById(inputName).value, 'force');
		}
	}

	// If this is step number 2, we will go ahead and verify that the passwords match and also check the expiration date
	if (stepNumber == 2) {
		// We will check that the passwords match
		if (!checkPasswordsMatch()) {
			toggleFormDisable(stepNumber, false);
			return false;
		}

		if (!checkDateInFuture()) {
			toggleFormDisable(stepNumber, false);
			return false;
		}
	}
	
	// Enable the form again 
	toggleFormDisable(stepNumber, false);
	return true;
}

// Check element functions that allow us to check some basic stuff here on the JavaScript side before we send it to the server.
// We have a helper function here to allow for our delayed onKeyUp event calls
var elementCheckCount = 0;
function doElementCheck(inputName, inputData, forceOrNot) {
	elementCheckCount = elementCheckCount + 1;
	var funcToTimeOut = "checkElement('"+inputName+"', '"+inputData+"', "+elementCheckCount+")";
	if (inputData != null && inputData != '') {
		if (forceOrNot == 'force') {
			elementCheckCount = 0;
			checkElement(inputName, inputData, 0);
		} else {
			setTimeout(funcToTimeOut, 500);
		}
	}
}

// This is the actual function that checks the element
function checkElement(inputName, inputData, currentCount) {
	if (currentCount == elementCheckCount) {
		elementCheckCount = 0;
		inputDiv = document.getElementById('formdiv'+inputName);
		if (inputDiv == null) {
			alert('No div to work with.');
		}

		inputDiv.className = 'row';
		
		// First we want to clear any error divs that may be in our element
		for (var ii = 0; ii < inputDiv.childNodes.length; ii++) {
			if (inputDiv.childNodes[ii].className == 'formerrordiv') {
				inputDiv.removeChild(inputDiv.childNodes[ii]);
			}
		}

		// We also want to clear any check images
		var checkSpan = document.getElementById('checkspan'+inputName);
		if (checkSpan != null) {
			while (checkSpan.hasChildNodes()) {
				checkSpan.removeChild(checkSpan.firstChild);
			}
		}
		
		var checkImgSrc = '/images/nocheck.png';

		// Now we can run our checks on the element. First minimum length.
		if (!checkMinLength(inputName)) {
			if (checkSpan != null) {
				var checkImg = document.createElement('img');
				checkImg.src = checkImgSrc;
				checkSpan.appendChild(checkImg);
			}
			inputDiv.className = 'inputfail';
			return false;
		}

		// Check maximum length restrictions
		if (!checkMaxLength(inputName)) {
			if (checkSpan != null) {
				var checkImg = document.createElement('img');
				checkImg.src = checkImgSrc;
				checkSpan.appendChild(checkImg);
			}
			inputDiv.className = 'inputfail';
			return false;
		}

		// Check regex restrictions
		if (!checkRegex(inputName)) {
			if (checkSpan != null) {
				var checkImg = document.createElement('img');
				checkImg.src = checkImgSrc;
				checkSpan.appendChild(checkImg);
			}
			inputDiv.className = 'inputfail';
			return false;
		}

		// Check to be sure it doesn't contain restricted words
		if (!checkRestrictedWords(inputName)) {
			if (checkSpan != null) {
				var checkImg = document.createElement('img');
				checkImg.src = checkImgSrc;
				checkSpan.appendChild(checkImg);
			}
			inputDiv.className = 'inputfail';
			return false;
		}

		// If we're dealing with the card_number input...
		if (inputName == 'card_number') { 
			// Then we also want to verify the card number
			if (!validateCreditCardNumber(document.getElementById('card_number').value)) {
				if (checkSpan != null) {
					var checkImg = document.createElement('img');
					checkImg.src = checkImgSrc;
					checkSpan.appendChild(checkImg);
				}
				inputDiv.className = 'inputfail';
				return false;
			}
		}

		// If this is the site_subdomain, we have to check to be sure it is not a restricted subdomain
		if (inputName == 'site_subdomain') {
			if (!checkRestrictedSubdomains('site_subdomain')) {
				if (checkSpan != null) {
					var checkImg = document.createElement('img');
					checkImg.src = checkImgSrc;
					checkSpan.appendChild(checkImg);
				}
				inputDiv.className = 'inputfail';
				return false;
			}
		}

		// If this is a custom_domain we have to make sure it is not a restricted custom domain
		if (inputName == 'custom_domain') {
			if (!checkRestrictedDomains('custom_domain')) {
				if (checkSpan != null) {
					var checkImg = document.createElement('img');
					checkImg.src = checkImgSrc;
					checkSpan.appendChild(checkImg);
				}
				inputDiv.className = 'inputfail';
				return false;
			}
		}

		checkImgSrc = '/images/check.png';
		if (checkSpan != null) {
			var checkImg = document.createElement('img');
			checkImg.src = checkImgSrc;
			checkSpan.appendChild(checkImg);
		}

		if (inputName == 'site_name') {
			// We want to display the new site name in the upper-right
			var siteNameElement = document.getElementById('currentsitename');
			if (siteNameElement != null) {
				if (siteNameElement.hasChildNodes()) {
					siteNameElement.removeChild(siteNameElement.firstChild);
				}
				siteNameElement.appendChild(document.createTextNode(inputData));
			}
		}

		return true;
	}
}

// This allows us to have our delayed AJAX lookup onkeyup when the user delays their typing for 500ms (.5 second)
var ifExistsCount = 0;
function doCheckIfExists(inputName, inputData, forceOrNot) {
	ifExistsCount = ifExistsCount + 1;
	var funcToTimeOut = "checkIfExists('"+inputName+"', '"+inputData+"', "+ifExistsCount+")";
	if (inputData != null && inputData != '') {
		if (forceOrNot == 'force') {
			ifExistsCount = 0;
			checkIfExists(inputName, inputData, 0);
		} else {
			setTimeout(funcToTimeOut, 500);
		}
	}
}

// This function will make an AJAX request to the database checkIfExists file to find out if a given input exists 
function checkIfExists(inputName, inputData, currentCount) {
	if (currentCount == ifExistsCount) {
		ifExistsCount = 0;
		
		document.getElementById(inputName).disabled = true;
			
		// Clear our any errors
		var inputDiv = document.getElementById('formdiv'+inputName);
		if (inputDiv != null) {
			for (var ii = 0; ii < inputDiv.childNodes.length; ii++) {
				if (inputDiv.childNodes[ii].className == 'formerrordiv') {
					inputDiv.removeChild(inputDiv.childNodes[ii]);
				}
			}
		}
		
		// Go ahead and remove any check or not check next to this
		var checkSpan = document.getElementById('checkspan'+inputName);
		if (checkSpan != null) {
			while (checkSpan.hasChildNodes()) {
				checkSpan.removeChild(checkSpan.firstChild);
			}

			var loadingImg = document.createElement('img');
			loadingImg.src = '/images/progress.gif';
			checkSpan.appendChild(loadingImg);
		}

		// Perform checks we can here client side
		elementCheckCount = 0;
		if (!checkElement(inputName, inputData, 0)) {
			// The function will have printed some error so let's give the field back to them
			document.getElementById(inputName).disabled = false;
            document.getElementById(inputName).focus();
			return false;
		}

		var inputDiv = document.getElementById('formdiv'+inputName);
		if (inputDiv != null) {
			inputDiv.className = 'row';
		}
		
		// Get our AJAX ready
		var postURI = '/order/ajax_exists';
		var postString = 'inputname='+inputName+'&inputvalue='+inputData;

		// Send it away
		loadXMLDocPost(postURI, postString);
	}
}

// This function will make an AJAX request to see if a particular form input exists or not
function returnFromCheckIfExists(input, results, success) {
	// Response for the lookup
	var existsOrNot = results[0].getElementsByTagName('existsornot')[0].firstChild.data;

	// Element that was being looked up
	var inputName = results[0].getElementsByTagName('inputelement')[0].firstChild.data;

	// If the response was invalid, this is the reason why
	var invalidReason = results[0].getElementsByTagName('invalidreason')[0].firstChild.data;

	// The step number that should be shown if there was a problem
	var stepNumber = results[0].getElementsByTagName('stepnumber')[0].firstChild.data;

	var checkSpan = document.getElementById('checkspan'+inputName);
	var inputDiv = document.getElementById('formdiv'+inputName);
	if (checkSpan != null) {
		// Remove any existing images in the span
		while (checkSpan.hasChildNodes()) {
			checkSpan.removeChild(checkSpan.firstChild);
		}

		var checkImgSrc = '/images/nocheck.png';

		// If it exists or invalid, we need to show 'em an error
		if (existsOrNot == 'exists') {
			// Then we need to show them an error
			displayError(inputName, 'Already exists. Please try something else.');
			if (inputDiv != null) {
				inputDiv.className = 'inputfail';
			}
		} else if (existsOrNot == 'invalid') {
			if (invalidReason == 'none') {
				displayError(inputName, 'Invalid entry. Please try something else.');
			} else {
				var invalidMessage = invalidReason+' Please try something else.';
				displayError(inputName, invalidMessage);
			}
			if (inputDiv != null) {
				inputDiv.className = 'inputfail';
			}
		} else {
			checkImgSrc = '/images/check.png';
			if (inputName == 'site_subdomain' || inputName == 'custom_domain') {
				var currentDomainNameElement = document.getElementById('currentdomainname');
				if (currentDomainNameElement != null) {
					if (currentDomainNameElement.hasChildNodes()) {
						currentDomainNameElement.removeChild(currentDomainNameElement.firstChild);
					}
					var replacementDomainName = document.getElementById(inputName).value;
					if (inputName != 'custom_domain') {
						replacementDomainName += document.getElementById('site_tld').value;
					}
					currentDomainNameElement.appendChild(document.createTextNode(replacementDomainName));
				}
			}
		}

		// Go ahead and append the proper check image
		var checkImg = document.createElement('img');
		checkImg.src = checkImgSrc;
		checkSpan.appendChild(checkImg);
	}

	// Make sure the form element they were dealing with is enabled
	document.getElementById(inputName).disabled = false;

	// Make sure they're looking at the step this AJAX check was performed for if they aren't
	if (existsOrNot == 'exists' || existsOrNot == 'invalid') {
		// We want to make sure they are looking at that step
		showStep(stepNumber, 'force');
	}
}

// Toggle between showing the different steps in the form
function showStep(stepNumber, forceOrNot) {
	// First we need to check everything in the current step
	if (stepNumber < 1 || stepNumber > 4) {
		return false;
	}

	// If we want the switch forced (no element checks) then we do so here
	if (forceOrNot != 'force') {
		// If they aren't forcing it, let's do our check for this step
		if (!checkFormStep(currentStep)) {
			return false;
		}
	}

	// Let's hide the current step and show the new step if everything went well with the checks
	var newStepID = 'step'+stepNumber+'div';
	var currentStepDiv = document.getElementById('step'+currentStep+'div');
	var newStepDiv = document.getElementById(newStepID);
	if (newStepDiv.className != "stepactive") {
		if (currentStepDiv != null) {
			currentStepDiv.style.display = 'none';
		}
		var stepSpan = document.getElementById('step'+currentStep+'span');
		if (stepSpan != null) {
			stepSpan.className = "stepinactive";
		}
		if (newStepDiv != null) {
			showme(newStepID);
		}
		var stepSpan = document.getElementById('step'+stepNumber+'span');
		if (stepSpan != null) {
			stepSpan.className = "stepactive";
		}

		currentStep = stepNumber;
	}
}

// These helper functions allow our delays when doing upgrade handling because of the dynamic nature of one of the elements
var alterUpgradesCount = 0;
function doAlterUpgrade(addOrRemove, price, upgradeName, forceOrNot) {
	alterUpgradesCount = alterUpgradesCount + 1;
	var funcToTimeOut = "alterUpgrade('"+addOrRemove+"', "+price+", '"+upgradeName+"', "+alterUpgradesCount+")";
	if (forceOrNot == 'force') {
		alterUpgradesCount = 0;
		alterUpgrade(addOrRemove, price, upgradeName, 0);
	} else {
		setTimeout(funcToTimeOut, 500);
	}
}

// This will alter the price and show the upgrade
function alterUpgrade(addOrRemove, price, upgradeName, currentCount) {
	if (currentCount == alterUpgradesCount) {
		alterUpgradesCount = 0;
		var currentPriceElement = document.getElementById('currentprice');
		var upgradeElement = document.getElementById('currentpriceupgrade'+upgradeName);

		// If this is the grup_upgrades element, then we need to have special handling since it's completely dynamic and user-controllable
		if (upgradeName == 'grup_upgrades') {
			// First we'll check to be sure it's a number
			var grupUpgradeElement = document.getElementById('grup_upgrades');
			var regexObject = new RegExp('^[0-9]+$');
			if (!regexObject.test(grupUpgradeElement.value)) {
				// If it isn't a number, we'll just clear the field
				grupUpgradeElement.value = '';
			} 

			// If they are requesting more than 0 grups
			if (grupUpgradeElement.value > 0) {
				// Check to see if the current grup upgrades is set. If so...
				if (currentGrupAdditions > 0 && currentGrupAdditions != grupUpgradeElement.value) {
					// Let's remove the previous upgrade's price
					currentPlanPrice = currentPlanPrice - (price * currentGrupAdditions);
				}

				// If the value in the box is different than the value stored, we need to change the price
				if (currentGrupAdditions != grupUpgradeElement.value) {
					currentPlanPrice = currentPlanPrice + (price * grupUpgradeElement.value);
				}

				// Remove the current price
				while (currentPriceElement.hasChildNodes()) {
					currentPriceElement.removeChild(currentPriceElement.firstChild);
				}

				// Put in the new price
				currentPriceElement.appendChild(document.createTextNode('$'+addCommas(currentPlanPrice.toFixed(2))));

				// Since this is a dynamic price, we'll need to inform our upgrade listing on the right of the price of the upgrade so we'll
				// go ahead and remove the upgrade listing that is there.
				while (upgradeElement.hasChildNodes()) {
					upgradeElement.removeChild(upgradeElement.firstChild);
				}

				// Create our new upgrade price text/link
				var thisUpgradePrice = price * grupUpgradeElement.value;
				var newPriceLink = document.createElement('a');
				newPriceLink.onclick = function () {
					showStep('3');
					return false;
				}
				newPriceLink.href = "#";

				// Put our new ugprade price link in there
				newPriceLink.appendChild(document.createTextNode('+$'+addCommas(thisUpgradePrice)+'.00 (Additional Groups)'));
				upgradeElement.appendChild(newPriceLink);

				// Show out new upgrade price link
				upgradeElement.className = 'activeupgrade';

				// Set our currentGrupAdditions variable globally
				currentGrupAdditions = grupUpgradeElement.value;
			} else if (grupUpgradeElement.value <= 0 || grupUpgradeElement.value == null || grupUpgradeElement.value == '') {
				// There are trying to 0 out the grup upgrades
				if (upgradeElement.className != 'inactiveupgrade') {
					upgradeElement.className = 'inactiveupgrade';
					
					// Update upgrade price and total price if necessary
					if (currentGrupAdditions > 0) {
						currentPlanPrice = currentPlanPrice - (price * currentGrupAdditions);
						while (currentPriceElement.hasChildNodes()) {
							currentPriceElement.removeChild(currentPriceElement.firstChild);
						}
						currentPriceElement.appendChild(document.createTextNode('$'+addCommas(currentPlanPrice.toFixed(2))));
					}

					// Set our currentGrupAdditions variable globally
					currentGrupAdditions = 0;
				}
			}
		} else if (upgradeName == 'topic_upgrades') {
			if (currentTopicAdditionsValue != price) {
				if (currentTopicAdditionsValue > 0) {
					currentPlanPrice = currentPlanPrice - currentTopicAdditionsValue;
				}

				if (price > 0) {
					currentPlanPrice = currentPlanPrice + price;
				}
			}

			// Remove the current price
			while (currentPriceElement.hasChildNodes()) {
				currentPriceElement.removeChild(currentPriceElement.firstChild);
			}

			currentPriceElement.appendChild(document.createTextNode('$'+addCommas(currentPlanPrice.toFixed(2))));
						
			// Since this is a dynamic price, we need to change the value on the right appropriately
			while (upgradeElement.hasChildNodes()) {
				upgradeElement.removeChild(upgradeElement.firstChild);
			}

			// Create/replace our new upgrade price text/link
			if (price > 0) {
				var newPriceLink = document.createElement('a');
				newPriceLink.onclick = function () {
					showStep('3');
					return false;
				}
				newPriceLink.href = "#";
	
				// Put our new ugprade price link in there
				newPriceLink.appendChild(document.createTextNode('+$'+price+'.00 (Additional Topics)'));
				upgradeElement.appendChild(newPriceLink);
	
				// Show out new upgrade price link
				upgradeElement.className = 'activeupgrade';
			} else {
				upgradeElement.className = 'inactiveupgrade';
			}

			// Set our currentTopicAdditionsValue variable globally
			currentTopicAdditionsValue = price;
			
		} else if (addOrRemove == 'add') {
			// If this element does not need special treatment, then we are just adding/removing costs/spans. If they are
			// adding, then we'll add to the price and show the upgrade link.
			if (upgradeElement.className != "activeupgrade") {
				upgradeElement.className = "activeupgrade";
				currentPlanPrice = currentPlanPrice + price;
				while (currentPriceElement.hasChildNodes()) {
					currentPriceElement.removeChild(currentPriceElement.firstChild);
				}
				currentPriceElement.appendChild(document.createTextNode('$'+addCommas(currentPlanPrice.toFixed(2))));
			}
		} else {
			// If they are removing, then we'll remove the upgrade price and hide the upgrade link
			if (upgradeElement.className != "inactiveupgrade") {
				upgradeElement.className = "inactiveupgrade";
				currentPlanPrice = currentPlanPrice - price;
				while (currentPriceElement.hasChildNodes()) {
					currentPriceElement.removeChild(currentPriceElement.firstChild);
				}
				currentPriceElement.appendChild(document.createTextNode('$'+addCommas(currentPlanPrice.toFixed(2))));
			}
		}
	}

	if (appliedPromotionalCodesPercentage.length > 0 || appliedPromotionalCodesFixed.length > 0) {
		calculateCostWithPromoCodes();
	}
}

// This function will fire off an AJAX request and apply a promotional code if necessary
function checkPromotionalCode() {
	promoCodeBox = document.getElementById('promo_code');
	var promotionalCode = promoCodeBox.value;
	if (promotionalCode == null || promotionalCode == '') {
		return false;
	}

	var inputName = 'promo_code';

	promoCodeBox.disabled = true;
	document.getElementById('promo_code_button').disabled = true;
	document.getElementById('promo_code_loading').style.display = '';

	// Clear our any errors
	var inputDiv = document.getElementById('formdiv'+inputName);
	if (inputDiv != null) {
		for (var ii = 0; ii < inputDiv.childNodes.length; ii++) {
			if (inputDiv.childNodes[ii].className == 'formerrordiv') {
				inputDiv.removeChild(inputDiv.childNodes[ii]);
			}
		}
	}
	
	// Go ahead and remove any check or not check next to this
	var checkSpan = document.getElementById('checkspan'+inputName);
	if (checkSpan != null) {
		while (checkSpan.hasChildNodes()) {
			checkSpan.removeChild(checkSpan.firstChild);
		}
	}

	// Perform checks we can here client side
	elementCheckCount = 0;
	if (!checkElement(inputName, promotionalCode, 0)) {
		// The function will have printed some error so let's give the field back to them
		promoCodeBox.disabled = false;
		document.getElementById('promo_code_button').disabled = false;
		document.getElementById('promo_code_loading').style.display = 'none';
		return false;
	}

	// Setup our AJAX request
	//var postURI = '/ajaxserver/checkpromocode.php5';
	var postURI = '/order/ajax_promocode';
	var postString = 'code='+promotionalCode;

	// Send it away
	loadXMLDocPost(postURI, postString);
}

function getTopicUpgradePrice(numberOfTopics) {
	if(numberOfTopics == 200) {
		return 10;
	} else if (numberOfTopics == 1000) {
		return 30;
	} else if (numberOfTopics == 10000) {
		return 100;
	}
}

// This function will handle the return for our promo code check
function returnFromCheckPromotionalCode(input, results, success) {
	// Response from the lookup
	var existsOrNot = results[0].getElementsByTagName('existsornot')[0].firstChild.data;

	// Discount to apply
	var discountToApply = parseFloat(results[0].getElementsByTagName('discount')[0].firstChild.data);

	// Discount Description
	var discountDescription = results[0].getElementsByTagName('discountdescription')[0].firstChild.data;
	
	// If the reason was invalid, this is the reason why
	var invalidReason = results[0].getElementsByTagName('invalidreason')[0].firstChild.data;

	// The type of discount
	var discountType = results[0].getElementsByTagName('discounttype')[0].firstChild.data;

	promoCodeDiv = document.getElementById('formdivpromo_code');
	promoCodeCheckSpan = document.getElementById('checkspanpromo_code');

	document.getElementById('promo_code').disabled = false;
	document.getElementById('promo_code_button').disabled = false;
	document.getElementById('promo_code_loading').style.display = 'none';

	while (promoCodeCheckSpan.hasChildNodes()) {
		promoCodeCheckSpan.removeChild(promoCodeCheckSpan.firstChild);
	}
	var checkImgSrc = '/images/nocheck.png';

	// If it exists or invalid, we need to show 'em an error
	if (existsOrNot == 'no') {
		// Then we need to show them an error
		displayError('promo_code', 'This promotional code does not exist or is no longer valid.');
		if (promoCodeDiv != null) {
			promoCodeDiv.className = 'inputfailside';
		}
	} else if (existsOrNot == 'invalid') {
		if (invalidReason == 'none') {
			displayError('promo_code', 'Invalid entry for promotional code. Please review your code and try again.');
		} else if (invalidReason != 'goodtogo') {
			var invalidMessage = invalidReason+' Please try something else.';
			displayError('promo_code', invalidMessage);
		}
		if (promoCodeDiv != null) {
			promoCodeDiv.className = 'inputfailside';
		}
	} else {
		// The promo code existed so we want to give a success and apply the code/discount
		checkImgSrc = '/images/check.png';

		var discountSpan = document.getElementById('currentpriceupgradepromo_code');
		if (discountSpan.className == 'activeupgrade') {
			discountSpan.appendChild(document.createElement('br'));
		}
		if (discountType == 'percent') {
			discountSpan.appendChild(document.createTextNode('- %'+discountToApply+' ('+discountDescription+')'));
			appliedPromotionalCodesPercentage.push(discountToApply);
		} else {
			discountSpan.appendChild(document.createTextNode('- $'+discountToApply.toFixed(2)+' ('+discountDescription+')'));
			appliedPromotionalCodesFixed.push(discountToApply);
		}
		
		discountSpan.className = 'activeupgrade';

		calculateCostWithPromoCodes();
	}

	// Go ahead and append the proper check image
	var checkImg = document.createElement('img');
	checkImg.src = checkImgSrc;
	promoCodeCheckSpan.appendChild(checkImg);
}

// This function will replace the current price with a recalculated one that takes promotional codes into account
function calculateCostWithPromoCodes() {
	var discountedPrice = parseFloat(currentPlanPrice);
	if (appliedPromotionalCodesPercentage.length > 0) {
		for (var ii = 0; ii < appliedPromotionalCodesPercentage.length; ii++) {
			var discountPercentage = parseFloat(appliedPromotionalCodesPercentage[ii]) * 0.01;
			var discountToApply = discountedPrice * discountPercentage;
			discountedPrice = discountedPrice - discountToApply;
		}
	}
	if (appliedPromotionalCodesFixed.length > 0) {
		for (var ii = 0; ii < appliedPromotionalCodesFixed.length; ii++) {
			discountedPrice = discountedPrice - appliedPromotionalCodesFixed[ii];
		}
	}

	if (discountedPrice <= 0) {
		discountedPrice = 0;
	}

	if (discountedPrice != currentPlanPrice) {
		var currentPriceElement = document.getElementById('currentprice');
		while (currentPriceElement.hasChildNodes()) {
			currentPriceElement.removeChild(currentPriceElement.firstChild);
		}
		currentPriceElement.appendChild(document.createTextNode('$'+addCommas(discountedPrice.toFixed(2))));
	}
}
