//
// JavaScript: loanCal.js
//
// Programmer: T-K Andy Lau     NOAA/PMEL/OERD HMSC Newport, Oregon 97365
//    Revised: March  15, 1998  Add pay to princpical feature.
//    Revised: August 26, 1997  Date: August 15, 1997
//

// The functions below will be calling the function IsNumeric()
// to verify the input is a Numerical value.
// IsNumeric() is saved in the file: IsNumeric.js

//
// Thses functions will calculate a loan and interest payments.
//
// Their Inputs:
// loan          = Amount of the loan in dollers.
// interest_rate = annual interest rate, e.g. 8.34%.
// n_payaments   = number of payments, e.g. 30 years x 12 = 360 payments.
// payament      = Amount of each payament in dollers.
//

//
// Callers: HTML FORM
//
function AmortizationTableOnOff( form )
{
  // Compute the Amortization Table if it is asked for.

  if ( form.ComputeTable.selectedIndex == 0 ) {  // Compute table is Off.
     form.AmortizationTable.value =    "";       // Clean the table.
  } else {                        // Compute table is On.
     doLoanCalculations( form );  // & the Amortization Table.
  }

} // End of AmortizationTableOnOff().

//
// This function will compute the Monthly Payment & Additional Payment
// when a total number of payments is given from input area (8) which
// is different than the input area (4) ( mostly  (8) < (4),
// i.e., pay off the loan sooner ).  After the Monthly & Additional
// Payments are calculated, The all new information for the form
// will be updated.
//
// Callers: HTML FORM
//
function CalculatePayment( form )
{
  // Get the parameters.

  var loan           = parseFloat( form.LoanAmount.value );
  var interest_rate  = parseFloat( form.InterestRate.value );
  var payment        = parseFloat( form.Payment.value );
  var pay2principal  = parseFloat( form.Pay2Principal.value );
  var n_payments     = parseFloat( form.TotalNPayments.value );
  var payments_in1yr = parseFloat( form.PaymentsPerYear.value );

  if ( n_payments < 0 ) {
     alert( "Input value for option (8) must be > 0 and\n"
          + "should be < the Number of Payment in input area (4)!" );
     return;
  }

  interest_rate /= payments_in1yr;

  payment = ComputePayment( loan, interest_rate, n_payments );

  // Compute and Update information.

  form.MonthlyPayment.value = payment;  // for areas (7).
  form.Pay2Principal.value  = payment   //       and (6).
                            - parseFloat( form.Payment.value );

  form.OverPay.value        = 0;                   // for areas (9),
  form.TotalPayment.value   = n_payments*payment;         //   (10),
  form.TotalInterest.value  = n_payments*payment - loan;  // & (11).

  // Compute the Amortization Table if it is on.

  if ( form.ComputeTable.selectedIndex == 1 ) {

  // Note the n_payments is from input area (8).
  // If it is from (4), round off value may cause one more
  // iteration before stop.

     payment       = parseFloat( form.Payment.value );
     pay2principal = parseFloat( form.Pay2Principal.value );

     PaymentInfo   = new ComputeAmortizationTable( loan,
     interest_rate, payment, pay2principal, n_payments );

  // Clean the old table and show the new one.
     form.AmortizationTable.value =    "";             // Clean the table.
     form.AmortizationTable.value = PaymentInfo.table; // Show  the table.

  // Update the final payment information.
     form.OverPay.value        = PaymentInfo.over_pay;
     form.TotalNPayments.value = PaymentInfo.n_payments;
     form.TotalPayment.value   = PaymentInfo.n_payments
                               * ( payment + pay2principal )
                               - PaymentInfo.over_pay;
     form.TotalInterest.value  = PaymentInfo.total_interest_paid;

  }

  payment    = parseInt( form.NumberPayments.value );
  n_payments = parseInt( form.TotalNPayments.value );

  if ( ( payment < n_payments ) || ( n_payments <= 0 ) ) {
     alert( "Input value for option (8) should be < the Number\n"
          + "of Payment in input area (4) and > 0!" );
  }

} // End of CalculatePayment().

