var typeSelectionChanging = false;

// store the selector options implemented by the page in HTML
var g_defaultEquipmentTypeOptions = null;
var g_defaultEquipmentModelOptions = null;
var g_defaultCommissionOptions = null;

// Back up the current options in the selector object
function cctl_BackupOptions(selector, backup) {
	if (backup == null) {
		debugWindow.writeln("cctl_BackupOptions: backing up selector " + selector.name + " with " + selector.options.length + " options.")
		backup = new Array(selector.length);
		for (var i = 0; i < selector.length; i++) {
			backup[i] = new Option(selector.options[i].text, selector.options[i].value, selector.options[i].defaultSelected, selector.options[i].selected);
		}
	}
	return backup;
}

// Restores the default (implemented by the page when it first loaded) options of the selector object.
function cctl_RestoreOptions(selector, backup) {
	if (backup == null) {
		debugWindow.writeln("backup is empty");
		return;
	}
	if (selector == null || selector.selectedIndex == null) {
		alert("'selector' is not an element or is not a selector");
		return;
	}
	selector.length = backup.length;
	for (var i = 0; i < selector.length; i++) 
		selector.options[i] = backup[i];
}

// clears all options of a select object and restores the default options implemented by the HTML page.
function cctl_ClearSelector(name, backup) {
	if (name == null || name == "") {
		alert(name + " is not supplied");
		return;
	}
	var selector = document.getElementById(name);
	
	// clear selector
	if (selector == null || selector.nodeName != "SELECT") {
		alert(name + " is not a selector");
		return;
	}
	
	// Add the default options to the selector
	cctl_RestoreOptions(selector, backup);
}

// is called when the add button is pressed
function cctl_AddItem(doNotCalculate) {

	// lease type must be selected if it exists on the page
	var lt = document.getElementById("leaseProduct");
	if (lt != null) {
		var ltv = lt.options[lt.selectedIndex].text;
		if (ltv == null || ltv.indexOf("----") != -1) {
			alert(g_selectValidLeaseMsg);
			return;
		}
		else {
			//first keep selected value for reference in print page
			var lpv = document.getElementById("leaseProductValue");
			if (lpv != null) {
				lpv.value = ltv;
			}
		}
	}
	
	// type must be selected
	var et = document.getElementById("equipmentType");
	if (et == null) {
		alert("Required element 'equipmentType' missing!");
		return;
	}
	
	var etv = et.options[et.selectedIndex].text;
	if (etv == null || etv.indexOf("----") != -1) {
		alert(g_selectValidTypeMsg);
		return;
	}
	
	var modelNr;
	// Model must be selected for promotions
	if (promotion.isPromotion(et.options[et.selectedIndex].value)) {
		var em = sessionController.getValue("equipmentModel").val;
		
		if (em == null || em.indexOf("----") != -1) {
			alert(g_selectValidModelMsg);
			return;
		}
		modelNr = em;
	}
	else {
		var em = document.getElementById("equipmentModel");
		if (em == null) {
			alert("Required element 'equipmentModel' missing!");
			return;
		}
		
		if (em.value == "") {
			alert(g_selectValidModelMsg);
			return;
		}
		modelNr = em.value;
	}
	// equipment description cannot be empty
	var ed = sessionController.getValue("equipmentDescription").val;
	if (ed == null || ed == "") {
		alert(g_validDescriptionMsg);
		return;
	}
	// quantity must be equal to or greater than 1
	var eq = parseInt(sessionController.getValue("equipmentQuantity").val);
	if (isNaN(eq) || eq <= 0) {
		alert(g_minQuantityMsg);
		return;
	}
	// Sales prices must be a float
	var es = nf_parseFloat(sessionController.getValue("equipmentAmount").val);
	if (isNaN(es)) {
		alert(g_validSalespriceMsg);
		return;
	}
	
	// Number of ports must be > 0
	if (isPricePerPort()) {
		var np = parseInt(sessionController.getValue("numberOfPorts").val);
		if (isNaN(np) || np <= 0) {
			alert(g_minQuantityMsg);
			return;
		}
	}
	else 
		if (isPricePerUser()) {
			var np = parseInt(sessionController.getValue("numberOfPorts").val);
			if (isNaN(np) || np <= 0) {
				alert(g_minQuantityMsg);
				return;
			}
		}
		else {
			np = 1;
		}
	
	// add the items to the equipmentlist
	it_AddItem("equipmentList", etv, modelNr, ed, eq, nf_formatNumeric(es), nf_formatNumeric(eq * es));
	var npitm = document.getElementById("numberOfPorts");
	if (npitm != null) sessionController.setValue("numberOfPorts", null, true);
	
	
	// fixate the lease product selector
	if (lt != null) sessionController.setValue("leaseProduct", null, true);
	
	if (doNotCalculate != true) cctl_Calculate();
	cctl_Clear();
	
	try {
		onLocalAddItem(doNotCalculate);
	} 
	catch (E) {
	}
}

// is called when the remove button is pressed of an item line in the equipment table
function cctl_onRemoveItem(doNotCalculate) {
	// Recalculate rates
	if (doNotCalculate != true) cctl_Calculate();
	
	// Enable the lease product selector when the last item is removed from the equipment table
	if (itemTable("equipmentList").getNrOfItems() == 0) {
		var lt = document.getElementById("leaseProduct");
		if (lt != null) {
			lt.selectedIndex = 0;
			sessionController.setValue("leaseProduct", "", false);
		}
	}
	
	try {
		onLocalRemoveItem(doNotCalculate);
	} 
	catch (E) {
	}
}

