//Within this file lives the constructor, the calculate, and the accessor
//methods for AmortScheduleCalculator

//Define Global Variables
var MAX_TERM = new Number(360);
var COLUMN_DELIMITER = "\t";
var ROW_DELIMITER = "\r\n";
var HEADER= "paymentNumber" + COLUMN_DELIMITER + "month" + COLUMN_DELIMITER +
 "year" + COLUMN_DELIMITER + "principal" + COLUMN_DELIMITER +
 "interest" + COLUMN_DELIMITER + "beginningBalance" + COLUMN_DELIMITER +
 "endingBalance" + COLUMN_DELIMITER + "rate" + COLUMN_DELIMITER +
 "prepaidPrincipal" + COLUMN_DELIMITER + "prepaidInterest" + COLUMN_DELIMITER +
 "prepaidBeginBalance" + COLUMN_DELIMITER + "prepaidEndBalance" + COLUMN_DELIMITER +
 "taxSavings" + COLUMN_DELIMITER + "PMI" + ROW_DELIMITER;



//accessor methods for the AmortScheduleCalculator

//accessor method for Index Range
function checkIndexRange(index)
{
 if (index > (this.payCount-1))
 {
 return false;
 }
 else
 {
 return true;
 }
}

//accessor method for payCount
function getPaymentCount()
{
 return (this.payCount);
}

//accessor method for month
function getMonth(index)
{
 if(this.checkIndexRange(index))
 {
 return (month[index]);
 }
 else return 0;
}

//accessor method for year
function getYear(index)
{
 if(this.checkIndexRange(index))
 {
 return (year[index]);
 }
 else return 0;
}

//accessor method for principal
function getPrincipal(index)
{
 if(this.checkIndexRange(index))
 {
 return (principal[index]);
 }
 else return 0;
}

//accessor method for interest
function getInterest(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.interest[index]);
 }
 else return 0;
}

//accessor method for interestRate
function getInterestRate(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.interestRate[index]);
 }
 else return 0;
}

//accessor method for Beginning Balance
function getBeginningBalance(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.beginningBalance[index]);
 }
 else return 0;
}

//accessor method for Ending Balance
function getEndingBalance(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.endingBalance[index]);
 }
 else return 0;
}

//accessor method for prepaidPrincipal
function getPrepaidPrincipal(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.prepaidPrincipal[index]);
 }
 else return 0;
}

//accessor method for prepaidInterest
function getPrepaidInterest(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.prepaidInterest[index]);
 }
 else return 0;
}

//accessor method for prepaidBeginBalance
function getPrepaidBeginBalance(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.prepaidBeginBalance[index]);
 }
 else return 0;
}

//accessor method for prepaidEndBalance
function getPrepaidEndBalance(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.prepaidEndBalance[index]);
 }
 else return 0;
}

//accessor method for totalNormalPrincipal
function getTotalNormalPrincipal()
{
 return (this.totalNormalPrincipal);
}

//accessor method for totalNormalInterest
function getTotalNormalInterest()
{
 return (this.totalNormalInterest);
}

//accessor method for taxSavings
function getTaxSavings(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.taxSavings[index]);
 }
 else return 0;
}

//accessor method for totalOwnershipSavings
function getTotalOwnershipSavings()
{
 return (this.totalOwnershipSavings);
}

//accessor method for totalPMI
function getTotalPMI()
{
 return (this.totalPMI);
}

//accessor method for monthlyPayment
function getMonthlyPayments()
{
 return (this.monthlyPayment);
}

//accessor method for totalTaxSavings
function getTotalTaxSavings()
{
 return (this.totalTaxSavings);
}

//accessor method for totalPrepaidSavings
function getTotalPrepaidSavings()
{
 return (this.totalPrepaidSavings);
}

//accessor method for PMI
function getPMI(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.PMI[index]);
 }
 else return 0;
}

//accessor method for paymentNumber
function getPaymentNumber(index)
{
 if(this.checkIndexRange(index))
 {
 return (this.paymentNumber[index]);
 }
 else return 0;
}

//accessor method for HEADER
function getHeader()
{
 return HEADER;
}

