function setupSignup(options) {
	// store the options..
	$('div#globals').data('options', options);

	// hide all the valids
	$('span.valid_field').hide();
	$('span.invalid_field').hide();

	// setup the login link and the tos link
    $('a#tos').attr('href', options.tos_url);
	
    $('a#why').click(function() {
    	$('#why_dialog').dialog('open');
		return false;
    });
	
	$('a#btnSubmit').click(function() {
		// cause all the validation to go off...
		$('input.req_immediate').blur();
		$('input.req_text').blur();
		$('select.req_select').change();
		
		var formIsValid= updateValidation();
		var requireConfirmation= false;
		
		if(requireConfirmation && $(this).html()=='Confirm') {
			// go to confirm..
			lockSection('information', true);
			lockSection('billing', true);
			lockSection('credit_card', true);
			lockSection('confirmation', true);
			// $(this).html('Submit');
		} else {
			if(formIsValid) {
				// submit the form...
			    var submit_options = { 
			        target:        '#output1',   // target element(s) to be updated with server response 
			        success:       function(result, statusText) {
	 					$('#submitting_dialog').dialog('close');

						if(result.success) {
							if(getOption('successful_or_login'))
							{
								getOption('successful_or_login')('success');
							}
							// on success, redirect to the welcome page..
							document.location.href= getOption('welcome_page_url');
						} else {
							var bad_fields= result.result.bad_fields;
						
							if(bad_fields && bad_fields.length>0)
							{
								// set the focus on one of the bad fields.
								for(var ii= 0; ii<bad_fields.length; ii++)
								{
									$('#'+bad_fields[ii]).val('');
								}
								$('#'+bad_fields[0]).focus();

								// reforce validation
								$('input.req_immediate').blur();
								$('input.req_text').blur();
								$('select.req_select').change();
							}
							
							// whatever the result was, goes into the validation errors dialog
							$('div#validation_summary').html(result.message);
							$('div#validation_summary').show(); // make sure it's visible.
				        	$('#validation_errors_dialog').dialog('open');
						}
			        },  // post-submit callback 

					failure: function (XMLHttpRequest, statusText, errorThrown) {
					  // typically only one of textStatus or errorThrown 
					  // will have info
	 					$('#submitting_dialog').dialog('close');

					    alert('Failure: ' + statusText + '\n\nresponseText: \n' + errorThrown + 
					        '\n\nThe output div should have already been updated with the responseText.');        
					},
					
					dataType: 'json',
					url: remoteURL()+'&cmd=post'
			        // other available options: 
			        //url:       url         // override for form's 'action' attribute 
			        //type:      type        // 'get' or 'post', override for form's 'method' attribute 
			        //dataType:  null        // 'xml', 'script', or 'json' (expected server response type) 
			        //clearForm: true        // clear all form fields after successful submit 
			        //resetForm: true        // reset the form after successful submit 
			 
			        // $.ajax options can be used here too, for example: 
			        //timeout:   3000 
			    }; 
			 
			 	// open a "submitting your order" dialog....
			 	
			 	// they have to be enabled to submit them (sigh)
			 	if(requireConfirmation) {
					lockSection('information', false);
					lockSection('billing', false);
					lockSection('credit_card', false);
					lockSection('confirmation', false);
				}
				
				$('#submitting_dialog').dialog('open');
				$('form#myForm').ajaxSubmit(submit_options);
			} else {
	        	$('#validation_errors_dialog').dialog('open');
			}
		}
		
		return false;
	});

	$('select.req_select').change(function() {
		switch($(this).attr('id')) {
			case 'cc_exp_month':
			case 'cc_exp_year':
				var valid= false;
				try {
					var year= parseInt($('select#cc_exp_year').val());
					var month= parseInt($('select#cc_exp_month').val());
					var d= new Date();
					d.setDate(1);
					d.setHours(0);
					d.setMinutes(0);
					d.setSeconds(0);
					d.setMilliseconds(0);
					d.setFullYear(year);
					d.setMonth(month); // after set year to move to next if needed.
					
					//alert(d.toString());
					var now= new Date();
					valid= (now.getTime() < d.getTime());
				} catch (err) {
				}
				mark_select_valid('cc_expiration', valid);
				// fallthrough...
		
			default:
				mark_select_valid($(this).attr('id'), $(this).val().length);
				break;
		}
		updateValidation();
	});
	
	// this is no longer a req_select, as it will always have a value.
	// needed because we don't want the validation to change this.
	$('select#country').change(function() {
		// changing country causes things to change.
		setCountry($("select#country").val());

		mark_select_valid($(this).attr('id'), $(this).val().length);
		updateValidation();		
	});

	
	// these prevent you from going back and changing something and verify working...
	var emailVerified= false;
	var passwordVerified= false;
	
	$('input.req_immediate').keyup(function() {
		switch($(this).attr('id')) {
			case 'email':
				validateEmail($(this).val());
				if(emailVerified) {
					mark_input_valid('verify_email', 
						($('input#email').val().length && 
						$('input#email').val()==$('input#verify_email').val()));
				}
				break;
			
			case 'verify_email':
				mark_input_valid('verify_email', 
					($('input#email').val().length && 
					$('input#email').val()==$(this).val()));
				emailVerified= true;
				break;

			case 'password':
				mark_input_valid($(this).attr('id'), $(this).val().length>=6);
				if(passwordVerified) {
					mark_input_valid('verify_password', 
						($('input#password').val().length && 
						$('input#password').val()==$('input#verify_password').val()));
				}
				break;
		
			case 'verify_password':
				mark_input_valid('verify_password', 
					($('input#password').val().length && 
					$('input#password').val()==$(this).val()));
				passwordVerified= true;
				break;
		}
	});

	// serious duplication going on here.  pull these out and put in one validate() function
	$('input.req_immediate').blur(function() {
		switch($(this).attr('id')) {
			case 'email':
				validateEmail($(this).val());
				if(emailVerified) {
					mark_input_valid('verify_email', 
						($('input#email').val().length && 
						$('input#email').val()==$('input#verify_email').val()));
				}
				break;
			
			case 'verify_email':
				mark_input_valid('verify_email', 
					($('input#email').val().length && 
					$('input#email').val()==$(this).val()));
				emailVerified= true;
				break;

			case 'password':
				mark_input_valid($(this).attr('id'), $(this).val().length>=6);
				if(passwordVerified) {
					mark_input_valid('verify_password', 
						($('input#password').val().length && 
						$('input#password').val()==$('input#verify_password').val()));
				}
				break;
		
			case 'verify_password':
				mark_input_valid('verify_password', 
					($('input#password').val().length && 
					$('input#password').val()==$(this).val()));
				passwordVerified= true;
				break;
		}
	});
/*
	$('input.req_text').keypress(function() {
alert($(this).attr('id')+" got a keypress event");
	});
	
	$('input.req_text').keydown(function() {
alert($(this).attr('id')+" got a keydown event");
	});
	
	$('input.req_text').keyup(function() {
alert($(this).attr('id')+" got a keyup event");
	});
*/
	
	$('input.req_text').blur(function() {
//alert($(this).attr('id')+" got a change event");
		switch($(this).attr('id')) {
			case 'email':
				validateEmail($(this).val());
				if(emailVerified) {
					mark_input_valid('verify_email', 
						($('input#email').val().length && 
						$('input#email').val()==$('input#verify_email').val()));
				}
				break;
			
			case 'verify_email':
				mark_input_valid('verify_email', 
					($('input#email').val().length && 
					$('input#email').val()==$(this).val()));
				emailVerified= true;
				break;
			
			case 'phone':
				validate_phone($(this));
				break;
			
			case 'us_zip': // this is doubling up.
				mark_input_valid($(this).attr('id'), $(this).val().replace(/[^\d]/g,'').length>=5);
				break;
			
			case 'password':
				mark_input_valid($(this).attr('id'), $(this).val().length>=6);
				if(passwordVerified) {
					mark_input_valid('verify_password', 
						($('input#password').val().length && 
						$('input#password').val()==$('input#verify_password').val()));
				}
				break;
		
			case 'verify_password':
				mark_input_valid('verify_password', 
					($('input#password').val().length && 
					$('input#password').val()==$(this).val()));
				passwordVerified= true;
				break;
			
			case 'cc_num':
				cc_valid= valid_credit_card($(this).val()); // isCreditCard()
				if(cc_valid) 
				{
					var the_cc_type= "";
					// autopopulate the type.
					switch($(this).val().charAt(0))
					{
						case '3': the_cc_type= "American Express"; break;
						case '4': the_cc_type= "Visa"; break;
						case '5': the_cc_type= "MasterCard"; break;
						case '6': the_cc_type= "Discover"; break;
					}

					if(the_cc_type.length>0) {
						$('select#cc_type').val(the_cc_type);
						$('select#cc_type').change();
					}
				}
				mark_input_valid($(this).attr('id'), cc_valid);
				break;
			
			case 'terms_of_service':
				mark_input_valid($(this).attr('id'), $(this).val());
				break;
				
			case 'company':
			case 'address_1':
			case 'other_postal_code':
			case 'other_state':
				mark_input_valid($(this).attr('id'), true); // always valid.
				break;
			
			case 'fname':
			case 'lname':
				if($('input#fname').val().length && 
					$('input#lname').val().length &&
					$('input#cc_name').val().length==0)
				{
					// prefill in the user's cc name.
					$('input#cc_name').val($('input#fname').val() + ' ' +$('input#lname').val());
				}
				mark_input_valid($(this).attr('id'), $(this).val().length);
				break;
			
			default:
				mark_input_valid($(this).attr('id'), $(this).val().length);
				break;
		}
		updateValidation();
	});

	// setup the expiration years.
	$('select#cc_exp_year').html('<option value=""></option>');
	startYear= new Date().getFullYear();
	for(ii= 0; ii<10; ii++)
	{
		year= startYear+ii;
		$("<option value='"+year+"'>"+year+"</option>").appendTo('select#cc_exp_year');
	}

	$('input#us_zip').change(function() {
		countryCode= $('select#country').val();
		zip= $('input#us_zip').val();

		// convert to digits only..
		var zipDigits= zip.replace(/[^\d]/g,'');
		mark_input_valid('input#us_zip', zipDigits.length>=5);

		if(zipDigits>=5) {
			// disable until we're back..
			$('select#us_state').attr("disabled", true); 
			$('input#us_city').attr("readonly", "readonly"); 

			$.getJSON(remoteURL()+"&cmd=cityStateForZip&cc="+countryCode+"&zip="+zipDigits.substring(0, 5),
        		function(data){
					// now reenable...
					if(!$("div#billing").hasClass('locked')) {
						$('select#us_state').removeAttr("disabled"); 
						$('input#us_city').removeAttr("readonly"); 
					}

        			if(data.success)
        			{
        				$('input#us_city').val(data.result[0].city);
        				$('select#us_state').val(data.result[0].state);	
        				
        				// force the validation
        				$("input#us_city").blur();
        				$("select#us_state").change();      				
//        				mark_input_valid('us_city', data.result[0].city.length);
        			}
	        	}
	        );
	   }
	});
	
	// canada has it as well...
	$('input#ca_postal_code').change(function() {
		// fetch the city and state for this zip...
		
		// disable until we're back..
		$('select#ca_state').attr("disabled", true); 
		$('input#ca_city').attr("disabled", true); 

		countryCode= $('select#country').val();
		zip= $('input#ca_postal_code').val();

		$.getJSON(remoteURL()+"&cmd=cityStateForZip&cc="+countryCode+"&zip="+zip,
    		function(data){
				// now reenable...
				$('select#ca_state').removeAttr("disabled"); 
				$('input#ca_city').removeAttr("disabled"); 

    			if(data.success)
    			{
    				$('input#ca_city').val(data.result[0].city);
    				$('select#ca_state').val(data.result[0].state);	
    			}
        	}
        );
	});	

	$('a.confirm-button').click(function() {
		if($(this).html()=='Edit') {
			lockSection($(this).attr('name'), false);
		} else {
			if(validateSection($(this).attr('name'))) 
			{
				lockSection($(this).attr('name'), true);
			}
		}
		return false;
	});
	
	$('#submitting_dialog').dialog({
		autoOpen: false,
		width: 600,
		modal: true,
		resizable: false
	});
	
	$('#why_dialog').dialog({
		autoOpen: false,
		width: 600,
		modal: true,
		resizable: false,
		buttons: {
			"Close": function() {
				$(this).dialog("close");
			}
		}
	});

	$('#validation_errors_dialog').dialog({
		autoOpen: false,
		width: 600,
		modal: true,
		resizable: false,
		buttons: {
			"Close": function() {
				$(this).dialog("close");
			}
		}
	});
		
	$('#already_exists_dialog').dialog({
		autoOpen: false,
		width: 600,
		modal: true,
		resizable: false,
		buttons: {
			"Login": function() { 
				$(this).dialog("close"); 
				if(getOption('successful_or_login'))
				{
					getOption('successful_or_login')('login');
				}
				document.location.href= getOption('login_url');
			}, 
			"Try Another": function() { 
				$('input#email').val('');
				$('input#verify_email').val('');
				$('input#email').focus();
				$('input#valid_email').hide();
			
				$(this).dialog("close"); 
			} 
		}
	});		

	// now load things.	
	// AJAX load the country list....
	loadCountries();
	loadProducts();
}