// Clears Type, promotion description and conditions, model and description nd quantity and unit price
function cctl_Clear(doNotFillModels) {
	var et = document.getElementById("equipmentType");
	if (et == null) {
		alert("Required element 'equipmentType' missing!");
		return;
	}
	var ed = document.getElementById("equipmentDescription");
	if (ed == null) {
		alert("Required element 'equipmentDescription' missing!");
		return;
	}
	var em = document.getElementById("equipmentModel");
	if (em == null) {
		alert("Required element 'equipmentModel' missing!");
		return;
	}
	var pc = document.getElementById("promoConditions");
	if (pc == null) {
		alert("Required element 'promoConditions' missing!");
		return;
	}
	var pd = document.getElementById("promoDescription");
	if (pd == null) {
		alert("Required element 'promoDescription' missing!");
		return;
	}
	var eq = document.getElementById("equipmentQuantity");
	if (eq == null) {
		alert("Required element 'equipmentQuantity' missing!");
		return;
	}
	var ea = document.getElementById("equipmentAmount");
	if (ea == null) {
		alert("Required element 'equipmentAmount' missing!");
		return;
	}
	var np = document.getElementById("numberOfPorts");
	if (np == null) {
		alert("Required element 'numberOfPorts' missing!");
		return;
	}
	
	et.selectedIndex = 0;
	em.selectedIndex = 0;
	em.value = "";
	pd.innerHTML = "";
	pc.innerHTML = "";
	ed.value = "";
	eq.value = "";
	ea.value = "";
	
	
	em.disabled = true;
	eq.disabled = true;
	ed.disabled = true;
	ea.disabled = true;
	
	
	if (doNotFillModels == false) {
		cctl_FillModels("");
	}
}

function cctl_ClearAll() {
	cctl_Clear();
	it_resetTable("equipmentList")
	
	// Enable the lease product selector if present
	var lt = document.getElementById("leaseProduct");
	if (lt != null) {
		lt.selectedIndex = 0;
		sessionController.setValue("leaseProduct", "", false);
	}
	
	sessionController.setValue("quoteto", "");
	sessionController.setValue("quotefrom", "");
	sessionController.setValue("phoneNr", "");
	sessionController.setValue("reseller", "");
	sessionController.setValue("comment", "");
	sessionController.setValue("period", "3 years");
	sessionController.setValue("frequency", "monthly");
	sessionController.setValue("numberOfPorts", "");
	if (document.getElementById("leaseProductValue") != null) sessionController.setValue("leaseProductValue", "");
}

// gets value from selected item of a select box
function cctl_setSelectedValue(name, val) {
	if (name == null || name == "") {
		alert(name + " is not supplied");
		return;
	}
	var o = document.getElementById(name);
	
	if (o == null || o.nodeName != "SELECT") {
		alert(name + " is not a selector");
		return;
	}
	
	var valChanged = false;
	var curSelText = o.options[o.selectedIndex].value;
	
	// find the value in the list of options and select it
	for (var i = 0; val != null && i < o.length; i++) {
		if (val == "") {
			// the empty value of a selector is a string of dashes
			if (o.options[i].text.indexOf("---") == 0) {
				o.selectedIndex = i;
				if (curSelText != val) valChanged = true;
				break;
			}
		}
		else {
			if (o.options[i].value == val) {
				// Fire the onchange only if the selected changes
				o.selectedIndex = i;
				if (curSelText != val) valChanged = true;
				break;
			}
		}
	}
	// Fire the onchange method if the value has been changed
	if (valChanged && o.onchange != null) try {
		o.onchange();
	} 
	catch (E) {
		alert("exception in '" + o.onchange + "': " + E.description);
	}
}


