function PlusStaffordAmortize(principle, interest, length) {

  this.principle=principle;
  this.newPrinciple=principle;
  this.interest=interest;
  this.length=length;
  this.earlyRateDiscount= 0;
  this.earlyDuration= 0;
  this.lateRateDiscount= 0;
  this.totIntPaid= 0;
  this.totPrinPaid= 0;
  this.reducedPrinciple;
  this.setEarlyRate = false;
  this.setLateRate = false;
  this.newPrinciple;
     
  this.monthlyPayment;

  this.totIntPaid;
  this.totPrinPaid;
    
  this.paymentSchedule = new Array();
  this.payments = new Array();

  this.presetPaymentNumber = 0;
  this.currentPaymentNumber = 0;
 this.getMonthlyPayment = Amortize_getMonthlyPayment;
  this.setMonthlyPayment = Amortize_setMonthlyPayment;
  this.doPaymentSchedule  = Amortize_doPaymentSchedule;

  this.runAmort  = Amortize_runAmort;

  this.setInterestDiscount  = Amortize_setInterestDiscount;

  this.computeInterestOnly  = Amortize_computeInterestOnly;
  this.amortizeDifferentPrinciple  = Amortize_amortizeDifferentPrinciple;
  this.setEarlyRateDiscount  = Amortize_setEarlyRateDiscount;
  this.getEarlyRateDiscount  = Amortize_getEarlyRateDiscount;
  this.setLateRateDiscount  = Amortize_setLateRateDiscount;

  this.getLateRateDiscount  = Amortize_getLateRateDiscount;

  this.getEarlyDuration  = Amortize_getEarlyDuration;
  this.setEarlyDuration  = Amortize_setEarlyDuration;
  this.getPrinciple = Amortize_getPrinciple;
  this.setPrinciple  = Amortize_setPrinciple;
  this.setNewPrinciple  = Amortize_setNewPrinciple;
  this.getNewPrinciple  = Amortize_getNewPrinciple;
  this.getInterest  = Amortize_getInterest;
  this.setInterest  = Amortize_setInterest;

  this.getLength  = Amortize_getLength;
  this.setLength  = Amortize_setLength;
  this.getDblLength  = Amortize_getDblLength;
  this.setTotalInterestPaid  = Amortize_setTotalInterestPaid ;
  this.getTotalInterestPaid  = Amortize_getTotalInterestPaid;
  this.setTotalPrinciplePaid  = Amortize_setTotalPrinciplePaid;
  this.getTotalPrinciplePaid  = Amortize_getTotalPrinciplePaid;
  this.setPaymentSchedule  = Amortize_setPaymentSchedule;
  this.getPaymentSchedule  = Amortize_getPaymentSchedule;
  this.setPayments  = Amortize_setPayments;
  this.getPayments  = Amortize_getPayments;
  this.setPresetPaymentNumber  = Amortize_setPresetPaymentNumber;
  this.getPresetPaymentNumber  = Amortize_getPresetPaymentNumber;
  this.setCurrentPaymentNumber  = Amortize_setCurrentPaymentNumber;
  this.getCurrentPaymentNumber  =  Amortize_getCurrentPaymentNumber;
  this.setReducedPrinciple  =  Amortize_setReducedPrinciple;
  this.getReducedPrinciple  =  Amortize_getReducedPrinciple;
  this.getCurrentInterest  = Amortize_getCurrentInterest;


  //THESE MUST COME AFTER THEIR RESPECTIVE 'METHOD DECLARATIONS'. 
  // this.initNumberFormat(); //for creator()
  this.setMonthlyPayment(); //for creator()
 

}

function setScale(myFloat,scale){
  FloatVal = (Math.round(myFloat * Math.pow(10,scale))/Math.pow(10,scale)); 

  return parseFloat(FloatVal);
}

function Amortize_getMonthlyPayment() {
  return this.monthlyPayment;
}

function Amortize_setMonthlyPayment(monthlyPayment)
{
  if (!monthlyPayment) {
  var J = this.getInterest() / (12 * 100);
  this.monthlyPayment  = setScale(this.getPrinciple() * ( J / ( 1 - Math.pow((1 + J),- (this.getLength() * 12)) ) ),2);
  }
  else {
    this.monthlyPayment = monthlyPayment;
  }
}


