//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;        
}