function cctl_onEquipmentTypeSelectionChanged() {
	typeSelectionChanging = true;
	var et = document.getElementById("equipmentType");
	if (et == null) {
		alert("Required element 'equipmentType' missing!");
		return;
	}
	var ed = document.getElementById("equipmentDescription");
	if (ed == null) {
		alert("Required element 'equipmentDescription' missing!");
		return;
	}
	var pe = document.getElementById("period");
	if (pe == null) {
		alert("Required element 'period' missing!");
		return;
	}
	var fr = document.getElementById("frequency");
	if (fr == null) {
		alert("Required element 'frequency' missing!");
		return;
	}
	var eq = document.getElementById("equipmentQuantity");
	if (eq == null) {
		alert("Required element 'equipmentQuantity' missing!");
		return;
	}
	var ea = document.getElementById("equipmentAmount");
	if (ea == null) {
		alert("Required element 'equipmentAmount' missing!");
		return;
	}
	var pd = document.getElementById("promoDescription");
	if (pd == null) {
		alert("Required element 'promoDescription' missing!");
		return;
	}
	var pc = document.getElementById("promoConditions");
	if (pc == null) {
		alert("Required element 'promoConditions' missing!");
		return;
	}
	var tp = document.getElementById("totalPromosAddedToList");
	if (tp == null) {
		alert("Required element 'totalPromosAddedToList' missing!");
		return;
	}
	var em = document.getElementById("equipmentModelContainer");
	if (em == null) {
		alert("Required element 'equipmentModelContainer' missing!");
		return;
	}
	var md = document.getElementById("equipmentModel");
	if (md == null) {
		alert("Required element 'equipmentModel' missing!");
		return;
	}
	var np = document.getElementById("numberOfPorts");
	if (np == null) {
		alert("Required element 'numberOfPorts' missing!");
		return;
	}
	
	var selectedValue = et.options(et.selectedIndex).value;
	debugWindow.writeln("cctl_onEquipmentTypeSelectionChanged: selected equipment type is " + selectedValue);
	
	// if a promo is selected
	if (promotion.isPromotion(selectedValue)) {
		// freeze the period and frequency to the promotion's period and frequency
		cctl_setSelectedValue("period", promotion.getPromotionPeriod(selectedValue));
		cctl_setSelectedValue("frequency", promotion.getPromotionFrequency(selectedValue));
		sessionController.save();
		pe.disabled = true;
		fr.disabled = true;
		md.disabled = false;
		eq.disabled = false;
		ed.disabled = false;
		ea.disabled = false;
		// show the description and conditions of the promotion
		pd.innerHTML = promotion.getPromotionDescription(selectedValue);
		pc.innerHTML = promotion.getPromotionConditions(selectedValue, "<BR>");
		em.innerHTML = "<select size='1' class='formcontent' name='equipmentModel' onchange='javascript:calculatorController.onEquipmentModelSelectionChanged();'></select>";
		cctl_FillModels(selectedValue);
	}
	// else if no promo is added to the list
	else 
		if (selectedValue == "") {
			// no type is selected
			md.disabled = true;
			eq.disabled = true;
			ed.disabled = true;
			ea.disabled = true;
		}
		else {
			// if no promotions are added to the list
			var promoCount = tp.value;
			if (promoCount == 0) {
				// unfreeze the period and frequency
				sessionController.setValue("period", sessionController.getValue("period"), false);
				sessionController.setValue("frequency", sessionController.getValue("frequency"), false);
			}
			
			var childNode = em.firstChild;
			// Change the node type if necessary
			if (childNode == null || childNode.nodeName != "INPUT") em.innerHTML = "<input name='equipmentModel' size='8' class='formcontent'>";
			// hide the description and conditions of the promotion
			pd.innerHTML = "";
			pc.innerHTML = "";
			md.disabled = false;
			eq.disabled = false;
			ed.disabled = false;
			ea.disabled = false;
		}
	
	if (isPricePerPort() || isPricePerUser()) {
		if (document.location.href.indexOf("calcCSCit.htm") != -1 &&
		document.getElementById("repID").selectedIndex == 0) {
			fr.disabled = false;
			pe.selectedIndex = 4;
		}
		else {
			fr.disabled = true;
		}
	}
	
	// if a promo is added to the list
	// limit the equipment type selection combo to regulars and only the promotions with the same period and frequency
	// and keep the period and frequency frozen
	typeSelectionChanging = false;
}

function cctl_onEquipmentModelSelectionChanged() {
	var et = document.getElementById("equipmentType");
	if (et == null) {
		alert("Required element 'equipmentType' missing!");
		return;
	}
	var ed = document.getElementById("equipmentDescription");
	if (ed == null) {
		alert("Required element 'equipmentDescription' missing!");
		return;
	}
	
	var selectedValue = et.options(et.selectedIndex).value;
	// if a promo is selected
	if (promotion.isPromotion(selectedValue)) {
		// Show the description of the model
		ed.value = getPromotionModelDescription(selectedValue, sessionController.getValue("equipmentModel").val);
		if (ed.value != "") {
			ed.disabled = true;
		}
		else {
			ed.disabled = false;
		}
	}
	else {
		ed.value = "";
		ed.disabled = false;
	}
}

