ccValidation = null;
ppValidation = null;
var copiesField = null;
var baseCostField = null;

BULK_DISCOUNT = null; // number of copies before eligible for free (eg, 4 is "buy 3 get 1")

function getPurchaseForm() {
	return document.getElementById("mainPurchaseForm");
}

function validate() {
	var fm = getPurchaseForm();
	var currentField = null;
	var errors = new Array();
	var isValid = true;
		// we should check that the email address is a valid email address (or at least, looks like an email address)
	currentField = document.getElementsByName("email")[0];
	if (fieldIsEmpty(currentField)) {
		errors.push("Please provide an email address that can be used to contact you in case of problems.");
		isValid = false;
	} else {
		var confirmEmail = document.getElementsByName("confirmemail")[0];
		if (confirmEmail && (fieldIsEmpty(confirmEmail) || currentField.value != confirmEmail.value)) {
			errors.push("Please double-check the email address, as it doesn't match the confirmation value");
			isValid = false;
		}
	}
	if (fieldIsEmpty(document.getElementsByName("firstname")[0])) {
		errors.push("Please provide a first and last name for registration purposes");
		isValid = false;
	}
	if (fieldIsEmpty(document.getElementsByName("lastname")[0])) {
		errors.push("Please provide a first and last name for registration purposes");
		isValid = false;
	}
	if (fieldIsEmpty(document.getElementsByName("billaddr1")[0])) {
		errors.push("You must provide the billing address associated with the card");
		isValid = false;
	}
		/// conditionally check for billing info (if no coupon)
	if (!isElement(document.getElementsByName("coupon")[0])) {
		if (fieldIsEmpty(document.getElementsByName("billname")[0])) {
			errors.push("You must provide the name on the card");
			isValid = false;
		}
		if (fieldIsEmpty(document.getElementsByName("ccnum")[0])) {
			errors.push("You must provide a valid credit card");
			isValid = false;
		}
		if (fieldIsEmpty(document.getElementsByName("ccsec")[0])) {
			errors.push("You must provide the 3- or 4-digit security code for this card.");
			isValid = false;
		}
		if (!validExpDate(document.getElementsByName("ccexp")[0])) {
			errors.push("You must provide a valid expiration date (mm/yy) for the given card");
			isValid = false;
		}
		
	
	}
	
	
		/// check for the existence of #useBillingCheckbox (which implies that product ships);
		/// if it exists, it must be checked _or_ shipctry must have something selected
		var shipToBillCheck = document.getElementById("useBillingCheckbox");
		if (isElement(shipToBillCheck)) {
			var shipctryMenu = document.getElementsByName("shipctry")[0]
			if (!shipToBillCheck.checked && (shipctryMenu == -1 || fieldIsEmpty(document.getElementsByName("shipaddr1")[0]))) {
				errors.push("You must provide full shipping information, or check the box to ship to billing address");
				isValid = false;
			}
		}
	
		/// conditionally check that total copies field >= number of gifts
// 	var theGifts = document.getElementsByName("giftDeliverNow");
// 	if (theGifts && theGifts.length > 0) {
// 		var theCopiesField = document.getElementById("copiesField");
// 		if (theCopiesField && parseInt(theCopiesField.value) < theGifts.length) {
// 			errors.push("Number of gifts exceeds total copies. Please edit the number of copies you want to purchase.");
// 			isValid = false;
// 		}
// 	}
/* 	if (isValid == true) { */
/* //		alert("Form is valid, and so would continue."); */
/* 		isValid = confirm("Submit purchase information and fire registration?"); */
/*	} else */ 
	if (errors.length > 0) {
		var mesg = "There were problems with this form. Please check the following:\n";
		for (var e=0; e<errors.length; e++) {
			mesg += "\t* "+errors[e]+"\n";
		}
		alert(mesg);
	}
	
	return isValid;
}

function paypalValidate() {
	//return true;
	
	
	var fm = getPurchaseForm();
	var currentField = null;
	var errors = new Array();
	var isValid = true;
		// we should check that the email address is a valid email address (or at least, looks like an email address)
	currentField = document.getElementsByName("email")[0];

		/// check for the existence of #useBillingCheckbox (which implies that product ships);
		/// if it exists, it must be checked _or_ shipctry must have something selected
		var shipToBillCheck = document.getElementById("useBillingCheckbox");
		if (isElement(shipToBillCheck)) {
			var shipctryMenu = document.getElementsByName("shipctry")[0]
			if (!shipToBillCheck.checked && (shipctryMenu == -1 || fieldIsEmpty(document.getElementsByName("shipaddr1")[0]))) {
				errors.push("You must provide full shipping information, or check the box to ship to billing address");
				isValid = false;
			}
		}
	
		/// conditionally check that total copies field >= number of gifts
// 	var theGifts = document.getElementsByName("giftDeliverNow");
// 	if (theGifts && theGifts.length > 0) {
// 		var theCopiesField = document.getElementById("copiesField");
// 		if (theCopiesField && parseInt(theCopiesField.value) < theGifts.length) {
// 			errors.push("Number of gifts exceeds total copies. Please edit the number of copies you want to purchase.");
// 			isValid = false;
// 		}
// 	}
/* 	if (isValid == true) { */
/* //		alert("Form is valid, and so would continue."); */
/* 		isValid = confirm("Submit purchase information and fire registration?"); */
/*	} else */ 
	if (errors.length > 0) {
		var mesg = "There were problems with this form. Please check the following:\n";
		for (var e=0; e<errors.length; e++) {
			mesg += "\t* "+errors[e]+"\n";
		}
		alert(mesg);
	}
	
	return isValid;
}