//
// Callers: doLoanCalculations
//
function ComputeAmortizationTable( loan,
         interest_rate, payment, pay2principal, n_payments )
{
  var remaining_loan      = loan;
  var total_interest_paid =  0.0;
  var       interest_paid =  0.0;
  var total_loan_paid     =  0.0;
  var       loan_paid     =  0.0;
  var i = interest_rate/100.0;  // Convert % to demical, e.g 8.5% = 0.085.

  var n = 1;
  var table   = "";  // output.

  var message = MsgBox( "Computing Amortization Table<BR>"
                      + "Please wait..." );

  while ( ( n <= n_payments ) && ( remaining_loan > 0.0 ) ) {
            interest_paid  = remaining_loan*i;
                loan_paid  = payment - interest_paid;
      total_interest_paid += interest_paid;
      total_loan_paid     += pay2principal;
      total_loan_paid     += loan_paid;
      remaining_loan      -= pay2principal;
      remaining_loan      -= loan_paid;
  //  table += n.toString() + " " +       interest_paid.toString()
  //                        + " " + total_interest_paid.toString()
  //                        + " " +           loan_paid.toString()
  //                        + " " +     total_loan_paid.toString()
  //                        + " " +      remaining_loan.toString() + "\n";
      table += Iformat( n, 3, "0" ) + " "
            +  Fformat(       interest_paid.toString(), 10, 2 ) + " "
            +  Fformat( total_interest_paid.toString(), 11, 2 ) + " "
            +  Fformat(           loan_paid.toString(), 10, 2 ) + " "
            +  Fformat(       pay2principal.toString(), 10, 2 ) + " "
            +  Fformat(     total_loan_paid.toString(), 11, 2 ) + " "
            +  Fformat(      remaining_loan.toString(), 11, 2 ) + "\n";
      n +=1;
  }

  this.n_payments          = n - 1;           // Total number of payments made.
  this.over_pay            = Math.abs( remaining_loan );  // will be <= 0.
  this.table               = table;
  this.total_interest_paid = total_interest_paid;

  message.close();

  // No return statement here.  This function will be called an
  // Object Constructor.

} // End of ComputeAmortizationTable().

//
// Callers: doLoanCalculations
//
function ComputeInterestRate( loan, payment, n_payments, payments_in1yr )
{
  // payment = loan/( 1 - Math.pow( ( 1 + i ), -n_payments ) )/i );

  var  r1 = 0.0;
  var  r2 = 0.0;
  var fr2 = loan - payment*n_payments; 

  if ( fr2 > 0.0 ) {
     alert( "Total payments will not cover the loan.\n"
          + "Increase either the amount of each payment,\n"
          + "number of payment or both." );
     return -1;  // Error.
  } else {

  // Define the function's properties.

     PVA.loan       = loan;
     PVA.payment    = payment;
     PVA.n_payments = n_payments;

  // Set 2 interest rates: r1 & r2.

      r1 = ( n_payments > 12 ? 24.0 : n_payments*2.0 );
      r2 = payment*n_payments - loan;
      r1 = r1*r2;
      r2 = r1/( loan*( n_payments + 1 ) );
      r2 = r2/payments_in1yr;
      r1 = r2/4.0;
     fr2 = PVA( r2 );

  // alert( "1) r1 & r2 = " + r1 + " " + r2 + " " + PVA( r1 ) + " " + fr2 );

  // Adjust r1 and r2 so that PVA( r1 )*PVA( r2 ) < 0 which
  // means there is a value: r such that PVA( r ) = 0.
  // The root: r is the interest rate that this function is
  // serach for.

     var iterations = 0;

     while ( PVA( r1 )*fr2 > 0.0 && iterations < 100 ) {
           iterations += 1;
           if ( fr2 < 0.0 ) {
              r1  = r2;
              r2 *= 2.0;
           } else {
              r2 = r1
              r1 = r2/2.0;
           }
           fr2 = PVA( r2 );
     }
  // alert( "2) r1 & r2 = " + r1 + " " + r2 + " " + PVA( r1 ) + " " + fr2 );

     var interest_rate = zbrent( PVA, r1, r2, 1.0E-7 );
     if ( interest_rate.status != "ok" ) interest_rate.value = -1;

     return interest_rate.value*100;  // in %-age.
  }
} // End of ComputeInterestRate().