function cctl_onLeaseProductSelectionChanged() {
	var lt = document.getElementById("leaseProduct");
	if (lt == null) {
		alert("Required element 'leaseProduct' missing!");
		return;
	}
	
	var np = document.getElementById("numberOfPorts");
	if (np == null) {
		alert("Required element 'numberOfPorts' missing!");
		return;
	}
	var fr = document.getElementById("frequency");
	if (fr == null) {
		alert("Required element 'frequency' missing!");
		return;
	}
	var lnp = document.getElementById("lblNumberOfPorts");
	if (lnp == null) {
		alert("Required element 'lblNumberOfPorts' missing!");
		return;
	}
	var lthdr = document.getElementById("lblTabhdrPorts");
	if (lthdr == null) {
		alert("Required element 'lblTabhdrPorts' missing!");
		return;
	}
	var eqlistcol3 = document.getElementById("equipmentList.col3");
	if (eqlistcol3 == null) {
		alert("Required element 'equipmentList.col3' missing!");
		return;
	}
	
	var vlblAmountPerEq = document.getElementById("lblAmountPerEq");
	if (vlblAmountPerEq == null) {
		alert("Required element 'lblAmountPerEq' missing!");
		return;
	}
	var vlblFirstPayment = document.getElementById("lblFirstPayment");
	if (vlblFirstPayment == null) {
		alert("Required element 'lblFirstPayment' missing!");
		return;
	}
	var vlblPaymentAmount = document.getElementById("lblPaymentAmount");
	if (vlblPaymentAmount == null) {
		alert("Required element 'lblPaymentAmount' missing!");
		return;
	}
	var vlblNumberOfPorts = document.getElementById("lblNumberOfPorts");
	var vlblTabhdrPorts = document.getElementById("lblTabhdrPorts");
	
	if (isSpecialLeaseType_0perc()) {
		g_maxTransaction = g_maxTransaction_0Perc;
	}
	else {
		g_maxTransaction = g_maxTransactionNorm;
	}
	
	if (isPricePerPort()) {
		vlblAmountPerEq.innerHTML = g_hdrLblAmountPerEqppp;
		vlblFirstPayment.innerHTML = g_hdrLblFirstPaymentppp;
		vlblPaymentAmount.innerHTML = g_hdrLblPaymentAmountppp;
		vlblNumberOfPorts.innerHTML = g_hdrLblEnterAmountppp;
		vlblTabhdrPorts.innerHTML = g_hdrLblTabhdrPortsppp;
		
		lthdr.style["visibility"] = "";
		eqlistcol3.style["visibility"] = "";
		lnp.style["visibility"] = "";
		fr.disabled = false;
		fr.selectedIndex = 0;
		cctl_frequencyChanged();
		if (lt.disabled == false) np.disabled = false;
		np.value = 1;
		np.style["visibility"] = "";
	}
	else 
		if (isPricePerUser()) {
			vlblAmountPerEq.innerHTML = g_hdrLblAmountPerEqppu;
			vlblFirstPayment.innerHTML = g_hdrLblFirstPaymentppu;
			vlblPaymentAmount.innerHTML = g_hdrLblPaymentAmountppu;
			vlblNumberOfPorts.innerHTML = g_hdrLblEnterAmountppu;
			vlblTabhdrPorts.innerHTML = g_hdrLblTabhdrPortsppu;
			
			lthdr.style["visibility"] = "";
			eqlistcol3.style["visibility"] = "";
			lnp.style["visibility"] = "";
			fr.disabled = false;
			fr.selectedIndex = 0;
			cctl_frequencyChanged();
			if (lt.disabled == false) np.disabled = false;
			np.value = 1;
			np.style["visibility"] = "";
		}
		else {
			vlblAmountPerEq.innerHTML = g_hdrLblAmountPerEq;
			vlblFirstPayment.innerHTML = g_hdrLblFirstPayment;
			vlblPaymentAmount.innerHTML = g_hdrLblPaymentAmount;
			vlblNumberOfPorts.innerHTML = g_hdrLblEnterAmount;
			vlblTabhdrPorts.innerHTML = g_hdrLblTabhdrPorts;
			
			lthdr.style["visibility"] = "hidden";
			eqlistcol3.style["visibility"] = "hidden";
			lnp.style["visibility"] = "hidden";
			fr.disabled = false;
			fr.selectedIndex = 0;
			np.disabled = true;
			np.value = "";
			np.style["visibility"] = "hidden";
		}
	
	// set the label in the disclaimer if present on the page
	var lbl = document.getElementById("leaseProductLabel");
	if (lbl != null) {
		var v = lt.options[lt.selectedIndex].text;
		if (v != "" && v.indexOf("----") < 0) lbl.innerText = v.toLowerCase();
	}
	
	// extra disclaimer text
	var v = lt.options[lt.selectedIndex].text;
	disclaimer_addition(v);
}

function disclaimer_addition(text) {
	if (text.indexOf("Voice") != -1 
		|| text.indexOf("Network") != -1
		|| text.indexOf("0% Financ") != -1
		|| text.indexOf("A2C 0%") != -1
		) {
	//	document.getElementById("extraDisclaimer").style.visibility = 'visible';
		document.getElementById("extraDisclaimer").style.display = 'inline';
	}
	else {
	//	document.getElementById("extraDisclaimer").style.visibility = 'hidden';
		document.getElementById("extraDisclaimer").style.display = 'none';
	}
}

function cctl_FillEquipmentTypesForPeriodAndFrequency() {
	var fr = document.getElementById("frequency");
	if (fr == null) {
		alert("Required element 'frequency' missing!");
		return;
	}
	var pr = document.getElementById("period");
	if (pr == null) {
		alert("Required element 'period' missing!");
		return;
	}
	
	// clear the combo (which also adds the default options implemented by the HTML in the page)
	cctl_ClearSelector("equipmentType", g_defaultEquipmentTypeOptions)
	var et = document.getElementById("equipmentType");
	if (et == null) {
		alert("Required element 'equipmentType' missing!");
		return;
	}
	
	// Add the promotions to the equipment type combo
	//alert(pr.options[pr.selectedIndex].value + "  " + fr.options[fr.selectedIndex].value);
	var promotions = promotion.getPromotionTableForPeriodAndFrequency(pr.options[pr.selectedIndex].value, fr.options[fr.selectedIndex].value);
	for (var i = 0; i < promotions.length; i++) {
		var promo = new Option(promotions[i][1], promotions[i][0]);
		et.options.add(promo);
	}
}

function cctl_FillEquipmentTypes() {
	// clear the combo
	cctl_ClearSelector("equipmentType", g_defaultEquipmentTypeOptions);
	var et = document.getElementById("equipmentType");
	if (et == null) {
		alert("Required element 'equipmentType' missing!");
		return;
	}
	
	// Add the promotions to the equipment type combo
	var promotions = promotion.getPromotionTable();
	for (var i = 0; i < promotions.length; i++) {
		var promo = new Option(promotions[i][1], promotions[i][0]);
		et.options.add(promo);
	}
	
	cctl_onEquipmentTypeSelectionChanged();
}

function cctl_FillModels(promotionId) {
	// clear the combo
	cctl_ClearSelector("equipmentModel", g_defaultEquipmentModelOptions);
	var em = document.getElementById("equipmentModel");
	if (em == null) {
		alert("Required element 'equipmentModel' missing!");
		return;
	}
	
	if (promotion.isPromotion(promotionId)) {
		// Add the promotions to the equipment model combo
		var models = promotion.getPromotionModels(promotionId);
		for (var i = 0; i < models.length; i++) {
			var model = new Option(models[i][1], models[i][0]);
			em.options.add(model);
		}
	}
}