function disableBillingFields() {
	changeBillingFields(true); // set 'disabled' to true
}

function enableBillingFields() {
	changeBillingFields(false); // set 'disabled' to false
}

function changeBillingFields(disab) {
	try {
		var billfld = ["billname", "billcomp", "billaddr1", "billaddr2", "billcity", "billstate", "billzip", "billctry", "ccnum", "ccsec", "ccexp"];
		for (var f=0; f<billfld.length; f++) {
			var theField = document.getElementsByName(billfld[f])[0];
			if (theField && (theField.disabled != disab)) {
				theField.disabled = disab;
			}
		}
		if (document.getElementById("shippingInfo")) { // if shipping info is visible
			var shipfld = ["shipname", "shipcomp", "shipaddr1", "shipaddr2", "shipcity", "shipstate", "shipzip", "shipctry"];
			for (var f=0; f<shipfld.length; f++) {
				var theField = document.getElementsByName(billfld[f])[0];
				if (theField && (theField.disabled != disab)) {
					theField.disabled = disab;
				}
			}
		}
	} catch (m) {
		alert("Could not properly disable billing fields: " + m.toString());
	}
}

function hideBillingFields() {
	changeBillingFieldsVisibility(false);
}

function showBillingFields() {
	changeBillingFieldsVisibility(true);
}

function changeBillingFieldsVisibility(vis) {
	try {
		var theFields = document.getElementById("billingInfo");
		if (theFields) {
			if (!vis) {
				theFields.style.display = "none";
			} else {
				theFields.style.display = "block";
			}
		}
	} catch (m) {
		alert("Could not change billing fields visibility: " + m.toString());
	}
}

	/// this doesn't quite do the right thing w/r/t cached behavior or properly including other onsubmit actions (makeBusy(), etc.)
function usePayPalPayment() {
	try {
		var theForm = getPurchaseForm();
		if (!ccValidation && theForm.onsubmit) { // if we haven't already cached (runtime-calculated) cc validation behavior, do so now
			ccValidation = theForm.onsubmit;
		}
		hideBillingFields();
		disableBillingFields();
			// & set up PP-based form validation (if any)
		if (document.getElementsByName("memid").length > 0) { // user is member
			theForm.onsubmit = function () {
				makeBusy();
				return (unmakeBusy(paypalValidate()));
			}
		} else { // need to make member onsubmit
			theForm.onsubmit = function () {
				makeBusy();
				return (unmakeBusy(paypalValidate()) && memberWithForm(theForm));
			}
		}
	} catch (m) {
//		console.log("Could not change onsubmit handler for purchase form (%o)", theForm);
	}
}

function useCreditCardPayment() {
	try {
		var theForm = getPurchaseForm();
		if (!ppValidation && theForm.onsubmit) {
			ppValidation = theForm.onsubmit;
		}
		enableBillingFields();
		showBillingFields();
			// & set up original validation on form
		if (document.getElementsByName("memid").length > 0) { // user is member
			theForm.onsubmit = function () {
				makeBusy();
				return (unmakeBusy(validate()));
			}
		} else {
			theForm.onsubmit = function() {
				makeBusy();
				return (unmakeBusy(validate()) && memberWithForm(theForm));
			}
		}
//		console.log("Changed form.onsubmit. Billing fields should be active")
	} catch (m) {
//		console.log("Could not change onsubmit handler for purchase form (%o)", theForm);
	}
}