function Amortize_doPaymentSchedule()
{
  this.runAmort((this.length * 12));
}

function Amortize_runAmort( periods) {
  // System.out.println("runAmort periods: " + periods);

  var thePayment ;
  var paymentNumber;
  var  interestPayment;
  var  principlePayment;
  var principleBalance;
  var  newPrinciple;
  var  totPrinPayments = 0;
  var  totIntPayments=0;
  var  payments = new Array();
    

  var i = 0;
  for (; i < periods; i++)
    {
   
      if (this.getPrinciple()> 0 )
        {
          thePayment = new PlusStaffordPayment();

//           thePayment.setFullPayment(this.monthlyPayment);

          this.setCurrentPaymentNumber(this.getCurrentPaymentNumber() +1 );
           thePayment.setPaymentNumber(this.getCurrentPaymentNumber());
//           thePayment.setBeginningBalance(this.getNewPrinciple());

  
           thePayment.setInterestRate(this.getInterest());
	   thePayment.setBeginningBalance(this.getNewPrinciple());

	   thePayment.setFullPayment(this.monthlyPayment);
	   this.setInterestDiscount();

//           // This is always based on current principle
           thePayment.setInterestPayment( thePayment.getBeginningBalance() * (thePayment.getInterestRate() /1200));
    
           totIntPayments += thePayment.getInterestPayment();

           // Have to check if we are on the last payment so we don't report an overpay
           if ( (thePayment.getFullPayment() - thePayment.getInterestPayment()) > thePayment.getBeginningBalance())
	    {
	      // System.out.println(i + ": Last principle payment. Period" + i);
 	      thePayment.setPrinciplePayment(thePayment.getBeginningBalance());

 	      // something is wrong here....  //evidently Brandan didn't know what was wrong
 	      thePayment.setEndingBalance(0);
	      totPrinPayments = totPrinPayments + thePayment.getPrinciplePayment();

// 	      // and here...
	      this.setNewPrinciple(thePayment.getEndingBalance());
 	      payments[payments.length] = thePayment;
           
 	      break;
 	    } else {
             thePayment.setPrinciplePayment( thePayment.getFullPayment() - thePayment.getInterestPayment());
             thePayment.setEndingBalance( thePayment.getBeginningBalance() - thePayment.getPrinciplePayment());
           }

          totPrinPayments +=  thePayment.getPrinciplePayment();
           // System.out.println("Prin payment " + i + ": " + thePayment.getPrinciplePayment());
          this.setNewPrinciple(thePayment.getEndingBalance());
          payments[payments.length] = thePayment;

//           // occasionally, there are a few cents left over after the last payment.  If that is the case, then go ahead and give it one more.

//           /**
//            * Per Dave Rose, we'll eliminate this, and calculate total cost as
//            *
//            *   user entered principle + calculated interest
//            *
//            * As opposed to:
//            *   calculated paid principle + calculated interest
//            *
//            * If the situation comes up where one last payment of a few cents
//            * must be calculated, please un comment this section.
//            *
// 	   if (thePayment.getFullPayment() > thePayment.getEndingBalance()) {
// 	   i--;
// 	   }
// 	   *
// 	   **/

	}
    }

//   // System.out.println("Remaining Balance: " + thePayment.getEndingBalance());
   this.setTotalInterestPaid(totIntPayments);
   this.setTotalPrinciplePaid(totPrinPayments);
   // System.out.println("Payments size: " + payments.size());
   this.setPayments(payments);
   this.setLength(i);
//   // System.out.println("Returing from runAmort.");
}

/***
 * Calculates the discount to the interst rate, based on the ACH rate, loan amount, and payment number.
 *
 *
 */

function Amortize_setInterestDiscount() {
    
  if (this.getEarlyRateDiscount() > 0  && (this.getCurrentPaymentNumber() <= this.getEarlyDuration() || this.getPresetPaymentNumber() >= this.getEarlyDuration() ) && !this.setEarlyRate) {
      
    this.setInterest(this.getInterest() - this.getEarlyRateDiscount());
    this.setEarlyRate = true;
      
  }

  if (this.getLateRateDiscount() > 0 && getCurrentPaymentNumber() > this.getEarlyDuration() && !this.setLateRate) {
      
    this.setInterest(this.getInterest() - this.getLateRateDiscount());
    this.setLateRate = true;
     
  }
     
}