function getOption(name) {
	var options= $('div#globals').data('options');
	return options[name];
}

function remoteURL() {
	return getOption('remote_url')+'?nid='+getOption('signup_key');
}

function valid_credit_card(digits)
{
	var digitsOnly= digits.replace(/[^\d]/g,'');
	var valid= false;
	
	if(digitsOnly.length)
	{
		switch(digitsOnly.charAt(0))
		{
			case '3': // amex
				if(digitsOnly.length==15)
				{
					valid= isCreditCard(digitsOnly);
				}
				break;
			case '4': // visa
			case '5': // mastercard
			case '6': // discover.
				if(digitsOnly.length==16)
				{
					valid= isCreditCard(digitsOnly);
				}
				break;
		}
	}
	
	return valid;
}


function validateSection(sectionName) {
	valid= false;

	$('div#'+sectionName+' input.req_immediate').blur();		
	$('div#'+sectionName+' input.req_text').blur();
	$('div#'+sectionName+' select.req_select').change();

	if($('div#'+sectionName+' .invalid_field:visible').length==0) {
		valid= true;
	}
	
	return valid;
}

function lockSection(sectionName, locked) {
	if(locked) {
		$("div#"+sectionName).addClass('locked');
		$("div#"+sectionName+" input[type='text']").attr('readonly', 'readonly');
		$("div#"+sectionName+" input[type='password']").attr('readonly', 'readonly');
		$("div#"+sectionName+" input[type='checkbox']").attr('disabled', 'disabled');
		$("div#"+sectionName+" select").attr('disabled', 'disabled');
		$("div#"+sectionName+" a.confirm-button").html('Edit').show();
	} else {
		$("div#"+sectionName).removeClass('locked');
		$("div#"+sectionName+" input[type='text']").removeAttr('readonly');
		$("div#"+sectionName+" input[type='password']").removeAttr('readonly');
		$("div#"+sectionName+" input[type='checkbox']").removeAttr('disabled');
		$("div#"+sectionName+" select").removeAttr('disabled');
		$("div#"+sectionName+" a.confirm-button").html('Change').show();
	}
}