function memberWithForm(fm) {
	//alert("memberWithForm");
		
	var success = false;
	var fields = new Array();
	fields["email"] = document.getElementsByName("email")[0];
	fields["screenname"] = document.getElementsByName("screenname")[0];
	fields["password"] =  document.getElementsByName("password")[0];
	fields["confirmpass"] = document.getElementsByName("confirmpass")[0];
	fields["firstname"] = document.getElementsByName("firstname")[0];
	fields["lastname"] = document.getElementsByName("lastname")[0];
	var invite = document.getElementsByName("invite")[0];
	if (invite) {
		fields["invite"] = invite;
	}
	
	//alert("email "+ document.getElementsByName("email")[0])
	
	resp = requestCreateMember(fields);
	
	if(window.console) {
	//	window.console.log(resp);
		}
		
	// process resp to determine whether to change success or not
	if (resp) {
		var errs = resp.getElementsByTagName("err");
		
		if(window.console) {
		//	window.console.log(errs);
			}
			
			
		if (errs.length > 0) {
			var report = "";
			for (var e=0; e<errs.length; e++) {
				var mesg = errs[e].getElementsByTagName("mesg");
				for (var m=0; m<mesg.length; m++) {
					report += mesg[m].firstChild.nodeValue + "\n";
				}
			}
			//tell the user what the error is!
			unmakeBusy(false);
			alert(report);
			
		} else {
			success = true; // no errors, so everything should have been fine
				/// add memid field (hidden) to form for post-processing
			var theNode = resp.getElementsByTagName("success")[0];
			if (theNode && theNode.hasAttribute("memid")) {
				var theMemField = document.createElement("input");
				theMemField.setAttribute("type", "hidden");
				theMemField.setAttribute("name", "memid");
				theMemField.setAttribute("value", theNode.getAttribute("memid"));
				fm.appendChild(theMemField);
					/// if we need to distingish between newly-created (inline) members,
					/// we could add another field here (say 'newmem') and check for 
					/// presence when making invitation settings below
			}
				/// add invisible iframe to document to support background implicit login
			var theLoginFrame = document.createElement("iframe");
			theLoginFrame.setAttribute("src", "http://www.mupromo.com/inline-login.php");
			theLoginFrame.setAttribute("height", "0");
			theLoginFrame.setAttribute("width", "0");
			document.body.appendChild(theLoginFrame);
		}
	} else {
		alert("There was a problem creating your account. Please try again in a moment. (77)");
	}
	return success;
}

function requestCreateMember(fields) {
		
	var args = new Array();
	for (fld in fields) {
		if (fields[fld]) {
			args.push(fld+"="+fields[fld].value);
		}
	}
	//alert("requestCreateMembers " +args.join('&'));
	if(window.console) {
		//	window.console.log("requestCreateMembers " +args.join('&'));
		}
	if (!requestChange("make-member2.php", args.join('&'), null, false)) { // process _synchronously_
		alert("There was a problem creating your new MacUpdate member account; please try again in a moment. (88)");
	}
	
	if(window.console) {
		//	window.console.log(req.responseXML);
		}
	//alert("response XML "+req.responseXML);
	// by here, req should contain response (may want else condition of requestChange() test)
	return req.responseXML;
}

function checkNewMember() {
	var theMainEmail = document.getElementsByName("email")[0];
	var theConfirmEmail = document.getElementsByName("confirmemail")[0];
	if (!fieldIsEmpty(theMainEmail) && !fieldIsEmpty(theConfirmEmail) && theMainEmail.value == theConfirmEmail.value) {
		console.log("fire existing-member check");
		requestCheckNewMember(theMainEmail.value);
	}
}

function requestCheckNewMember(addr) {
	// console.log("Would check for existing member %o", addr);
	requestChange("check-member.php", "email="+addr, function () { genericRespond(respondCheckNewMember); });
}

function respondCheckNewMember() {
	if (req.responseXML) { 
		var theSuccess = req.responseXML.getElementsByTagName("success")[0];
		if (theSuccess) {
			console.log("account already exists: " + theSuccess.getAttribute("memid"));
			memberLoginBox(theSuccess.getAttribute("memid"), theSuccess.getAttribute("user"));
		} else {
			console.log("no pre-existing account");
		}
	}
}

function memberLoginBox(memid, user) {
	var theLogin = document.createElement("div");
	theLogin.id = "existingMemberLogin";
	var thePass = document.createElement("input");
	thePass.setAttribute("type", "password");
	thePass.setAttribute("name", "pass");
	var theExplanation = document.createElement("div");
	theExplanation.className = "passDialogExplain";
	theExplanation.appendChild(document.createTextNode("Please enter the password for this account" + ((user) ? " ("+user+")" : "") + "."));
	theLogin.appendChild(theExplanation);
	theLogin.appendChild(thePass);
	var theLoginButton = document.createElement("button");
	theLoginButton.appendChild(document.createTextNode("login"));
	theLoginButton.onclick = function () { existingMemberLogin(user, thePass); }; // will these closures behvave correctly?
	var theCancelButton = document.createElement("button");
	theCancelButton.appendChild(document.createTextNode("cancel"));
	theCancelButton.onclick = function () { removeMemberLoginBox(); };
	theLogin.appendChild(theLoginButton);
	theLogin.appendChild(theCancelButton);
	document.body.appendChild(theLogin);
}

function existingMemberLogin(uname, passField) {
	if (uname && passField && !fieldIsEmpty(passField)) {
		requestExistingMemberLogin(uname, passField.value);
	}
}

function requestExistingMemberLogin(uname, pass) {
	requestChange("https://sandbox.macupdate.com/promo/check-login.php", "email="+uname+"&pass="+pass+"&full=1", respondExistingMemberLogin);
}

function respondExistingMemberLogin() {
	genericRespond(handleExistingMemberLogin);
}