function cctl_openHelp() {
	var URL = unescape(document.location.href);
	var helpPageURL = URL.replace(".htm", "help.htm");
	helpPageURL = helpPageURL.replace("/calcCSC", "/calc");
	var helpPageHeight = '620';
	// assign to the global help page height if defined
	try {
		helpPageHeight = g_helpPageHeight;
	} 
	catch (E) {
	}
	window.open(helpPageURL, null, 'height=' + helpPageHeight + ',width=740,status=0,toolbar=0,menubar=0,location=0,top=50,left=50');
}

function cctl_navigateToPrint() {

	sessionController.save();
	
	var URL = unescape(document.location.href);
	var printPageURL = URL.replace(".htm", "print.htm");
	printPageURL = printPageURL.replace("/calcCSC", "/calc");
	//alert(printPageURL);
	window.navigate(printPageURL);
}

// This function determines the extension of the rate table name to look for in the rate sheet.
// The extension currently contains the following components:
// - asset (product category, asset, promotion name)
// - lease (product)type
function cctl_determineExtension(asset) {
	var ext = "";
	
	// Add the asset to the rate table extension
	if (asset != null) {
		try {
			asset = onLocalTranslateAsset(asset, false);
		} 
		catch (E) {
		}
		ext += asset;
	}
	
	// Get the lease product if applicable and add it to the rate table extension
	var lt = document.getElementById("leaseProduct");
	if (lt != null) {
		var product = lt.options[lt.selectedIndex].text;
		try {
			product = onLocalTranslateLeaseProduct(product, false);
		} 
		catch (E) {
		}
		ext += product;
	}
	
	// Get the additional commission if applicable and add it to the rate table extension
	// If the commissions table is not defined no extension is added.
	var cid = document.getElementById("repID");
	if (cid != null && cc_getCommissions(g_countryAbbreviation)) {
		ext += cid.value;
	}
	
	// Remove all unwanted ASCII characters
	return ext.replace(/[^a-zA-Z0-9]+/g, "");
}

function cctl_isVendorEquipment(equipmentType) {
	var et = document.getElementById("equipmentType");
	if (et == null) return false;
	
	// Find the value of the equipment type in the dropdown box. A value of 1 denotes
	// vendor specific equipment. The values in the dropdown box are taken from the
	// assetTable in the ratesheet or the promotions in the promo sheet. Promos are
	// considered vendor specific.
	for (var i = 0; i < et.options.length; i++) {
		if (et.options[i].text == equipmentType) {
			return ((et.options[i].value == 1) || promotion.isPromotion(et.options[i].value));
		}
	}
	return false;
}

function cctl_isSettlement(equipmentType) {
	// Check if the equipment type (previously selected in the dropdown box) is equal to  
	// "Settlement amount".
	// Maybe this function should be replaced by a somekind of data driven one.
	return (equipmentType == "Settlement amount");
}