function updateValidation()
{
	var valid= true;

	$('div#validation_summary').html('<p>Please fix the following issues:<ul>');
		$.each($('.invalid_field:visible'), function(i,item){ 
			// workaround IE8 has a bug with offsetWidth/offsetHeight
			if($(item).css('display')!='none') 
			{
				// add it...
				if($(item).attr('title').length>0) {
					$('<li>'+$(item).attr('title')+'</li>').appendTo('div#validation_summary');
				} else {
					$('<li>'+item.innerText+'</li>').appendTo('div#validation_summary');
				}
				valid= false;
			}
      });
	$('</ul></p>').appendTo('div#validation_summary');

	// in invisibile dialog, don't hide it, or else...
	if(valid) {
		$('div#validation_summary').hide();
	} else {
		$('div#validation_summary').show();
	}
	
	return valid;
}

function validate_phone(phone_elem)
{
	switch($("select#country").val())
	{
		case 'US':
		case 'PR':
		case 'CA':
			// us specific stuff in here...
			var num= phone_elem.val().replace(/[^\d]/g,'');
			mark_input_valid(phone_elem.attr('id'), num.length==10);
			if(num.length == 10) {
               var str = "(" + num.substring(0,3) + ") " +
                            num.substring(3, 6) + "-" + num.substring(6);
               phone_elem.val(str);
            }
			break;
			
		default:
			mark_input_valid(phone_elem.attr('id'), checkInternationalPhone(phone_elem.val()));
			break;
	}
}