function handleExistingMemberLogin() {
	if (req.responseXML.getElementsByTagName("success").length > 0) {
		console.log("respond to memberLoginBox() correctly");
		removeMemberLoginBox();
		implicitLogin();
//////////////// we don't need to do this when we reload the page
// 		try {
// 			var theMember = new Member(req.responseXML.getElementsByTagName("member")[0]);
// 			var theAction = document.getElementById("debugLogoutAction");
// 			if (theAction) {
// 				var theNewAction = theAction.cloneNode(false);
// 				theNewAction.appendChild(document.createTextNode(theMember.user));
// 				var theParent = theAction.parentNode;
// 				theParent.replaceChild(theNewAction, theAction);
// 				theAction.id = "debugLogoutAction";
// 			}
// 			window.location.href = window.location.href; // window.location.reload();
// 		} catch (m) {
// 			console.log("Could not initialize member object: %o", req.responseXML.getElementsByTagName("member")[0]);
// 			console.log(m.toString());
// 		}
//////////////////
	} else {
		console.log("there was a problem responding to login box");
	}
}

function removeMemberLoginBox() {
	document.body.removeChild(document.getElementById("existingMemberLogin"));
}

function implicitLogin() {
	var theLoginFrame = document.createElement("iframe");
	theLoginFrame.setAttribute("src", "http://sandbox.macupdate.com/promo/inline-login.php"); // "?dest="+window.location.href, though we really want this to go someplace blank
	theLoginFrame.setAttribute("height", "0");
	theLoginFrame.setAttribute("width", "0");

// 	var theLoginFrame = document.createElement("object");
// 	theLoginFrame.setAttribute("data", "http://sandbox.macupdate.com/promo/inline-login.php");
// 	theLoginFrame.appendChild(document.createTextNode("Cannot process login"));
	document.body.appendChild(theLoginFrame);
}



	// this does more-or-less exactly what makeCursor() does in ajaxbasic.js
function createCursor() {
	var curs = document.createElement("img");
	curs.setAttribute("src", "https://www.macupdate.com/watch/bigSpinner.gif");
	curs.setAttribute("id", "busyCursor");
	curs.setAttribute("alt", "processing...");
	return curs;
}

function findCursor() {
	return document.getElementById("busyCursor");
}

function makeBusy() {
	/// change UI (spinner, disable button, etc.)
	var theButton = document.getElementById("regButton");//  but; 
//	var origButtonLabel = theButton.value;
	if (theButton) {
		theButton.value = "Processing...";
		theButton.disabled = true;
	}
//	makeCursor();
	var curs = findCursor(); // document.createElement("img");
// 	curs.setAttribute("src", "http://www.macupdate.com/watch/bigSpinner.gif");
// 	curs.setAttribute("id", "busyCursor");
// 	curs.setAttribute("alt", "processing...");
	var couldPlaceCursor = false;
//	var cursContain; // check scoping rules for try-blocks (maybe don't need this)
	try {
		if (isElement(curs)) {
			curs.style.display = "block";
		} else {
			curs = createCursor();
			document.body.appendChild(curs);
		}
// 		cursContain = theButton.parentNode;
// 		cursContain.appendChild(curs);
		couldPlaceCursor = true;
	} catch (e) {
		alert("Problem processing...\n"+e.toString());
	}
	return true; // this is so makeBusy() can be part of the return conditional...
}

function unmakeBusy(succ) {
	if (!succ) { // if false, unspin spinner, and reennable button
		var curs = findCursor();
		try {
			curs.style.display = "none";
		} catch (e) {}
//		removeCursor(); // this assumes cursor is #busyCursor
		isProcessing = false; // have to manually take care of this here
		var theButton = document.getElementById("regButton");
		if (theButton && theButton.disabled) {
			theButton.disabled = false;
			theButton.value = "Purchase and Register";
		}
	}
	return succ;
}

function fieldIsEmpty(fld) {
	return (!fld || fld.value == "") // NB: this should really be checked against regex for empty strings (eg, so "   " doesn't pass)
}

function validExpDate(fld) {
	var dateExp = /\d{1,2}\/\d{2,4}/;
	return (!fieldIsEmpty(fld) && dateExp.test(fld.value));
}

/// need definitions for shipping calculation ajax...

function determineShippingCost(pid, useBill) {
	// pid contains product id (obviously this doesn't work for multiway promos)
	//makeBusy();
	//var shipArgs = buildShippingArgs(useBill);
	
	copyBilltoShip();
	
	
	//requestChange("upsbridge.php", "prod="+pid+"&ship="+shipArgs, respondShippingCost); // not updateShippingCost() as direct handler...
}

function copyBilltoShip()
{
    document.getElementsByName("shipname")[0].value = document.getElementsByName("billname")[0].value;
	document.getElementsByName("shipcomp")[0].value = document.getElementsByName("billcomp")[0].value;
	document.getElementsByName("shipaddr1")[0].value = document.getElementsByName("billaddr1")[0].value;
	document.getElementsByName("shipaddr2")[0].value = document.getElementsByName("billaddr2")[0].value;
	document.getElementsByName("shipcity")[0].value = document.getElementsByName("billcity")[0].value;
    document.getElementsByName("shipstate")[0].value = document.getElementsByName("billstate")[0].value;
	document.getElementsByName("shipzip")[0].value = document.getElementsByName("billzip")[0].value; 
	document.getElementsByName("shipctry")[0].value =	document.getElementsByName("billctry")[0].value;
    
}