function cctl_Calculate() {
	var fr = document.getElementById("frequency");
	if (fr == null) {
		alert("Required element 'frequency' missing!");
		return;
	}
	var pr = document.getElementById("period");
	if (pr == null) {
		alert("Required element 'period' missing!");
		return;
	}
	var ta = document.getElementById("totalAmounts");
	if (ta == null) {
		alert("Required element 'totalAmounts' missing!");
		return;
	}
	var tp = document.getElementById("totalPayments");
	if (tp == null) {
		alert("Required element 'totalPayments' missing!");
		return;
	}
	var tf = document.getElementById("totalFirstPayments");
	if (tf == null) {
		alert("Required element 'totalFirstPayments' missing!");
		return;
	}
	var pt = document.getElementById("totalPromosAddedToList");
	if (pt == null) {
		alert("Required element 'totalPromosAddedToList' missing!");
		return;
	}
	var ts = document.getElementById("totalsStatus");
	if (ts == null) {
		alert("Required element 'totalsStatus' missing!");
		return;
	}
	var np = document.getElementById("numberOfPorts");
	if (np == null) {
		alert("Required element 'number of ports' missing!");
		return;
	}
	
	// get number of ports
	//var npval = parseInt(sessionController.getValue("numberOfPorts").val);
	var npval = parseInt(np.value);
	if (isNaN(npval) || npval <= 0) {
		npval = 1;
	}
	
	var equipmentTable = itemTable("equipmentList");
	var type = "";
	var promotionId = "";
	var amount = 0;
	var totalAmount = 0;
	var totalPayment = 0;
	var totalFirstPayment = 0;
	var totalSettlementAmount = 0;
	var rate;
	var typeColumn = 1;
	
	var totalAmountColumn = equipmentTable.getColumn(2);
	var numberOfPortsColumn = equipmentTable.getColumn(3);
	var firstPaymentColumn = equipmentTable.getColumn(4);
	var pauseColumn = equipmentTable.getColumn(5);
	var furtherPaymentsColumn = equipmentTable.getColumn(6);
	var paymentAmountColumn = equipmentTable.getColumn(7);
	var endPaymentColumn = equipmentTable.getColumn(8);
	
	var promoCount = 0;
	var frequency = fr.options(fr.selectedIndex).value;
	var period = pr.options(pr.selectedIndex).value;
	var firstPayment;
	var payment;
	var endPayment;
	
	// If the global variables g_vendor and g_nonVendor are assigned,
	// then subtotals will be calculated for vendor and nonVendor equipment
	var typeOfEquipment;
	var totalNonVendor = 0;
	var totalVendor = 0;
	var totalSettlementAmount = 0;
	
	ta.innerHTML = "";
	sessionController.setValue("unformatted_totalAmounts", 0, false)
	tp.innerHTML = "";
	sessionController.setValue("unformatted_totalPayments", 0, false)
	tf.innerHTML = "";
	sessionController.setValue("unformatted_totalFirstPayments", 0, false)
	ts.innerHTML = "";
	
	if (equipmentTable.getNrOfItems() > 0) {
		// Calculate the total amount for all equipment. The getRate method requires the total amount to determine
		// the payment profile for each line item
		for (var q = 0; q < equipmentTable.getNrOfItems(); q++) {
			var qc = equipmentTable.getRowNr(q); // get the real row nr for getEntry
			amount = nf_parseFloat(equipmentTable.getEntry(qc, totalAmountColumn));
			
			// Determine the amount allocated to vendor specific equipment
			typeOfEquipment = equipmentTable.getEntry(qc, typeColumn);
			
			//alert("calculating: "+amount+" type: "+ typeOfEquipment);
			
			if (cctl_isVendorEquipment(typeOfEquipment)) totalVendor += amount;
			else 
				totalNonVendor += amount;
			
			if (cctl_isSettlement(typeOfEquipment)) totalSettlementAmount += amount;
			
			totalAmount += amount;
		}
		ta.innerHTML = nf_formatNumeric(totalAmount);
		
		if (document.getElementById("unformatted_totalNonVendorAmount") != null) sessionController.setValue("unformatted_totalNonVendorAmount", totalNonVendor, false);
		if (document.getElementById("unformatted_totalVendorAmount") != null) sessionController.setValue("unformatted_totalVendorAmount", totalVendor, false);
		if (document.getElementById("unformatted_totalSettlementAmount") != null) sessionController.setValue("unformatted_totalSettlementAmount", totalSettlementAmount, false);
		sessionController.setValue("unformatted_totalAmounts", totalAmount, false);
		
		for (var q = 0; q < equipmentTable.getNrOfItems(); q++) {
			var qc = equipmentTable.getRowNr(q); // get the real row nr for getEntry
			// determine amount for the equipment and the promotion type
			type = equipmentTable.getEntry(qc, typeColumn);
			amount = nf_parseFloat(equipmentTable.getEntry(qc, totalAmountColumn));
			promotionId = promotion.getPromotionId(type);
			if (promotion.isPromotion(promotionId)) {
				// Promotion:
				promoCount++;
				
				rate = promotion.getFirstPaymentRate(promotionId);
				firstPayment = rateCalculator.calculate(amount, 0, rate);
				rate = promotion.getPromotionRate(promotionId);
				payment = rateCalculator.calculate(amount, 0, rate);
				rate = promotion.getEndPaymentRate(promotionId);
				endPayment = rateCalculator.calculate(amount, 0, rate);
				
				equipmentTable.setEntry(qc, firstPaymentColumn, nf_formatNumeric(firstPayment / npval), false, true);
				equipmentTable.setEntry(qc, furtherPaymentsColumn, promotion.getPromotionFurtherPayments(promotionId), false, true);
				equipmentTable.setEntry(qc, paymentAmountColumn, nf_formatNumeric(payment / npval), false, true);
				equipmentTable.setEntry(qc, pauseColumn, promotion.getPromotionPause(promotionId), false, true);
				if (endPayment > 0) {
					equipmentTable.setEntry(qc, endPaymentColumn, nf_formatNumeric(endPayment / npval), false, true);
				}
				else {
					equipmentTable.setEntry(qc, endPaymentColumn, "", false, true);
				}
			}
			else {
				// Regular:	get the rate for this type of asset
				rate = rateCalculator.getRate(totalAmount, frequency, period, g_countryAbbreviation, cctl_determineExtension(type))
				payment = rateCalculator.calculate(amount, 0, rate);
				firstPayment = payment;
				equipmentTable.setEntry(qc, firstPaymentColumn, nf_formatNumeric(firstPayment / npval), false, true);
				equipmentTable.setEntry(qc, furtherPaymentsColumn, cctl_DetermineNrOfFurtherPaymentsForRegular(period, frequency), false, true);
				equipmentTable.setEntry(qc, paymentAmountColumn, nf_formatNumeric(payment / npval), false, true);
				equipmentTable.setEntry(qc, pauseColumn, 0, false, true);
				equipmentTable.setEntry(qc, endPaymentColumn, "", false, true);
				
				var nocomm_payment = rateCalculator.calculate(amount, 0, rate);
			}
			// use the displayed values to update the totals to prevent rounding errors
			totalFirstPayment += nf_parseFloat(equipmentTable.getEntry(qc, firstPaymentColumn));
			totalPayment += nf_parseFloat(equipmentTable.getEntry(qc, paymentAmountColumn));
		}
		
		tp.innerHTML = nf_formatNumeric(totalPayment);
		sessionController.setValue("unformatted_totalPayments", totalPayment, false);
		
		tf.innerHTML = nf_formatNumeric(totalFirstPayment);
		sessionController.setValue("unformatted_totalFirstPayments", totalFirstPayment, false);
		
		var blankPaymentColumns = false;
		//		if (typeof g_minTransaction != "undefined" && !isNaN(g_minTransaction) && totalAmount<g_minTransaction/npval) {
		if (typeof g_minTransaction != "undefined" && !isNaN(g_minTransaction) && totalAmount < g_minTransaction) {
			ts.innerHTML = g_minTransactionMsg;
			blankPaymentColumns = g_blankPaymentAtMin;
			disableButtonContinue(true);
		}
		//		else if (typeof g_maxTransaction != "undefined" && !isNaN(g_maxTransaction) && totalAmount>g_maxTransaction/npval) {
		else 
			if (typeof g_maxTransaction != "undefined" && !isNaN(g_maxTransaction) && totalAmount > g_maxTransaction) {
				ts.innerHTML = g_maxTransactionMsg;
				blankPaymentColumns = g_blankPaymentAtMax;
				disableButtonContinue(true);
			}
			else 
				if (typeof g_minPercFormVendor != "undefined" && (g_minPercFormVendor * totalAmount > totalVendor)) {
					ts.innerHTML = g_minPercFormVendorMsg;
					disableButtonContinue(true);
				}
				else {
					disableButtonContinue(false);
				}
		
		if (blankPaymentColumns) {
			// blank the payment related columns
			equipmentTable.blankColumn(firstPaymentColumn);
			equipmentTable.blankColumn(pauseColumn);
			equipmentTable.blankColumn(furtherPaymentsColumn);
			equipmentTable.blankColumn(paymentAmountColumn);
			equipmentTable.blankColumn(endPaymentColumn);
			// blank the payment totals
			tp.innerHTML = "";
			sessionController.setValue("unformatted_totalPayments", 0, false)
			tf.innerHTML = "";
			sessionController.setValue("unformatted_totalFirstPayments", 0, false)
		}
	}
	
	// Allow country specific local calculations if the method onLocalCalculate is defined
	try {
		onLocalCalculate(equipmentTable);
	} 
	catch (E) {
	}
	
	// if the list has no more promotions unfreeze the period and frequency and refill the equipment type combo with all promotions
	pt.value = promoCount;
	
	if (promoCount == 0) {
		// unfreeze the period and frequency
		sessionController.setValue("period", sessionController.getValue("period"), false);
		sessionController.setValue("frequency", sessionController.getValue("frequency"), false);
		
		if (!typeSelectionChanging) {
			cctl_FillEquipmentTypes();
		}
	}
	else {
		// freeze the period and frequency to the promotion's period and frequency
		sessionController.setValue("period", sessionController.getValue("period"), true);
		sessionController.setValue("frequency", sessionController.getValue("frequency"), true);
		
		// refill the equipment type combo with just the promotions having the same frequency and period
		if (!typeSelectionChanging) {
			cctl_FillEquipmentTypesForPeriodAndFrequency();
		}
	}
}

