// ###	Creates structured data for a lease item. An array of these instances is
//		passed into EstimatorDataClass function as leaseDataArray
function LeaseDataClass (acquisitionFeeNum, mileageCdeVal, moneyFactorFloat, residualPctFloat, termNum) {
	this.acquisitionFeeAmt = acquisitionFeeNum;
	this.mileageCde = mileageCdeVal;
	this.moneyFactor = moneyFactorFloat;
	this.residualPct = residualPctFloat;
	this.term = termNum;
}

// ###	Core Data class for the payment estimator
function EstimatorDataClass (yearNum, baseMsrpNum, destFeeNum, leaseDataArray) {
//	### PRIVATE ###
	var modelYear = yearNum;
	var baseMSRP = baseMsrpNum;
	var destinationFee = destFeeNum;
	var leaseDataList = leaseDataArray;
	var hasLeaseData = checkHasLeaseData(leaseDataList);
	var loanData = new LoanDataClass ( (baseMSRP+destinationFee), 60, 3000, 0, '6.0'); //These values are the page defaults
	var leaseData = new LeaseDataClass ( (baseMSRP+destinationFee), 24, 3000, 0, 'L'); //These values are the page defaults
	
	// Data for the lease part of the app is stored in this instace. Holds and
	// drives all lease specific data and functions
	function LeaseDataClass (estSellingPriceNum, termNum, downPaymentNum, tradeInNum, mileageCodeValue) {
		var estimatedSellingPrice = estSellingPriceNum;
		var term = termNum;
		var downPayment = downPaymentNum;
		var tradeIn = tradeInNum;
		var mileageCode = mileageCodeValue;
		
		this.getEstimatedSellingPrice = function (formatFlag) { if (formatFlag) return convertToDollar(estimatedSellingPrice); else return estimatedSellingPrice; }
		this.setEstimatedSellingPrice = function (value) { estimatedSellingPrice = value; }
		
		this.getTerm = function () { return term; };
		this.setTerm = function (value) { term = value; };
		
		this.getDownPayment = function () { return downPayment; };
		this.setDownPayment = function (value) { downPayment = value; };
		
		this.getTradeIn = function () { return tradeIn; };
		this.setTradeIn = function (value) { tradeIn = value; };
		
		this.getMileageCode = function () { return mileageCode; };
		this.setMileageCode = function (value) { mileageCode = value; };
		
		this.getMonthlyLeasePaymentObj = function () { return calculateLease(estimatedSellingPrice,(baseMSRP+destinationFee),downPayment,tradeIn,mileageCode,term); }
	}
	
	// Data for the loan (aka purchase) part of the app is stored in this instace.
	// Holds and drives all loan specific data and functions
	function LoanDataClass (estSellingPriceNum, termNum, downPaymentNum, tradeInNum, aprValue) {
		var estimatedSellingPrice = estSellingPriceNum;
		var term = termNum;
		var downPayment = downPaymentNum;
		var tradeIn = tradeInNum;
		var apr = aprValue;
		
		this.getEstimatedSellingPrice = function (formatFlag) { if (formatFlag) return convertToDollar(estimatedSellingPrice); else return estimatedSellingPrice; }
		this.setEstimatedSellingPrice = function (value) { estimatedSellingPrice = value; }
		
		this.getTerm = function () { return term; };
		this.setTerm = function (value) { term = value; };
		
		this.getDownPayment = function () { return downPayment; };
		this.setDownPayment = function (value) { downPayment = value; };
		
		this.getTradeIn = function () { return tradeIn; };
		this.setTradeIn = function (value) { tradeIn = value; };
		
		this.getApr = function () { return apr; };
		this.setApr = function (value) { apr = value; };
		
		this.getMonthlyLoanPaymentObj = function () { return calculateLoan( estimatedSellingPrice, downPayment, tradeIn, (apr/100), term ); }
	}
	
	// Validates and calculates lease data.
	// Note: this is primarily legacy code with minor modifications
	function calculateLease(fLeasePrice,fActualMSRP,fDownPay,fTradeIn,fLeaseType,fTerm) {
		var estLeasePrice = fLeasePrice * 1;
		var actualMSRP = fActualMSRP * 1;
		var downPay = fDownPay * 1;
		var tradeIn = fTradeIn * 1;
	
		var errorMsg;
		var errorCheck = false; // false = no error; true = error
		var errorType = "lease";
		
		// set all values from the array
		var moneyFactor = getLeaseDataForTypeAndTerm(fLeaseType,fTerm,'moneyFactor');//leaseDataArray[fLeaseType][fTerm].moneyfactor  * 1;
		var residualPct = getLeaseDataForTypeAndTerm(fLeaseType,fTerm,'residualPct');//leaseDataArray[fLeaseType][fTerm].residual  * 1;
		var acquisitionFee = getLeaseDataForTypeAndTerm(fLeaseType,fTerm,'acquisitionFeeAmt');//leaseDataArray[fLeaseType][fTerm].destination  * 1;
		var incentives = 0; // no incentives as of now
	
		// calculate monthly Lease Payments
		var residualValue = actualMSRP * residualPct;
		var totalGrossCapCost = estLeasePrice + incentives + acquisitionFee;
		var capCostReduction = downPay + tradeIn;
		var adjustedCapCost = totalGrossCapCost - capCostReduction;
		var depreciationPay = (adjustedCapCost - residualValue) / fTerm;
		var monthlyRentCharge = (adjustedCapCost + residualValue) * moneyFactor;
		var monthlyLeasePay = monthlyRentCharge + depreciationPay;
		
		// SA500 Changes - Start
		var acquisition_Fee = acquisitionFee;
		var cap_Cost_Reduction = capCostReduction;
		var adjusted_Cap_Cost = adjustedCapCost;
		var security_dep = roundValTo50(monthlyLeasePay);	
		var first_Inst = parseFloat(monthlyLeasePay);
		var total_Due = acquisitionFee + security_dep + first_Inst + cap_Cost_Reduction;	
		// SA500 Changes - End
	
		// BEGIN ERROR CHECK
		if (estLeasePrice < (actualMSRP * 0.70)){
			errorMsg = "Est. purchase price must be greater than or equal to $" + roundValue(actualMSRP * 0.70) + ". Please re-enter the est. purchase price.";
			errorCheck = true;		
		} 
		else if (estLeasePrice > (actualMSRP * 1.25)) {
			errorMsg = "Est. purchase price must be less than or equal to $" + roundValue(actualMSRP * 1.25) + ". Please re-enter the est. purchase price.";
			errorCheck = true;
		}
		else if (downPay < 0) {
			errorMsg = "Down payment must be greater than or equal to $0. Please re-enter the down payment amount.";
			errorCheck = true;
		}
		else if (downPay > estLeasePrice) {
			errorMsg = "Down payment must be less than or equal to est. purchase price. Please reduce down payment amount.";
			errorCheck = true;
		}
		else if (tradeIn < 0) {
			errorMsg = "Net trade-in value must be greater than or equal to $0. Please re-enter the net trade-in value.";
			errorCheck = true;
		}
		else if (tradeIn > estLeasePrice) {
			errorMsg = "Net trade-in value must be less than or equal to est. purchase price. Please re-enter the net trade-in value.";
			errorCheck = true;
		}
		else if (capCostReduction > (estLeasePrice * 0.29)) {
			errorMsg = "The sum of net trade-in value and down payment must be less than or equal to $" + roundValue(estLeasePrice * 0.29) + ". Please reduce down payment and/or trade-in amount.";
			errorCheck = true;
		}

		else if (adjustedCapCost < residualValue + 100) {
			errorMsg = "The est. purchase price minus the net trade-in value and down payment must be greater than $" + roundValue(residualValue + 100) + ". Please reduce down payment and/or trade-in amount.";
			errorCheck = true;
		}
		// END ERROR CHECK
	
		if (errorCheck) { monthlyLeasePay = -1; }

		return new MonthlyLeasePaymentClass(errorCheck, errorMsg, parseFloat(monthlyLeasePay), adjusted_Cap_Cost, security_dep, first_Inst, acquisition_Fee, cap_Cost_Reduction, total_Due) ;
	}
	
	// Creates structured data for the return value of calculateLease function.
	// It bundles error messaging and lease specific values
	function MonthlyLeasePaymentClass (isErrorBool, errorMsgValue, leasePaymentFloat, adjustedCapCostNumber, securityDepNumber, firstPaymentFloat, acquisitionFeeNumber, capCostReductionNumber, totalDueFloat) {
		var isError = isErrorBool;
		var errorMsg = errorMsgValue;
		var paymentValue = leasePaymentFloat;
		var adjustedCapCost = adjustedCapCostNumber;
		var securityDeposite = securityDepNumber;
		var firstPayment = firstPaymentFloat;
		var acquisitionFee = acquisitionFeeNumber;
		var capCostReduction = capCostReductionNumber;
		var totalDue = totalDueFloat;
		
		this.getIsError = function () { return isError }
		this.getErrorMsg = function () { return errorMsg }
		this.getPaymentValue = function (formatFlag){ if (formatFlag) return convertToDollar(paymentValue); else return paymentValue; }
		this.getAdjustedCapCost = function (formatFlag){ if (formatFlag) return convertToDollar(adjustedCapCost); else return adjustedCapCost; }
		this.getSecurityDeposite = function (formatFlag){ if (formatFlag) return convertToDollar(securityDeposite); else return securityDeposite; }
		this.getFirstPayment = function (formatFlag){ if (formatFlag) return convertToDollar(firstPayment); else return firstPayment; }
		this.getAcquisitionFee = function (formatFlag){ if (formatFlag) return convertToDollar(acquisitionFee); else return acquisitionFee; }
		this.getCapCostReduction = function (formatFlag){ if (formatFlag) return convertToDollar(capCostReduction); else return capCostReduction; }
		this.getTotalDue = function (formatFlag){ if (formatFlag) return convertToDollar(totalDue); else return totalDue; }		
	}
	
	// Validates and calculates loan data.
	// Note: this is primarily legacy code with minor modifications
	function calculateLoan(fLoanPrice,fDownPay,fTradeIn,fRate,intTerm) {
		var cost = fLoanPrice * 1;
		var downPay = fDownPay * 1;
		var tradeIn = fTradeIn * 1;
		var loanRate = fRate * 1;
		var term = intTerm * 1;
		var loanPayment;
	
		var errorMsg;
		var errorCheck = false; // false = no error; true = error
		var errorType = "loan";
	
		// BEGIN ERROR CHECKING
		if (cost <= 0) {
			errorMsg = "Est. purchase price must be greater than $0. Please re-enter the est. purchase price.";
			errorCheck = true;
		}
		else if (downPay < 0) {
			errorMsg = "Down payment must be greater than $0. Please re-enter the down payment amount.";
			errorCheck = true;
		}
		else if (downPay > cost) {
			errorMsg = "Down payment must be less than est. purchase price.  Please reduce down payment amount.";
			errorCheck = true;
		}
		else if (tradeIn < 0) {
			errorMsg = "Net trade-in value must be greater than or equal to $0. Please re-enter the trade-in amount.";
			errorCheck = true;
		}
		else if (tradeIn > cost) {
			errorMsg = "Net trade-in value must be less than est. purchase price.  Please reduce net trade-in value amount.";
			errorCheck = true;
		}
		else if (loanRate < 0) {
			errorMsg = "Interest rate must be greater than or equal to 0.  Please re-enter the Interest Rate.";
			errorCheck = true;
		}
		else if ((tradeIn + downPay) > cost) {
			errorMsg = "Net trade-in value plus down payment must be less than est. purchase price.  Please reduce down payment and/or trade-in amount.";
			errorCheck = true;
		}
		else if ((cost - tradeIn - downPay) < 4000) {
			errorMsg = "Your total finance amount must be greater than $4,000.";
			errorCheck = true;
		}
		// END ERROR CHECKING
	
		// if no errors found, then calculate payment
		if (!errorCheck) {
			var amtFinanced = cost - tradeIn - downPay;
			if (loanRate == 0) {
				loanPayment = amtFinanced / term;
			} else {
				// calculate monthly loan payment
				var a = 1 / (1 + (loanRate/12));			
				var b = a - Math.pow(a,(term + 1));
				loanPayment = amtFinanced * (1 - a) / b;
				
			}
		} else { loanPayment = -1; }
		return new MonthlyLoanPaymentClass(errorCheck, errorMsg, parseFloat(loanPayment));
	}
	
	// Creates structured data for the return value of calculateLoan function.
	// It bundles error messaging and loan specific values
	function MonthlyLoanPaymentClass (isErrorBool, errorMsgValue, loanPaymentFloat) {
		var isError = isErrorBool;
		var errorMsg = errorMsgValue;
		var paymentValue = loanPaymentFloat;
		
		this.getIsError = function () { return isError }
		this.getErrorMsg = function () { return errorMsg }
		this.getPaymentValue = function (formatFlag){ if (formatFlag) return convertToDollar(paymentValue); else return paymentValue; }
	}
	
	
	// LEGACY: Rounds values to 2 decimal places and adds a zero to ensure well rounded cents (ex: $34.80 instead of $34.8)
	function roundValue(number){
	    number = Math.round(number*100)/100;
		return (number == Math.floor(number)) ? number + '.00' : ((number*10 == Math.floor(number*10)) ? number + '0' : number);
	}
	
	// LEGACY: Converts any number ie. 999999 to a dollar value of $999,999 or 999.00 to a dollar value of $999.00.
	function convertToDollar(numValue){
		var signValue = "";
		var intNumberValue = parseFloat(numValue);
		if(intNumberValue < 0) signValue = "-";
		var strNumberValue = roundValue(Math.abs(intNumberValue)) + ' ';
		strNumberValue = strNumberValue.substring(0,strNumberValue.length - 1)
		var numLength = strNumberValue.length;
		if (strNumberValue.length > 6)
			strNumberValue = "$" + strNumberValue.slice(0,numLength-6) + "," + strNumberValue.slice(numLength-6,numLength)
		else
			strNumberValue = "$" + strNumberValue.slice(0,numLength)
		return (signValue + strNumberValue);
	}
	
	// LEGACY: Function added for SA500 - rounds the value to next 50
	function roundValTo50(origNumber)
	{
			var ceilNumber = (Math.ceil(origNumber/100))*100;
			var diff = ceilNumber-origNumber;
			diff = ((diff < 50) ? 0 : (50));
			var updatedNumber = ceilNumber - diff;
			return updatedNumber;
	}
	
	// A helper function that returns a requested property value from a
	// LeaseDataClass object in the leaseDataList array based on the given lease 
	// type and lease term
	function getLeaseDataForTypeAndTerm (leaseTypeValue, leaseTermNumber, propFlag) {
		if ( !hasLeaseData ) return null;
		var foundLeaseItem = null;
		for (var idx in leaseDataList) {
			leaseItem = leaseDataList[idx];
			if (leaseItem.mileageCde == leaseTypeValue && leaseItem.term == leaseTermNumber) {
				foundLeaseItem = leaseItem;
				break;
			}
		}
		switch (propFlag){
			case 'moneyFactor':
				return foundLeaseItem.moneyFactor;
			case 'residualPct':
				return foundLeaseItem.residualPct;
			case 'acquisitionFeeAmt':
				return foundLeaseItem.acquisitionFeeAmt;
			default: 
				return foundLeaseItem;
		}
	}
	
	// Helper function to determin if lease data was passed is
	function checkHasLeaseData( leaseDataList ) {
		if ( typeof(leaseDataList) == 'undefined' || !leaseDataList || leaseDataList.length <= 0 )
			return false;
		return true;
	}
	
//	### PUBLIC ###
	this.getModelYear = function () { return modelYear }
	this.setModelYear = function (value) { modelYear = value; }
	
	this.getBaseMSRP = function (formatFlag) { if (formatFlag) return convertToDollar(baseMSRP); else return baseMSRP; }
	this.setBaseMSRP = function (value) { baseMSRP = value; }
	
	this.getDestinationFee = function (formatFlag){ if (formatFlag) return convertToDollar(destinationFee); else return destinationFee; }
	this.setDestinationFee = function (value) { destinationFee = value; }
	
	this.getEstimatedSellingPrice = function (formatFlag) { if (formatFlag) return convertToDollar(baseMSRP+destinationFee); else return (baseMSRP+destinationFee); }
	
	this.getLeaseDataList = function (){ return leaseDataList; }
	
	this.getLoanDataObj = function () { return loanData; }
	
	this.getLeaseDataObj = function () { return leaseData; }
	
	this.getHasLeaseData = function () { return hasLeaseData; }
}