function buildShippingArgs(useBill) {
	var tags = (useBill) ? infoFromBilling() : infoFromShipping(); // new Array();
	var shipArgs = new Array();
	if (!useBill) {
		try {
			var checkBill = document.getElementById("useBillingCheckbox");
			if (isElement(checkBill) && checkBill.checked) {
				checkBill.checked = false;
			}
		} catch (e) {}
	}
	for (var k in tags) {
		var theTag = tags[k];
		if (isElement(theTag)) {
//			theTag.normalize();
			var tagValue = theTag.value.replace(/^\s*|\s*$/, ""); // if we have to use this in other places, it might be better to define a trim() function
			if (tagValue != "") {
				shipArgs.push(k+":"+tagValue);
			}
		}
	}
	return shipArgs.join("|");
}

function infoFromShipping() {
	var tags = new Array();
	tags['name'] = 	document.getElementsByName("shipname")[0];
	tags['comp'] = 	document.getElementsByName("shipcomp")[0];
	tags['addr1'] = 	document.getElementsByName("shipaddr1")[0];
	tags['addr2'] = 	document.getElementsByName("shipaddr2")[0];
	tags['city'] = 	document.getElementsByName("shipcity")[0];
	tags['state'] = 	document.getElementsByName("shipstate")[0];
	tags['zip'] =		document.getElementsByName("shipzip")[0];
	tags['ctry'] =	document.getElementsByName("shipctry")[0];
	return tags;
}

function infoFromBilling() {
	var tags = new Array();
	tags['name'] = 	document.getElementsByName("billname")[0];
	tags['comp'] = 	document.getElementsByName("billcomp")[0];
	tags['addr1'] = 	document.getElementsByName("billaddr1")[0];
	tags['addr2'] = 	document.getElementsByName("billaddr2")[0];
	tags['city'] = 	document.getElementsByName("billcity")[0];
	tags['state'] = 	document.getElementsByName("billstate")[0];
	tags['zip'] =		document.getElementsByName("billzip")[0];
	tags['ctry'] =	document.getElementsByName("billctry")[0];
	return tags;
}

function determineShippingFromBilling(pid, ctl) {
	try {
		if (ctl.checked) {
			determineShippingCost(pid, true);
		} // do nothing if _unchecking_ "use billing"
	} catch (e) {
		alert("Problem: "+e.toString());
	}
}

function respondShippingCost() {
//	genericRespond(updateShippingCost);
	respondUPS(updateShippingCost);
}

function updateShippingCost() {
//	var shipCost = shippingCostFromResult(req.responseXML)
	var shipCost = shippingCostFromResultUPS(req.responseXML)
	var shipInput = document.createElement("input");
	shipInput.setAttribute("type", "hidden");
	shipInput.setAttribute("name", "shipCost");
	shipInput.setAttribute("value", shipCost);
	var theForm = document.getElementById("purchaseForm");
	theForm.appendChild(shipInput);
	var theVisibleField = document.getElementById("visibleShippingCharges");
	if (isElement(theVisibleField)) {
		theVisibleField.normalize();
		if (theVisibleField.hasChildNodes()) {
			for (var curr = theVisibleField.firstChild; curr != null; curr = curr.nextSibling) {
				theVisibleField.removeChild(curr);
			}
		}
		theVisibleField.appendChild(document.createTextNode("$"+shipCost.toFixed(2)));
	}
//	alert("Would update shipping costs and underlying price: " + shipCost);
	unmakeBusy(false); // disable spinner
}

function shippingCostFromResult(doc) {
//	return 10 * Math.random();
	var shipTotal = 0;
	try {
		var shipElements = doc.getElementsByTagName("ship");
		for (var i=0; i<shipElements.length; i++) {
			shipElements[i].normalize();
			shipTotal += Number(shipElements[i].firstChild.nodeValue);
		}
	} catch (e) {
		alert("Problem processing shipping results: " + e.toString());
	}
	return shipTotal;
}

//// coupon handling

	// check for valid coupon; if yes, change total to zero (& update visible),
	// otherwise, inform user that coupon is invalid.
function checkCoupon(promo) {
	makeBusy();
	var theCouponField = document.getElementById("couponField");
	if (theCouponField && theCouponField.value != "") {
		var args = "promo="+promo+"&code="+theCouponField.value;
		requestChange("couponCheck.php", args, respondCoupon);
	} else {
		alert("Cannot check coupon: can't find entered coupon code");
	}
}

function respondCoupon() {
	genericRespond(updateCoupon);
	unmakeBusy();
}

function updateCoupon() {
	// process status; if coupon passed check, change total amount input & displayed value,
	// otherwise, inform user (or, was handled by genericRespond and error conditions)
//	alert("called updateCoupon() with response, which must have been true to get this far");
	disableBillingFields();
	// update displayed purchase value
	var theDisplayedAmount = document.getElementById("amountField");
	if (theDisplayedAmount) {
		theDisplayedAmount.replaceChild(document.createTextNode("$0"), theDisplayedAmount.firstChild);
	}
	var theBillableAmount = document.getElementsByName("amount")[0];
	if (isElement(theBillableAmount)) {
		theBillableAmount.value = 0;
	}
	
}