function disableButtonContinue(disable) {
	var button = document.getElementById("continue");
	if (typeof button != "undefined") {
		button.disabled = disable;
	}
}

function cctl_DetermineNrOfFurtherPaymentsForRegular(period, frequency) {
	var freqPerYear;
	switch (frequency.toUpperCase()) {
		case "MONTH":
			freqPerYear = 12;
			break;
		case "BIMONTHLY":
			freqPerYear = 6;
			break;
		case "QUARTER":
			freqPerYear = 4;
			break;
		case "3PERYEAR":
			freqPerYear = 3;
			break;
		case "SEMIANNUAL":
			freqPerYear = 2;
			break;
		case "YEAR":
			freqPerYear = 1;
			break;
	}
	return (period * freqPerYear) - 1;
}

function cctl_periodChanged() {
	var pv = document.getElementById("periodValue");
	if (pv == null) {
		alert("Required element 'periodValue' missing!");
		return;
	}
	var pe = document.getElementById("period");
	if (pe == null) {
		alert("Required element 'period' missing!");
		return;
	}
	
	pv.value = pe.options[pe.selectedIndex].value;
	cctl_Calculate();
}

function cctl_frequencyChanged() {
	var fv = document.getElementById("frequencyValue");
	if (fv == null) {
		alert("Required element 'frequencyValue' missing!");
		return;
	}
	var fe = document.getElementById("frequency");
	if (fe == null) {
		alert("Required element 'frequency' missing!");
		return;
	}
	
	fv.value = fe.options[fe.selectedIndex].value;
	cctl_Calculate();
}

function cctl_prefillEquipmentTypes() {
	// fill the vendor Value (if present)
	var value = document.getElementById("vendorValue");
	if (value != null) {
		value.innerText = "error";
		if (typeof g_vendor != "undefined") value.innerText = g_vendor;
	}
	
	// fill the non-vendor Value (if present)
	value = document.getElementById("nonVendorValue");
	if (value != null) {
		value.innerText = "error";
		if (typeof g_nonVendor != "undefined") value.innerText = g_nonVendor;
	}
}

// prime the equipment type combo with the assets defined in the rate sheet.
// The assets table in the rate sheet contains two entries per asset.
// The first entry is the asset's name
// The second entry contains a 1 if the asset is a Vendor asset else 0.
// [in] elementName: the name of the HTML selector holding the list of available assets
function cctl_fillAssets(elementName) {
	if (elementName == null) elementName = "equipmentType";
	var et = document.getElementById(elementName);
	if (et == null) {
		alert("Required element '" + elementName + "' missing!");
		return;
	}
	var assets = null;
	try {
		assets = cc_getAssets(g_countryAbbreviation);
	} 
	catch (E) {
	}
	if (assets != null) {
		et.options.length = assets.length + 1;
		et.options[0] = new Option("------", "", true, true);
		var i;
		for (i = 1; i < assets.length + 1; i++) {
			et.options[i] = new Option(assets[i - 1][0], assets[i - 1][1]);
		}
	}
}