function mark_input_valid(id, valid) {
	if(valid) {
		$('input#'+id).removeClass('invalid');
		$('span#invalid_'+id).hide();
		$('span#valid_'+id).show();
	} else {
		$('input#'+id).addClass('invalid');
		$('span#invalid_'+id).show();
		$('span#valid_'+id).hide();
	}
}

function mark_select_valid(id, valid) {
	if(valid) {
		$('select#'+id).removeClass('invalid');
		$('span#invalid_'+id).hide();
		$('span#valid_'+id).show();
	} else {
		$('select#'+id).addClass('invalid');
		$('span#invalid_'+id).show();
		$('span#valid_'+id).hide();
	}
}

function validateEmail(email)
{
	var emailRegEx = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;

	if(email.search(emailRegEx)==-1) {
		mark_input_valid('email', false);
	} else {
		mark_input_valid('email', true);
		$.getJSON(remoteURL()+"&cmd=checkEmail&e="+email,
    		function(data){
    			if(data.result.exists) {
    				// alert("Your email exists in the system.  This will be a dialog asking if you want to a) Try another, or b) Login");
    				// $('#already_exists_dialog p').htmlremoteURL();
					$('#already_exists_dialog').dialog('open');
    			}
        	}
        );
   }
}

function getDefaultCountry()
{
	$.getJSON(remoteURL()+"&cmd=defaultCountryForIP",
		function(data){
			// programmatically set to default, then cause it to adjust the form.
		  	$("select#country").val(data.result[0].cc);
			setCountry($("select#country").val());
			$("select#country").change();
			
			// countries loaded, and the default has been set.
			$('div#billing').show();
			$('div#loading_billing').hide();
    	}
    );
}