//accessor method for Schedule
function getSchedule()
{
 var tempBuffer = "";
 var i = 0;

 for (i = 0; i < payCount; i++)
 {
 tempBuffer += (this.paymentNumber[i] + COLUMN_DELIMITER +
 this.month[i] + COLUMN_DELIMITER +
 this.year[i] + COLUMN_DELIMITER +
 this.principal[i] + COLUMN_DELIMITER +
 this.interest[i] + COLUMN_DELIMITER +
 this.beginningBalance[i] + COLUMN_DELIMITER +
 this.endingBalance[i] + COLUMN_DELIMITER +
 this.interestRate[i] + COLUMN_DELIMITER +
 this.prepaidPrincipal[i] + COLUMN_DELIMITER +
 this.prepaidInterest[i] + COLUMN_DELIMITER +
 this.prepaidBeginBalance[i] + COLUMN_DELIMITER +
 this.prepaidEndBalance[i] + COLUMN_DELIMITER +
 this.taxSavings[i] + COLUMN_DELIMITER +
 this.PMI[i] + COLUMN_DELIMITER);

 tempBuffer += ROW_DELIMITER;
 }

 return tempBuffer;
}

//this method is the new AmortScheduleCalculator object constructor
function AmortScheduleCalculator()
{
 //Arrays
 this.paymentNumber = new Array();
 this.month = new Array();
 this.year = new Array();
 this.principal = new Array();
 this.interest = new Array();
 this.beginningBalance = new Array();
 this.endingBalance = new Array();
 this.interestRate = new Array();
 this.prepaidPrincipal = new Array();
 this.prepaidInterest = new Array();
 this.prepaidBeginBalance = new Array();
 this.prepaidEndBalance = new Array();
 this.taxSavings = new Array();
 this.PMI = new Array();
 this.monthlyPayment = new Array();

 //Numbers
 this.payCount = new Number();
 this.totalTaxSavings = new Number();
 this.totalNormalPrincipal = new Number();
 this.totalNormalInterest = new Number();
 this.totalPMI = new Number();
 this.totalPrepaidSavings = new Number();

 //ID
 this.className = "AmortScheduleCalculator";

 //Accessor Methods
 this.checkIndexRange = checkIndexRange;
 this.getPaymentCount = getPaymentCount;
 this.getMonth = getMonth;
 this.getYear = getYear;
 this.getPrincipal = getPrincipal;
 this.getInterest = getInterest;
 this.getInterestRate = getInterestRate;
 this.getBeginningBalance = getBeginningBalance;
 this.getEndingBalance = getEndingBalance;
 this.getPrepaidPrincipal = getPrepaidPrincipal;
 this.getPrepaidInterest = getPrepaidInterest;
 this.getPrepaidBeginBalance = getPrepaidBeginBalance;
 this.getPrepaidEndBalance = getPrepaidEndBalance;
 this.getTotalNormalPrincipal = getTotalNormalPrincipal;
 this.getTotalNormalInterest = getTotalNormalInterest;
 this.getTaxSavings = getTaxSavings;
 this.getTotalOwnershipSavings = getTotalOwnershipSavings;
 this.getTotalPMI = getTotalPMI;
 this.getMonthlyPayments = getMonthlyPayments;
 this.getTotalTaxSavings = getTotalTaxSavings;
 this.getTotalPrepaidSavings = getTotalPrepaidSavings;
 this.getPMI = getPMI;
 this.getPaymentNumber = getPaymentNumber;
 this.getHeader = getHeader;
 this.getSchedule = getSchedule;
 this.calculate = AmortScheduleCalculatorCalculate;

 return this;
}

function getARMPayments(totalLoanAmt, initialRate, loanTerm, firstTerm, recurringTerm, rateCap1, rateCap2, marginRate, indexRate, payments, rates)
{
 //Declare Local Variables
 var currentChange = new Number(0);
 var currentPeriod = new Number(0);
 var remainingTerm = new Number(0);
 var totalChanges = new Number(0);
 var remainingBalance = new Number(0);
 var monthlyPI = new Nnmber(0);
 var monthlyRate = new Number(0);
 var rateCap = new Number(0);

 monthlyRate = initialRate/12;
 remainingBalance = totalLoanAmt;

 monthlyPI = getMonthlyPayment(loanTerm,initialRate,remainingBalance);

 var li = 0;

 // First set of payments
 for(li = 0; li < firstTerm; li++)
 {
 payments[li] = monthlyPI;
 rates[li] = monthlyRate;
 remainingBalance = remainingBalance - (monthlyPI-((monthlyRate)* remainingBalance));
 }

 // Make adjustment for every subsequent change

 remainingTerm = loanTerm - firstTerm;
 totalChanges = remainingTerm / recurringTerm;
 currentPeriod = firstTerm - 1;

 // Determine remaining payments
 for(currentChange=0; currentChange < totalChanges; currentChange++)
 {
 if (currentChange == 0 )
 {
 rateCap = rateCap1;
 }
 else
 {
 rateCap = rateCap2;
 }

 monthlyRate = (monthlyRate * 12 + rateCap) / 12 ;

 // Cannot exceed the index + margin
 if (monthlyRate > ( indexRate + marginRate ) / 12 )
 {
 monthlyRate = ( indexRate + marginRate ) / 12;
 }

 // Call the external function
 remainingTerm = loanTerm - currentPeriod - 1;

 monthlyPI = getMonthlyPayment(remainingTerm, monthlyRate*1200, remainingBalance);

 // Second set of payments
 for (li=0; li < recurringTerm; li++)
 {
 currentPeriod = currentPeriod + 1;
 payments[fisrtTerm + li] = monthlyPI;
 rates[firstTerm = li] = monthlyRate;
 remainingBalance = remainingBalance - (monthlyPI-((monthlyRate)*remainingBalance));

 if((remainingBalance < 0)||(remainingBalance == 0))
 {
 remainingBalance = 0;
 monthlyPI = 0;
 }
 }
 }
}