//// refer-a-friend invitation handling
function sendInvite() {
//	console.log("Dispatching request");
	requestInvite();
}

function requestInvite() {
	var theForm = document.getElementById("inviteForm");
	if (theForm) {
//		console.assert((theForm.elements && theForm.elements.length > 0), "No children; incorrect form reference?");
		var args = new Array();
		for (var i=0; i<theForm.elements.length; i++) {
			var theElement = theForm.elements[i];
			args.push(theElement.name+"="+theElement.value);
		}
		requestChange("invite.php", args.join("&"), respondInvite);
	} else {
//		console.error("Problem getting form %o", theForm);
	}
}

function respondInvite() {
	genericRespond(updateInvite);
}

function updateInvite() {
	/// modify invitation form (update number of invites left, deactivate controls if 0)
	try {
		var theCounter = document.getElementById("inviteRemain");
//		console.assert(theCounter && theCounter.hasChildNodes(), "Could not get counter value");
			// decrement remaining invitations
		var newCount = parseInt(theCounter.value) - 1;
			// replace old remaining value with current value
		theCounter.value = newCount;
//		theCounter.replaceChild(document.createTextNode(newCount), theCounter.firstChild);
		var theForm = document.getElementById("inviteForm");
//			console.assert(theForm.elements.length > 0, "No elements to disable");

			/// if airplane icon is not yet visible, show
		var thePlane = document.getElementById("invAirplane"); // de plane, boss! de plane
		if (!thePlane) {
			thePlane = document.createElement("img");
			thePlane.setAttribute("src", "newlayout/images/inv_airplane.png");
			thePlane.id = "invAirplane";
			theContainer = document.getElementById("refer");
			theContainer.appendChild(thePlane);
		}
			/// change badge
		var theBadge = document.getElementById("invCount");
		if (theBadge) {
			theBadge.setAttribute("src", "newlayout/images/inv_count"+newCount+".png");
		}

			/// reset text fields
		for (var e=0; e<theForm.elements.length; e++) {
			if (!theForm.elements[e].hasAttribute("type") || theForm.elements[e].getAttribute("type") == "text") {
				theForm.elements[e].value = "";
			}
			if (newCount == 0) {
				theForm.elements[e].disabled = true;
			}
		}
			/// check returned record for winner
		if (userDidWin(req.responseXML)) {
			// if won, display choice dialog
			userPickRedeemOption(req.responseXML);
		}
	} catch (m) {
//		console.error("Caught exception updating invite form: " + m.toString());
		alert("Caught exception updating invite form: " + m.toString());
	}
}

function userDidWin(xml) {
	try {
		var theInvite = xml.getElementsByTagName("invite")[0];
		return (theInvite && theInvite.hasAttribute("win") && theInvite.getAttribute("win") == "yes");
	} catch (m) {
		alert("Trouble determining giveaway-calculation status: " + m.toString());
	}
}

	//// this explicitly depends on createDialogInviteCoupon, which is in promo.js
function userPickRedeemOption(xml) {
//	alert("Redemption choices menu goes here.");
	var coup = xml.getElementsByTagName("coupon");
	var theCoupon = coup[0]; // assume there's only one
	var theCode = theCoupon.firstChild.nodeValue;
	placeDialog(createDialogInviteCoupon(theCode, theCoupon.getAttribute("promo")), getOverlay());
}

function checkDiscount() {}

function DISABLED_checkDiscount() {
	removeAppleDiscountBadge();
	removeTestDiscountBadge(); // better way to handle this than to stack the calls?
	if (meetsAppleCriteria()) {
		updateAppleDiscount();
		return true;
	} else if (meetsUNTCriteria()) {
		updateUNTDiscount();
		return true;
	} else {
//		checkExistingMemberCriteria(); // dispatch check against existing accounts
		revertPrice();
		return false;
	}
}

function userEmail() {
	return document.getElementsByName("email")[0];
}

function meetsSiteCriteria(pat) {
	var theEmail = userEmail();
	return (		theEmail 
				&&	theEmail.value 
				&&	theEmail.value != ""
				&&	theEmail.value.match(pat)
	);
}

function meetsAppleCriteria() {
	return meetsSiteCriteria(/@((\w+\.)?apple|filemaker)\.com/);
}

function meetsTestCriteria() {
	return false; // meetsSiteCriteria(/@test.com/);
}

function meetsUNTCriteria() {
	return meetsSiteCriteria(/@unt.edu/);
}


function checkExistingMemberCriteria() {
	var theEmail = userEmail();
	if (theEmail && theEmail.value) {
		requestCheckMember({email: theEmail});
	} else {
// 		console.log("Could not get email value to check");
	}
}

function requestCheckMember(fields) {
	var args = new Array();
	for (fld in fields) {
		if (fields[fld]) {
			args.push(fld+"="+fields[fld].value);
		}
	}
	requestChange("check-member.php", args.join('&'), respondCheckMember);
}

function respondCheckMember() {
	genericRespond(updateMemberDiscount);
}