//
// Callers: doLoanCalculations
//
function ComputeLoanAmount( interest_rate, payment, n_payments )
{
  var i = interest_rate/100.0;  // Convert % to demical, e.g 8.5% = 0.085.

  // payment = loan/( 1 - Math.pow( ( 1 + i ), -n_payments ) )/i );
  // and it can be rewritten as
  // loan = (payment)( 1 - Math.pow( ( 1 + i ), -n_payments ) )/i;

  if ( i < 0.000001 ) // Assume interest rate is 0.
     return payment*n_payments;
  else {
     return payment*( 1.0 - Math.pow( ( 1.0 + i ), -n_payments ) )/i;
  }
} // End of ComputeLoanAmount().

//
// Callers: doLoanCalculations
//
function ComputeNumberPayments( loan, interest_rate, payment )
{
  var i = interest_rate/100.0;  // Convert % to demical, e.g 8.5% = 0.085.

  // payment = loan/( 1 - Math.pow( ( 1 + i ), -n_payments ) )/i );
  // and it can be rewritten as
  // n_payments = abs( log( 1 - (loan)(i)/Payment )/log( 1 + i ) );

  if ( i < 0.000001 ) // Assume interest rate is 0.
     return Math.round( loan/payment );
  else {
     var n = 1.0 - loan*i/payment;
     if ( n <= 0.0 ) {
        alert( "Monthly payment must be increased to at least "
             + loan*i + "\nin order to determine number of payment." );
        return -1;  // Error.
     } else {
        n = Math.abs( Math.log( n )/Math.log( 1.0 + i ) );
        return Math.ceil( n );  // Get the Closest integer that is >= n.
     }
  }
} // End of ComputeNumberPayments().

//
// Callers: doLoanCalculations
//
function ComputePayment( loan, interest_rate, n_payments )
{
  var i = interest_rate/100.0;  // Convert % to demical, e.g 8.5% = 0.085.

  // Payment = loan/( 1 - Math.pow( ( 1 + i ), -n_payments ) )/i );
  // and it can be rewritten as
  // Payment = ( loan*i )/( 1 - Math.pow( ( 1 + i ), -n_payments ) );

  if ( i < 0.000001 ) // Assume interest rate is 0.
     return loan/n_payments;
  else {
     return ( loan*i )/( 1.0 - Math.pow( ( 1.0 + i ), -n_payments ) );
  }

} // End of ComputePayment().