function Amortize_computeInterestOnly( periods) {

  // first, figure out the full interest payment on the beginning principle.
  var fullPayment = this.getPrinciple() * this.getInterest() /(12 * 100);
    
  // declare this up here to save memory.
  var currentInterest =0;
  var  currentPrinciple = 0;
    
  var  totInterestPayments = 0;
  var  totPrinciplePayments = 0;
    
  var period = 0;
    
  // loop thru the payments
  for (; period < periods; period++) {
      
    // compute discount interest on the remaining principle.
      
    // System.out.println("Setting payment number");
    this.setCurrentPaymentNumber(this.getCurrentPaymentNumber() + 1);
      
    // System.out.println("Setting interest discount.");
    this.setInterestDiscount();
      
    // System.out.println("Set interest discount.");
      
    // subtract this from full payment.
    currentInterest = this.getCurrentInterest();

    // add the interst paid to total interest.
    totInterestPayments = totInterestPayments + currentInterest;

    // subtract this from principle, and set principle to this new amount.
    currentPrinciple = fullPayment - currentInterest;

    // System.out.println("Subtracted current principle: " + currentPrinciple);

    // Reducing initial principle doesn't really buy us anything.  We need to reduce new principle.
    this.newPrinciple = this.newPrinciple - currentPrinciple ;

    totPrinciplePayments = totPrinciplePayments + currentPrinciple;

  }

  // Add a payment so that we can send this info back to the calling class.
//   var  cp = new ComplexPayment();
//   cp.setFullPayment(fullPayment);
//   var payments = new Array();
//   payments[payments.length] = cp;
//   this.setPayments(payments);

  // System.out.println("Finished loop.  Total interest: " + totInterestPayments + " Principle: " + totPrinciplePayments + " period: " + period);
  // set these variables to be retrieved.
  this.setTotalInterestPaid(totInterestPayments);
  this.setTotalPrinciplePaid(totPrinciplePayments);
  this.setLength(period);

}


//  public void amortizeDifferentPrinciple( reduced) {
//    amortizeDifferentPrinciple(reduced, getLength());
//  }


/**
 * Computes payments with a different principle.
 *
 * When called directly, this should be an intra-loan amortization.
 *
 * Huge candidate for refactoring with computeInterestOnly()
 *
 * @param periods
 */

function Amortize_amortizeDifferentPrinciple( reduced,  periods) {
  // first, figure out the full interest payment on the beginning principle.
  //     double fullPayment = getPrinciple() * getInterest() / (12 * 100);
  //     reducedPrinciple = reduced;
  if (!periods) { periods = this.getLength() * 12; } //poor-man's polymorphism 

  var fullPayment = this.monthlyPayment;

  // declare this up here to save memory. //Whatever Brandan
  var currentInterest = parseFloat("0.0");
  var currentPrinciple =  parseFloat("0.0");

  var totInterestPayments = parseFloat("0.0");
  var totPrinciplePayments = parseFloat("0.0");

  var period = 0;

  // loop thru the payments
  for (; period < periods; period++) {
    
    // compute discount interest on the remaining principle.

    this.setCurrentPaymentNumber(this.getCurrentPaymentNumber() + 1);

    this.setInterestDiscount();

    // subtract this from full payment.
     
    currentInterest = (this.getInterest() / (12 * 100)) * reduced;
    // special case for last payment.
    if (fullPayment >= (currentInterest + reduced)) {
      // System.out.println("Amortize DP if.  reduced: " + reduced);
      totPrinciplePayments = totPrinciplePayments + reduced;
      newPrinciple = newPrinciple - reduced;
      reduced = parseFloat("0.00");
      totInterestPayments = totInterestPayments + currentInterest;
      break;
    }

    // add the interst paid to total interest.
    totInterestPayments = totInterestPayments + currentInterest;

    // subtract this from principle, and set principle to this new amount.
    currentPrinciple = fullPayment - currentInterest;

    // decrease the 'running' principle.
    //      principle -= currentPrinciple;
    reduced = reduced - currentPrinciple;

    // Reducing initial principle doesn't really buy us anything.  We need to reduce new principle.
    this.newPrinciple = this.newPrinciple - currentPrinciple;

    totPrinciplePayments = totPrinciplePayments + currentPrinciple;

    // System.out.println(period + " adp: prin pmt: " + currentPrinciple + " new balance: " + reduced + " interest pmt: " + currentInterest);

    // Add a payment so that we can send this info back to the calling class.
  //   var cp = new ComplexPayment();
//     cp.setFullPayment(fullPayment);
//     var  payments = new Array();
//     payments[payments.length] = cp;
//     this.setPayments(payments);


  }

  // set these variables to be retrieved.
  this.setTotalInterestPaid(totInterestPayments);
  this.setTotalPrinciplePaid(totPrinciplePayments);
  this.setLength(period);
  this.setReducedPrinciple(reduced);
  

}