function updateAppleDiscount() {
// 	var theCost = document.getElementsByName("amount")[0];
// 	if (theCost && theCost.value) {
// 			// this constant discount shouldn't be hard-coded
// // 		console.log("updating with apple discount");
// 		var newCost = parseFloat(theCost.value)*.9;
// 		updateTotal(newCost, true, true);
// 		theCost.value = roundFloat(newCost, 2);
	if (updateCost(.9)) {
		placeAppleDiscountBadge();
	}
}

function updateTestDiscount() {
	if (updateCost(.9)) {
		placeTestDiscountBadge();
	}
}

function updateUNTDiscount() {
	if (updateCost(.9)) {
		placeUNTDiscountBadge();
	}
}


function updateCost(discount) {
	var theCost = document.getElementsByName("amount")[0];
	var theOrig = document.getElementsByName("undiscounted")[0];
	if (theCost && theCost.value && theOrig && theOrig.value) {
		var newCost = parseFloat(theOrig.value)*discount;
		updateTotal(newCost, true, true);
		theCost.value = roundFloat(newCost, 2);
		return true;
	} else {
		return false;
	}
}	

function updateMemberDiscount() {
	if (req.responseXML.getElementsByTagName("success")[0]) {
// 		console.log("update w/member discount");
		var theCost = document.getElementsByName("amount")[0];
		if (theCost && theCost.value) {
				// this constant discount shouldn't be hard-coded
			updateTotal(parseFloat(theCost.value)*.9, true, true);
		}
	} else {
// 		console.log("no matching member");
		/// switch back to orig price if not setup that way already
		var theOrigValue = document.getElementById("origprice");
		if (theOrigValue && theOrigValue.firstChild) {
			updateTotal(parseFloat(theOrigValue.firstChild.nodeValue), true);
		}
	}
}

function revertPrice() {
	var theUndiscountedField = document.getElementsByName("undiscounted")[0];
	if (theUndiscountedField && theUndiscountedField.value) {
		var newPrice = parseFloat(theUndiscountedField.value);
		updateTotal(newPrice, true);
		var theCost = document.getElementsByName("amount")[0];
		if (theCost && theCost.value) {
			theCost.value = roundFloat(newPrice, 2);
		}
	}
}
		
		

function placeDiscountBadge(id, text) {
	var theEmail = userEmail();
	if (!document.getElementById(id) && theEmail && theEmail.nodeType == Node.ELEMENT_NODE) {
		var theBadge = document.createElement("span");
		theBadge.appendChild(document.createTextNode(text));
		theBadge.id = id;
		theBadge.className = "discountBadge";
		theEmail.parentNode.appendChild(theBadge);
	}
}

function removeDiscountBadge(id) {
	var theBadge = document.getElementById(id);
	if (theBadge) {
		var theParent = theBadge.parentNode;
		theParent.removeChild(theBadge);
	}
}

function placeAppleDiscountBadge() {
	placeDiscountBadge("appleEmployee", "Apple Employee Discount");
}

function placeTestDiscountBadge() {
	placeDiscountBadge("testDiscount", "Test Discount");
}

function placeUNTDiscountBadge() {
	placeDiscountBadge("untDiscount", "UNT Student Discount");
}

function removeAppleDiscountBadge() {
	removeDiscountBadge("appleEmployee");
}

function removeTestDiscountBadge() {
	removeDiscountBadge("testDiscount");
}

function removeTestDiscountBadge() {
	removeDiscountBadge("untDiscount");
}

function forwardToReceipt() {
	/// find id for receipt
//	console.log("in forwardToReceipt()");
	var jumpForm = document.getElementById("jump");
	if (jumpForm) {
		var ridNode = document.getElementById("receiptId");
		if (ridNode && ridNode.value) {
			var mul=null;
			var mulNode = document.getElementById("receiptCopies");
			if (mulNode) {
				mul = parseInt(mulNode.value) > 1;
			}
			forwardToReceiptWithId(ridNode.value, mul);
		}
	}
}

function forwardToReceiptWithId(rid, mul) {
//	console.log("Forwarding to %o", rid);
	var mulArg = (mul) ? "&mul=1" : "";
	window.location.href="receipt.php?dir=1"+mulArg+"&r="+rid;
}

function updateTotalFromCopies(ctl, hascoup, cost) {
	var copies = parseInt(ctl.value);
	if (giftsCount && copies < giftsCount) {
		alert("You have specified more gifts than the total number of copies. To reduce the total number of copies, you'll need to delete some of these gifts.");
		ctl.value = giftsCount;
		copies = giftsCount;
	}
// 	if (hascoup) {
// 		if (copies > 1) {
// 			updateTotal(cost*(copies-1), true);
// 		} else {
// 			updateTotal(0, true);
// 		}
// 	} else {
// 		updateTotal(cost*copies, true);
// 	}
	updateTotal(cost * billableCopies(copies, hascoup), true);
}

function updateTotalFromMember(ctl, cost) {
	if (ctl.checked) {
		updateTotal(cost, false);
	} else {
		updateTotal(-1*cost, false);
	}
}