// prime the lease products box with the products defined in the rate sheet.
// Promoted products are considered Vender specific assets. See also cctl_fillAssets()
// [in] elementName: the name of the HTML selector holding the list of available lease products
function cctl_fillProducts(elementName) {
	if (elementName == null) elementName = "leaseProduct";
	var et = document.getElementById(elementName);
	if (et == null) {
		alert("Required element '" + elementName + "' missing!");
		return;
	}
	var products = null;
	try {
		products = cc_getProducts(g_countryAbbreviation);
	} 
	catch (E) {
	}
	if (products && et.options) {
		et.options.length = products.length + 1;
		et.options[0] = new Option("------", "", true, true);
		var i;
		for (i = 1; i < products.length + 1; i++) {
			var product = products[i - 1];
			// perform a locale dependant translation if defined
			try {
				product = onLocalTranslateLeaseProduct(product, true);
			} 
			catch (E) {
			}
			et.options[i] = new Option(product, 1);
		}
	}
}

// Prime the 'ID' box with the commissions found in the rate sheet
// The first entry found in the commission table will be the default selected commission
// [in] elementName: the name of the HTML selector holding the list of available commissions
function cctl_fillCommissionBox(elementName) {
	if (elementName == null) elementName = "repID";
	var et = document.getElementById(elementName);
	if (et == null) {
		alert("Required element '" + elementName + "' missing!");
		return;
	}
	var commissions = null;
	try {
		commissions = cc_getCommissions(g_countryAbbreviation);
	} 
	catch (E) {
	}
	if (commissions != null) {
		et.options.length = commissions.length;
		1;
		var i;
		for (i = 0; i < commissions.length; i++) {
			et.options[i] = new Option(commissions[i][0], commissions[i][1]);
		}
	}
	else {
		et.value = "0.00";
		et.disabled = true;
	}
}

function cctl_onLoad(automaticSessionHandling) {
	debugWindow.writeln("CalculatorController onLoad");
	if (automaticSessionHandling == null) automaticSessionHandling = true;
	
	// The automatic session handling is turned of by the request page which also uses the calculator controller to
	// manage the equipment list. The request page manages its own asset, product and commission boxes.
	if (automaticSessionHandling) {
		cctl_fillAssets();
		cctl_fillProducts();
		cctl_fillCommissionBox();
	}
	
	// Prefill the equipment types with the global values specified in the page
	cctl_prefillEquipmentTypes();
	g_defaultEquipmentTypeOptions = cctl_BackupOptions(document.getElementById("equipmentType"), g_defaultEquipmentTypeOptions);
	g_defaultEquipmentModelOptions = cctl_BackupOptions(document.getElementById("equipmentModel"), g_defaultEquipmentModelOptions);
	
	// If automatic session handling is turned on, the fields on the calculator page are automatically stored in the session cookie when
	// changed or restored by pressing the back button.
	if (automaticSessionHandling) {
		var dt = document.getElementById("date");
		if (dt == null) {
			alert("Required element 'date' missing!");
			return;
		}
		// store the values for those elements that need to show that value after a postback
		// the validator fields are automatically marked as storage fields
		sessionController.addField("unformatted_totalAmounts");
		if (document.getElementById("unformatted_totalNonVendorAmount") != null) sessionController.addField("unformatted_totalNonVendorAmount");
		if (document.getElementById("unformatted_totalVendorAmount") != null) sessionController.addField("unformatted_totalVendorAmount");
		sessionController.addField("unformatted_totalPayments");
		sessionController.addField("unformatted_totalFirstPayments");
		sessionController.addField("periodValue");
		sessionController.addField("frequencyValue");
		if (document.getElementById("leaseProductValue") != null) sessionController.addField("leaseProductValue");
		sessionController.addField("provision");
		
		sessionController.addField("quoteTo");
		sessionController.addField("quoteFrom");
		sessionController.addField("repID");
		sessionController.addField("phoneNr");
		sessionController.addField("reseller");
		sessionController.addField("comment");
		sessionController.addField("date");
		
		sessionController.addField("period");
		sessionController.addField("frequency");
		sessionController.addField("disclaimer");
		
		if (document.getElementById("leaseProduct") != null) sessionController.addField("leaseProduct");
		if (document.getElementById("numberOfPorts") != null) sessionController.addField("numberOfPorts");
		
		// check the page integrity and set the defaults
		sessionController.restore();
		
		cctl_FillEquipmentTypes();
		d = new Date();
		dt.value = d.getDate() + "-" + (d.getMonth() + 1) + "-" + d.getYear();
		// update the equipment table
		it_restoreFromSessionState("equipmentList");
		cctl_Calculate();
	}
}

function calcController_Setup() {
	this.onLoad = cctl_onLoad;
	this.openHelp = cctl_openHelp;
	this.navigateToPrint = cctl_navigateToPrint;
	this.FillModels = cctl_FillModels;
	this.onEquipmentModelSelectionChanged = cctl_onEquipmentModelSelectionChanged;
	this.onEquipmentTypeSelectionChanged = cctl_onEquipmentTypeSelectionChanged;
	this.onLeaseProductSelectionChanged = cctl_onLeaseProductSelectionChanged;
	this.AddItem = cctl_AddItem;
	this.onRemoveItem = cctl_onRemoveItem;
	this.ClearAll = cctl_ClearAll;
	this.Calculate = cctl_Calculate;
	this.fillEquipmentTypes = cctl_FillEquipmentTypes;
	this.fillAssets = cctl_fillAssets;
	this.fillProducts = cctl_fillProducts;
	this.fillCommissions = cctl_fillCommissionBox;
	this.periodChanged = cctl_periodChanged;
	this.frequencyChanged = cctl_frequencyChanged;
	return this;
}

var calculatorController = new Object();
calculatorController = calcController_Setup();