//this method is the transliteration of the AmortScheduleCalculator calculate method
function AmortScheduleCalculatorCalculate(totalLoanAmt, propertyValue, startingInterestRate, startingMonth, startingYear, periodStart, periodEnd, monthlyPrepaidAmt, yearlyPrepaidAmt, lumpSumPrepaidAmt, lumpSumPrepaidMonth, federalTaxRate, monthlyMI, isARM, scheduleTerm, actualTerm, firstTerm, recurringTerm, rateCap1, rateCap2, marginRate, indexRate)
{

 //Declare local variables
 var payCounter = new Number(0);
 var hasPMI = false;
 var prepaying = false;
 var normalBeginningBalance = new Number(0.0);
 var prepaidBeginningBalance = new Number(0.0);
 var normalEndingBalance = new Number(0.0);
 var prepaidEndingBalance = new Number(0.0);
 var normalInterest = new Number(0.0);
 var prepaidInterest = new Number(0.0);
 var normalPrincipal = new Number(0.0);
 var prepaidPrincipal = new Number(0.0);
 var normalPI = new Number(0.0);
 var monthlyPI = new Number(0.0);
 var monthlyPMI = new Number(0.0);
 var currMonthPMI = new Number(0.0);
 var LTV = new Number(0.0);
 var monthlyRate = new Number(0.0);
 var taxSavings = new Number(0.0);
 var tempMonthlyRate = new Number(0.0);
 var currentMonth = new Number(startingMonth);
 var currentYear = new Number(startingYear);
 var className = "AmortScheduleCalculator";

 var payments = new Array();
 var rates = new Array();

 var amortSchedule = new AmortScheduleCalculator();

 var LTV = new Number (0.0);
 var monthlyRate = new Number (0.0);
 var taxSavings = new Number(0.0);
 var tempMonthlyRate = new Number(0.0);
 var paymentNumber = new Number();

 var payments = new Array();
 var rates = new Array();

 var today = new Date();


 if (actualTerm == 0)
 {
 actualTerm = scheduleTerm;
 }

 //Automatically correct the ending month if it is calculated to be greater than the loan term
 if ((periodEnd > 0) && (periodEnd > actualTerm))
 {
 periodEnd = actualTerm;
 }

 //Check for prepay information
 prepaying = (lumpSumPrepaidAmt + yearlyPrepaidAmt + monthlyPrepaidAmt) > 0;

 //DETERMINE THE MONTHLY P&I PAYMENTS
 monthlyRate = (startingInterestRate / 12);

 //Check for an Adjustable Program
 if (isARM)
 {
 getARMPayments(totalLoanAmt,startingInterestRate, scheduleTerm,firstTerm,recurringTerm,rateCap1,rateCap2,marginRate,indexRate,payments,rates);
 }
 else
 {
 //It is a fixed interestRate
 //Get the fixed monthly payments
 monthlyPI = getMonthlyPayment(scheduleTerm, startingInterestRate, totalLoanAmt);
 }

 //Loop through each payment to create the AmortScheduleCalculator
 for (paymentNumber = 1; ((paymentNumber < actualTerm)||(paymentNumber == actualTerm)); paymentNumber++)
 {
 if (paymentNumber == 1)
 {
 normalBeginningBalance = totalLoanAmt;
 prepaidBeginningBalance = totalLoanAmt;

 //If we have a propertyValue add PMI to the monthly payment
 if ((propertyValue > 0) && (totalLoanAmt > 0) && (monthlyMI > 0))
 {
 //Only calculate PMI if we get a propertyValue and PMI
 LTV = totalLoanAmt / propertyValue;
 currMonthPMI = (LTV > 0.80)?monthlyMI:0.0;
 }

 if (currentMonth == 0)
 {
 // Get the current month
 currentMonth = today.getMonth() + 1;
 }

 if (currentYear == 0)
 {
 // Get the current year
 currentYear = today.getFullYear;
 }
 }
 else
 {
 normalBeginningBalance = normalEndingBalance;
 prepaidBeginningBalance = prepaidEndingBalance;

 if ((propertyValue > 0) && (normalBeginningBalance > 0) && (monthlyMI > 0))
 {
 //Only calculate PMI if we get a propertyValue
 LTV = normalBeginningBalance / propertyValue;
 currMonthPMI = (LTV > 0.80)?monthlyMI:0.0;
 }

 currentMonth++;

 if (currentMonth > 12)
 {
 currentMonth = 1;
 currentYear++;
 }
 }

 //Check for fixed or variable
 if (monthlyPI > 0 || (payments.length == 0))
 {
 normalPI = monthlyPI;
 tempMonthlyRate = monthlyRate;
 }
 else
 {
 normalPI = payments[paymentNumber-1];
 tempMonthlyRate = rates[paymentNumber-1];
 }

 if (Math.round(normalBeginningBalance) == 0)
 {
 normalInterest = 0;
 normalPrincipal = 0;
 }
 else
 {
 normalInterest = normalBeginningBalance * tempMonthlyRate;
 normalPrincipal = normalPI - normalInterest;
 //Start calculating tax savings per month
 if (federalTaxRate > 0)
 {
 taxSavings = normalInterest * federalTaxRate;
 }

 if (Math.round(prepaidBeginningBalance) == 0 )
 {
 prepaidInterest = 0;
 prepaidPrincipal = 0;
 }
 else
 {
 prepaidInterest = prepaidBeginningBalance * tempMonthlyRate;

 //Add any monthly Prepayment
 prepaidPrincipal = normalPI + monthlyPrepaidAmt - prepaidInterest;

 //Add any yearly Prepayment
 if (yearlyPrepaidAmt > 0 && paymentNumber % 12 == 0)
 {
 prepaidPrincipal = prepaidPrincipal + yearlyPrepaidAmt;
 }

 //Add any Lump Sum Payment
 if (lumpSumPrepaidMonth == paymentNumber)
 {
 prepaidPrincipal = prepaidPrincipal + lumpSumPrepaidAmt;
 }

 // Make sure we stop after the loan has been paid off
 if (prepaidPrincipal > prepaidBeginningBalance)
 {
 prepaidPrincipal = prepaidBeginningBalance;
 }
 }
 }

 normalEndingBalance = normalBeginningBalance - normalPrincipal;
 prepaidEndingBalance = prepaidBeginningBalance - prepaidPrincipal;

 if (Math.round(normalEndingBalance) == 0 )
 {
 normalEndingBalance = 0;
 }

 if (Math.round(prepaidEndingBalance) == 0 )
 {
 prepaidEndingBalance = 0;
 }

 if (!prepaying)
 {
 prepaidPrincipal = 0;
 prepaidInterest = 0;
 prepaidBeginningBalance = 0;
 prepaidEndingBalance = 0;
 }

 //Only send back result set requested by user
 if ((paymentNumber < periodStart) || (paymentNumber > periodEnd))
 {
 continue;
 }
 else
 {
 //Build an object of named arrays as the result
 amortSchedule.paymentNumber[payCounter] = paymentNumber;
 amortSchedule.month[payCounter] = currentMonth;
 amortSchedule.year[payCounter] = currentYear;
 amortSchedule.principal[payCounter] = normalPrincipal;
 amortSchedule.interest[payCounter] = normalInterest;
 amortSchedule.beginningBalance[payCounter] = normalBeginningBalance;
 amortSchedule.endingBalance[payCounter] = normalEndingBalance;
 amortSchedule.interestRate[payCounter] = tempMonthlyRate * 12;
 amortSchedule.prepaidPrincipal[payCounter] = prepaidPrincipal;
 amortSchedule.prepaidInterest[payCounter] = prepaidInterest;
 amortSchedule.prepaidBeginBalance[payCounter] = prepaidBeginningBalance;
 amortSchedule.prepaidEndBalance[payCounter] = prepaidEndingBalance;
 amortSchedule.taxSavings[payCounter] = taxSavings;
 amortSchedule.PMI[payCounter] = currMonthPMI;
 amortSchedule.monthlyPayment[payCounter] = normalPrincipal + normalInterest + currMonthPMI;

 amortSchedule.payCount = ++payCounter;
 amortSchedule.totalTaxSavings += taxSavings;
 amortSchedule.totalNormalPrincipal += normalPrincipal;
 amortSchedule.totalNormalInterest += normalInterest;
 amortSchedule.totalPMI += currMonthPMI;
 amortSchedule.totalPrepaidSavings += (normalPrincipal + normalInterest) - (prepaidPrincipal + prepaidInterest);
 }
 }

 return amortSchedule;
}