function updateTotal(amt, replace, strike) {
	var showorig = strike || false; // by default, _replace_ price value
	var amountField = document.getElementById("amountField");
	var currentAmount = parseFloat(amountField.firstChild.nodeValue.replace(/\$([\d,\.]+)/, "$1"));
	var newAmount = (replace) ? amt : currentAmount+amt;
	if (currentAmount != newAmount) {
		while (amountField.hasChildNodes()) {
			amountField.removeChild(amountField.childNodes[0]);
		}
		amountField.appendChild(document.createTextNode("$"+ensureDigits(roundFloat(newAmount, 2), 2)));
		if (showorig) {
			var strikeField = document.createElement("span");
			strikeField.id = "origprice";
			strikeField.appendChild(document.createTextNode(ensureDigits(roundFloat(currentAmount, 2), 2)));
			amountField.appendChild(strikeField); // child of amountField because of construction
		}
	}
}

function selfCopies() {
	if (!copiesField) {
		copiesField = document.getElementById("copiesField");
	}
	return (copiesField) ? parseInt(copiesField.value) : 0;
}

function basePromoCost() {
	if (!baseCostField) {
		baseCostField = document.getElementsByName("amount")[0];
	}
	return (baseCostField) ? parseFloat(baseCostField.value) : 0;
}

function billableCopies(copies, hascoup) {
	var eligibleCopies = (hascoup) ? Math.max(copies-1, 0) : copies;
	var freeCopies = 0;
	if (BULK_DISCOUNT) {
		freeCopies = Math.floor(eligibleCopies / BULK_DISCOUNT);
	}
	return eligibleCopies - freeCopies;
}


function roundFloat(n, d) {
	var rounded = Math.round(n*Math.pow(10,d))/Math.pow(10,d);
	return rounded;
}

function ensureDigits(n, d, force) {
	var zeroes = force || false;
	n = n.toString();
	var split = n.indexOf(".");
	if (split != -1) {
		var decpart = n.substr(split+1);
		return (n.substr(0, split+1) + ((decpart.length < d) ? padString(decpart, d, "0") : decpart));
	} else { // no decimal point
		if (zeroes) {
			return n + ".00";
		} else {
			return n;
		}
	}
}

function padString(str, len, ch) {
	for (var i = 0; i < (len - str.length); i++) {
		str += ch;
	}
	return str;
}

function updatePriceFields20() {
	var cost = basePromoCost();
	var copies = selfCopies() + giftCopies();
	if (copies < 20)
	{
		alert("You must purchase at least 20 copies to get the discounted price")
		copies = 20;
	}
	var discounted = copies - billableCopies(copies, false);
	var addons = totalAddonCosts();
	var discountedTotal = cost * discounted;
	var promoTotal = cost * copies;
	setSubtotalValue(promoTotal + addons);
//	if (discounted > 0) {
		setBulkDiscountValue(discountedTotal);
//	}
	setTotalValue(promoTotal - discountedTotal + addons);
}


function updatePriceFields() {
	var cost = basePromoCost();
	
	var copies = selfCopies() + giftCopies();
	
	setNoteBulkProfit(0);
	if (copies >= 20)
	{
		cost = 44.99;
		setNoteBulkProfit(1);
	}
		setPriceEach(cost);
	var discounted = copies - billableCopies(copies, false);
	var addons = totalAddonCosts();
	var discountedTotal = cost * discounted;
	var promoTotal = cost * copies;
	setSubtotalValue(promoTotal + addons);
//	if (discounted > 0) {
		setBulkDiscountValue(discountedTotal);
//	}
	setTotalValue(promoTotal - discountedTotal + addons);
}

function setSubtotalValue(subtot) {
	var theSubtotal = document.getElementById("subtotalAmount");
	if (theSubtotal) {
		replaceText(theSubtotal, ensureDigits(roundFloat(subtot, 2), 2));
	}
}

function setPriceEach(subtot) {
	var thepriceeach = document.getElementById("bpriceeach");
		if (thepriceeach) {
	replaceText(thepriceeach, ensureDigits(roundFloat(subtot, 2), 2));
}
}



function setNoteBulkProfit(toggle) {
	var bolkprofit = document.getElementById("bolkprofit");
		if (bolkprofit) {
			if (toggle)
			{
				replaceText(bolkprofit, 'Note: Reselling bundles for profit is prohibited');
			} else {
				replaceText(bolkprofit, '');
			}
		}
}


function setBulkDiscountValue(disc) {
	var theBulkDiscount = document.getElementById("bulkDiscount");
	if (theBulkDiscount) {
		replaceText(theBulkDiscount, ensureDigits(roundFloat(disc, 2), 2));
	}
}

function setTotalValue(tot) {
	var theTotal = document.getElementById("amountField");
	if (theTotal) {
		replaceText(theTotal, ensureDigits(roundFloat(tot, 2), 2));
	}
}

function replaceText(nd, text) {
	while (nd.hasChildNodes()) {
		nd.removeChild(nd.childNodes[0]);
	}
	nd.appendChild(document.createTextNode(text));
}