function loadProducts()
{
	$.getJSON(remoteURL()+"&cmd=params",
		function(data){
			// clear the products
			$('div#products').html('');
      		$.each(data.result.products, function(i,item){
      			// add it...
				$('<div class="product"><table><tr><td valign="top"><input type="radio" name="product" value="'+item.code+'" '+((i==0)?'checked="checked"':'')+'/></td><td><strong>'+item.name+'</strong><br/>'+item.desc+'</td></tr></table></div>').appendTo('div#products');
/*      			
				$('<div class="product"><input type="radio" name="product" value="'+item.code+'" '+((i==0)?'checked="checked"':'')+'/><b>'+item.name+'</b><br/>'+item.desc+'</div>').appendTo('div#products');
*/
	          });
	          
	        // now update the links.
	        // $('a#tos').attr('href', data.result.terms_of_service_url);
	        //$('a#why').attr('href', data.result.why_credit_card_url);
	        //LOGIN_URL= data.result.login_url;
    	}
    	
    );
}

function setCountry(country_code) {
	switch(country_code)
	{
		case 'AS':
		case 'GU':
		case 'PR':
		case 'US':
		case 'VI':
			$('div#us_address').show();
			$('div#canada_address').hide();
			$('div#other_address').hide();
			
			// load the states...
			loadUSStates(country_code);
			break;
			
		case 'CA':
			$('div#us_address').hide();
			$('div#canada_address').show();
			$('div#other_address').hide();
			loadCanadaStates()
			break;
			
		default:
			$('div#us_address').hide();
			$('div#canada_address').hide();
			$('div#other_address').show();
			break;
	}
}

function loadUSStates(country_code) {			
	$.getJSON(remoteURL()+"&cmd=regions&cc="+country_code,
		function(data){
			// clear the combobox
			$('select#us_state').html('');
			$('<option value=""></option>').appendTo('select#us_state'); // add an empty
      		$.each(data.result, function(i,item){
      			// add it...
				$("<option value='"+item.value+"'>"+item.name+"</option>").appendTo('select#us_state');
	          });
	       
	       	if(data.result.length)
	       	{
		       	$('select#us_state').show();
		       	$('label#us_state_label').show();
	       	} else {
	       		// Guam, USVI, PR, American Samoa...
		       	$('select#us_state').hide();
		       	$('label#us_state_label').hide();
	       	}
    	}
    );
}

function loadCanadaStates() {
	$.getJSON(remoteURL()+"&cmd=regions&cc=CA",
		function(data){
			// clear the combobox
			$('select#ca_state').html('');
			$('<option value=""></option>').appendTo('select#ca_state'); // add an empty
      		$.each(data.result, function(i,item){
      			// add it...
				$("<option value='"+item.value+"'>"+item.name+"</option>").appendTo('select#ca_state');
	          });
	       
	       	if(data.result.length)
	       	{
		       	$('select#ca_state').show();
		       	$('label#ca_state_label').show();
	       	} else {
		       	$('select#ca_state').hide();
		       	$('label#ca_state_label').hide();
	       	}
    	}
    );
}
		
function loadCountries() 
{
	$.getJSON(remoteURL()+"&cmd=countries",
		function(data){
			// clear the combobox
			$('select#country').html('');
      		$.each(data.result, function(i,item){
      			// add it...
				$("<option value='"+item.value+"'>"+item.name+"</option>").appendTo('select#country');
	          });

			// now get the default country (by user's ip address)
			getDefaultCountry();
    	}
    );
}