function Amortize_setEarlyRateDiscount ( earlyRateDiscount)
{
  this.earlyRateDiscount=earlyRateDiscount;
}

function Amortize_getEarlyRateDiscount ()
{
  return this.earlyRateDiscount;
}

function Amortize_setLateRateDiscount (lateRateDiscount)
{
  this.lateRateDiscount=lateRateDiscount;
}

function Amortize_getLateRateDiscount ()
{
  return this.lateRateDiscount;
}

function Amortize_getEarlyDuration()
{
  return this.earlyDuration;
}

function Amortize_setEarlyDuration( earlyDuration)
{
  this.earlyDuration = earlyDuration;
}

function Amortize_setPrinciple ( principle)
{
  this.principle=principle;
}

function Amortize_getPrinciple ()
{
  return this.principle;
}

function Amortize_setNewPrinciple (  principle)
{
  this.newPrinciple = principle;
}

function Amortize_getNewPrinciple ()
{
  return this.newPrinciple;
}

function Amortize_getInterest ()
{
  return this.interest;
}

function Amortize_setInterest ( interest)
{
  this.interest = interest;
}

function Amortize_getLength ()
{
  return  this.length;
}

function Amortize_setLength (length)
{
  this.length=length;
}

function Amortize_getDblLength ()
{
  return this.length;
}

function Amortize_setTotalInterestPaid ( intPaid)
{
  this.totIntPaid=intPaid;
}

function Amortize_getTotalInterestPaid ()
{
  return this.totIntPaid;
}

function Amortize_setTotalPrinciplePaid ( prinPaid)
{
  this.totPrinPaid=prinPaid;
}

function Amortize_getTotalPrinciplePaid ()
{
  return this.totPrinPaid;
}

function Amortize_setPaymentSchedule ( schedule)
{
  this.paymentSchedule=schedule;
}

function Amortize_getPaymentSchedule ()
{
  return this.paymentSchedule;
}

function Amortize_setPayments(payments)
{
  // System.out.println("In setPayments()");
  this.payments = payments;
}

function Amortize_getPayments()
{
  // System.out.println("In getPayments()");
  return this.payments;
}

function Amortize_setPresetPaymentNumber( presetPaymentNumber) {
  this.presetPaymentNumber = presetPaymentNumber;
  setCurrentPaymentNumber(presetPaymentNumber);
}

function Amortize_getPresetPaymentNumber() {
  return this.presetPaymentNumber;
}

function Amortize_setCurrentPaymentNumber( currentPaymentNumber) {
  this.currentPaymentNumber = currentPaymentNumber;
}

function Amortize_getCurrentPaymentNumber() {
  return this.currentPaymentNumber;
}

function Amortize_setReducedPrinciple( reducedPrinciple) {
  this.reducedPrinciple = reducedPrinciple;
}

function Amortize_getReducedPrinciple() {
  return this.reducedPrinciple;
}

/**
 * A simple consolidation of a frequently used line.
 *
 */
function Amortize_getCurrentInterest() {
  return (this.getInterest() / (12 * 100) * this.getNewPrinciple());
}