//
// Callers: HTML FORM, and AmortizationTableOnOff()
//
function doLoanCalculations( form )
{
  // Get the parameters.

  var loan           = parseFloat( form.LoanAmount.value );
  var interest_rate  = parseFloat( form.InterestRate.value );
  var payment        = parseFloat( form.Payment.value );
  var pay2principal  = parseFloat( form.Pay2Principal.value );
  var n_payments     = parseFloat( form.NumberPayments.value );
  var payments_in1yr = parseFloat( form.PaymentsPerYear.value );
  
  var cheker = 0;
  var tempor = 0;
  var months = " months";
  var years = " years ";

  interest_rate /= payments_in1yr;

  // Determine which parameter needs to be computed
  // and show the result.

  //if ( form.SetCompute[0].checked ) {
  //   loan = ComputeLoanAmount( interest_rate, payment, n_payments );
  //   form.LoanAmount.value = loan;  // Show & save the new loan value.
  //} else if ( form.SetCompute[1].checked ) {
  //   interest_rate = ComputeInterestRate(
  //                   loan, payment, n_payments, payments_in1yr )
  //   if ( interest_rate < 0 ) return;  // Skip the rest of calculations.
  //   form.InterestRate.value = interest_rate*payments_in1yr;
  //} else if ( form.SetCompute[2].checked ) {
  //   payment = ComputePayment( loan, interest_rate, n_payments );
  //   form.Payment.value = payment;
  //} else if ( form.SetCompute[3].checked ) {
     n_payments = ComputeNumberPayments( loan, interest_rate, payment );
     if ( n_payments < 1 ) return;     // Skip the rest of calculations.
     form.NumberPayments.value = n_payments;
  //}

  if ( pay2principal >= 0.0 ) {
     form.MonthlyPayment.value = pay2principal + payment;
  } else if ( form.MonthlyPayment.value > payment ) {
     form.Pay2Principal.value  = parseFloat( form.MonthlyPayment.value )
                               - payment;
     pay2principal = parseFloat( form.Pay2Principal.value );
  }

  if ( pay2principal > 0.0 ) {
     form.ComputeTable.selectedIndex = 1;
  } else {
     form.OverPay.value = 0;
	 
	 if(n_payments==1) { months = " month"; }
	 
	 // tempor is calc depend on monthly/fortnightly/weekly payment
	 tempor = n_payments / payments_in1yr;
	 
	 //alert(payments_in1yr);
	 
	 if(tempor < 1) {	// if repayments are in period max 11 monrhs
	 	
		form.TotalNPayments.value = Math.round( tempor * 12 ) + months;
		
	 }
	 else { // else if repayments are equal or more than 1 year
		if(parseInt(tempor)<2) {
			years = " year ";
		}
		
		cheker = Math.round((tempor - parseInt(tempor))*12);
		
		if( cheker < 2 ) {
			months = " month";
		}
		
		// print years amd months
		form.TotalNPayments.value = parseInt(tempor) + years; 
		
		if(cheker > 0) {
			form.TotalNPayments.value += Math.round((tempor - parseInt(tempor))*12)  + months; 
		}
	 }
	 
     form.TotalPayment.value   = payment * n_payments;
     form.TotalInterest.value  = form.TotalPayment.value - loan;
  }

  // Compute the Amortization Table if it is asked for.

  if ( form.ComputeTable.selectedIndex == 1 ) {  // 1 = On.
  // var message = MsgBox( "Computing Amortization Table..." );
     setTimeout( "", 10000 );
     PaymentInfo = new ComputeAmortizationTable( loan,
     interest_rate, payment, pay2principal, n_payments );
  // message.close();
  // Clean the old table and show the new one.
     form.AmortizationTable.value =    "";             // Clean the table.
     form.AmortizationTable.value = PaymentInfo.table; // Show  the table.
  // Update the final payment information.
     form.OverPay.value        = PaymentInfo.over_pay;
	  
     form.TotalNPayments.value = PaymentInfo.n_payments; 
	 
     form.TotalPayment.value   = PaymentInfo.n_payments
                               * ( payment + pay2principal )
                               - PaymentInfo.over_pay;
     form.TotalInterest.value  = PaymentInfo.total_interest_paid;
  }

} // End of doLoadCalculations().

//
// Caller: any
//
function MsgBox( message )
{
  var w = window.open( "", "MsgBox",
         "resizeable,scrollbars=1,status,width=256,height=126" );

  var d = w.document;

  d.write( '<HTML><BODY><DIV align=center>' );
  d.write( '<FONT SIZE=3>' );
  d.write( '<B>' + message + '</B><P>' );
  d.write( '</FONT></BODY></HTML>' );

  d.close();

  return w;
}

//
// PVA = Present Value Annuity function
//
// Caller: zbrent()
//
function PVA( i )  // i = interest rate in demical.
{
  var value = 0;

  value = Math.pow( 1.0 + i, -PVA.n_payments );
  value = ( 1.0 - value )/i;

  return value*PVA.payment - PVA.loan;

} // End of PresentValueAnnuity().
