// JavaScript Document



<!--

/* hide this code from non scriptable browsers



If you run into any problems while trying to configure this script, help is available.  

       1) E-mail the author at: Qube@ix.netcom.com



                            MORTGAGE LOAN CALCULATOR

COPYRIGHT NOTICE                                                         

Copyright 1997, 1998 Steven D. Witkop  All Rights Reserved.



This Javascript "Mortgage Loan calculator" Script  may be used and modified free of charge by anyone
so long as this copyright notice and the comments above remain intact.  By using this code you agree 
to indemnify Steven D. Witkop from any liability that  might arise from it's use.   

Selling the code for this program without prior written consent is  expressly forbidden.  In other 
words, please ask first before you try and  make money off of my program.  

Obtain permission before redistributing this software over the Internet or in any other medium. 
In all cases copyright and header must remain intact

 LANGUAGE: JavaScript 1.1 compliant

  PATTERN: MVC

*/



// initilize page variables

window.onerror=null
var bState = true;
var rec = 0;
var oTable = new Array();

// the colors for the amortization table... you will need to search and replace on these codes for the HTML form.
var bColor = '#FFFFFF' // white
var fColor = '#000000' //purple
// var fColor = '#000000' // green

// var bColor = 'WHITE'  // '#FFFFFF' 
// var fColor = 'PURPLE' // '#000000'


// names for the collections (used for form validation)
oReq = new Collection("AMOUNT","RATE","","","","")
oVal = new Collection("AMOUNT","RATE","","","","")
oTst = new Collection("N","N","","","","")


//============================================================================
// Gets called when the user pressed one of the buttons.
// oForm: 		form elements
// oBtn:  		the name of the button that was pressed
// return value:	did we make it through?
//============================================================================

function controller(oForm, oBtn) {

   while (bState) {

      if (!Required(oForm))

         break;

      if (!Validate(oForm))

         break;

      if (!Create())

         break;

      if (!SetValue(oForm))

         break;

      if (!Amortize(oForm, oBtn))

         break;

      if (bState) {

          bState = false

      }

   }

   bState = true

}



//============================================================================
// Check if a form element is required by comparing the all of the form
// elements against a collection of required form control names.
// oView: 		form elements
// oReq		required elements
// return value:	did it pass the test?
//============================================================================

function Required(oView) {

   for (i in oView ) {

      for (j in oReq) {

          if (i == oReq[j]) {      

             if (isMissing(oView[i])) {

               return(false)

             }

          }

      } 

  }

  return(true)

}



//============================================================================
// Check if a form control is required and missing
// oView: 		a form control
// Return value:	do we have a problem?
//============================================================================

function isMissing(oCtrl) {

   if (oCtrl.value == "") {  

      alert("You have left a required value blank. Please type a number");

      oCtrl.focus();

      oCtrl.select();

      return(true)

      }

   else

      { 

      return(false)

   }

}



//============================================================================
// Check if a form element inputs need to be a certain type by
// comparing all of the form elements against a collection of 
// form controls that need specific types of input data.
// oView: 		form elements
// oReq		required elements
// return value:	did it pass the test?
//============================================================================

function Validate(oView) {

   for (i in oView) {

      for (j in oVal) {

        if (i==oVal[j] && oTst[j]=="N") {      

           if (isTest(oView[i], oTst[j])) {

               return(false)

           }

        }

     }

  }

  return(true)

}



//============================================================================
// Check if a form control input is the right type
// oView: 		a form control
// Return value:	do we have a problem?
//============================================================================

function isTest(oCtrl, oTest) {

   if (oTest=="N" && !isNumber(oCtrl.value) ) {

      alert(oCtrl.value+" contains an invalid character. Please type a number");

      oCtrl.focus();

      oCtrl.select();

      return(true)

      }

      else

      { 

      return(false)

   }

}



//============================================================================
// Check if the result is a number
// input: 		a texbox value
// Return value:	true / false
//============================================================================

function isNumber(input) {

var result = ""

var nperiods = 0;

   for (var i=0;i<input.length;i++) {

      var ch = input.substring(i, i+1);

      if (!isNaN(parseInt(ch))) {

         result = result + ch

      } 

      if (ch==".") {

        nperiods++;

      }

      if (nperiods==1){

         result = result + ch  

      }

   }

   if (result == ""){

     return(false);

   }

return(true)

}



//============================================================================
// Make a string input into a number
// input: 		a texbox value
// Return value:	a number
//============================================================================

function makeNumber(input) {

var result = ""

var nperiods = 0;

   for (var i=0;i<input.length;i++) {

       var ch = input.substring(i, i+1);

       var flag = true;

       if (!isNaN(parseInt(ch))) {

          result = result + ch

       }           

       if (ch==".") {

         nperiods++;

       }

       if (nperiods==1){

          result = result + ch  

       }

     }

  return(result)

}


//============================================================================
// Create a default instance of the object
// parm1:	Amount	- required
// parm2:	Rate		- required
// parm3:   	Term		- required
// parm4:	Payment
// parm5:	Interest
// parm6:	Frequency	- required
// parm7:	Periods
// return value:	did we create the oebject?
//============================================================================

function Create() {

   Mortgage = new Loan(50000, 8, 30, 0, 0, "Monthly", 0 );

   return(true)

}


//============================================================================
// Set the properties of the object based on form inputs
// oView: 		form elements
// return value:	did it get and set the properties?
//============================================================================

function SetValue(oView) {

   // get the properties mapped from the form

   Mortgage.Amount = makeNumber(oView.AMOUNT.value);

   // works like a masked edit
   oView.AMOUNT.value = calcRound(Mortgage.Amount);

   Mortgage.Rate = makeNumber(oView.RATE.value);

   Mortgage.Term = get_selection(oView.YEARS);

   Mortgage.Frequency = get_selection(oView.FREQUENCY);

   // set the number of periods
   Mortgage.calcPeriods();

   // set the monthly payment
   Mortgage.calcPayment();

   // set the total interest due
   Mortgage.calcInterest();

   // update the form view
   Show()

   return(true)

}


//============================================================================
// Amortize is called at the end of the controler loop and checks to see
// if the amortize button was pushed
// oForm: 		form elements
// oBtn:  		the name of the button that was pressed
// return value:	did we select the Amortize button?
//============================================================================

function Amortize(oForm, oBtn) {

   if (oBtn.name == "cmdCalc") {

      return(false)

   }

   if (confirm("An Amortization Table calculates the periodic payment breakdown for each specific category listed.")) {

      // need to create the table before you can show it
      createRecords();

      // display the table
      showAmortize(oForm);

      return(true)

    }

  return(false)

}



//============================================================================
// create Records computes the values associated with the Amortzation of a Mortgage Loan and 
// adds those values to a record in the Amortization table container array
// return value:	did we calculate all values to display in the Amortization?
//============================================================================

function createRecords(){

   // re-init the record counter and container array
   rec = 0;

   oTable = new Array();

   // initialize variables
   var currInt = 0;

   var currPrin = 0;

   prevBalance = Mortgage.Amount;

   InterestRate = ( Mortgage.Rate /100) / Mortgage.Periods;

   MonthlyPayment = Mortgage.Payment;

   //currStart = '1997';
   currStart = get_selection(document.MORTGAGE.START);
  
   // let the loops begin
   for(i=1;i<=30;i++) {

      for(j=1;j<=Mortgage.Periods;j++) {

         periodInt = prevBalance * InterestRate;

         periodPrin = MonthlyPayment - periodInt;

         currBal = prevBalance - periodPrin;

         currInt += periodInt;

         currPrin += periodPrin;

         prevBalance = currBal;

      }

      if( currBal <= 0 ){ 

         currBal = 0;

      }



      // set the parameters
      Year = currStart;
      Interest = calcRound(currInt);
      Principle = calcRound(currPrin);
      Balance = calcRound(currBal);

      // increment the container 
      rec++

      // add a record to the table
      addRecord(Year, Interest, Principle, Balance);

      // re-init the private variables
      currInt = 0;
      currPrin = 0;
      currStart = parseInt(currStart);
      currStart += 1;

      // are we done?
      if(currBal<=0) {

         return(true)

      }       

   }

   return (true)

}

//============================================================================
// Build a text string with a header, the table and a footer in HTML then
// diplay the table in a new window with only the menu active.
// oForm: 		form elements
// return value:	did we display the Amortization?
//============================================================================

function showAmortize(oForm) {

   // create the header

   text = ("<HEAD><TITLE>Amortization Table</TITLE></HEAD>");

   text = (text +"<BODY BGCOLOR =  "+bColor+"><BR><BR>");

   text = (text +"<H2 ALIGN=CENTER><FONT COLOR="+fColor+">Amortization Table</FONT></H2>");

   text = (text +"<UL><FONT SIZE=-1>The following table is based on the information entered in the calculator form.</FONT></UL>");

   text = (text +"<UL><FONT SIZE=+1 COLOR="+fColor+"> Mortgage Amount: </FONT>" +calcRound(Mortgage.Amount));

   text = (text +"<BR><FONT SIZE=+1 COLOR="+fColor+">   Interest Rate: </FONT>" + Mortgage.Rate + " %");

   text = (text +"<BR><FONT SIZE=+1 COLOR="+fColor+"> Mortgage Length: </FONT>" + Mortgage.Term + " Years");

   text = (text +"<BR><FONT SIZE=+1 COLOR="+fColor+"> Payment Frequncy: </FONT>" + Mortgage.Frequency + "  </UL>");

   text = (text +"<BR><CENTER><table border='1' width='100%'>");

   text = (text +"<TR><TD ALIGN=CENTER BGCOLOR="+fColor+"><FONT COLOR="+bColor+"><B>Year</B></FONT></TD><TD ALIGN=RIGHT BGCOLOR="+fColor+"><FONT COLOR="+bColor+"><B>Interest&nbsp;</B></FONT></TD><TD ALIGN=RIGHT BGCOLOR="+fColor+"><FONT COLOR="+bColor+"><B>Principal&nbsp;</B></FONT></TD><TD ALIGN=RIGHT BGCOLOR="+fColor+"><FONT COLOR="+bColor+"><B>Balance&nbsp;</B></FONT></TD></TR>\n");
     
   // create the Amortization table text by looping through a CONTAINER ARRAY 

   for (var q=1; q<oTable.length;q++) {

      text = (text +"<TR><TD ALIGN=CENTER>"+ oTable[q].Year +"</TD><TD ALIGN=RIGHT>"+ oTable[q].Interest +"&nbsp;</TD><TD ALIGN=RIGHT>"+ oTable[q].Principle +"&nbsp;</TD><TD ALIGN=RIGHT>"+ oTable[q].Balance +"&nbsp;</TD></TR>");

   }

   

   // create the footer  

   text = (text +"</TABLE></CENTER>");



   // Create a new window to display the results

   oWindow=window.open("","displayWindow","toolbar=no,width=500,height=300,directories=no,status=no,scrollbars=yes,resize=no,menubar=yes");

   oWindow.document.write(text);

   oWindow.document.close();



   return(true)

}





//============================================================================
// Collection Constructor, a custom object to act as an array but provide
// more flexibility in the future.
//============================================================================

function Collection(item1, item2, item3, item4, item5, item6) {

   this.item1 = item1;

   this.item2 = item2;

   this.item3 = item3;

   this.item4 = item4;

   this.item5 = item5;

   this.item6 = item6;

}



//============================================================================
// Loan Constructor, defines what the Loan object will look like
// and how it will behave. 
//============================================================================

function Loan(Amount, Rate, Term, Payment, Interest, Frequency, Periods ) {

   this.Amount = Amount;

   this.Rate = Rate;

   this.Term = Term;

   this.Payment = Payment;

   this.Interest = Interest;

   this.Frequency = Frequency;

   this.Periods = Periods;

   this.calcPeriods = calcPeriods;

   this.calcPayment = calcPayment;

   this.calcInterest = calcInterest;

}



//============================================================================
// Loan object method that calculates the monthly payment for a mortgage loan in the US
//============================================================================

function calcPayment() {

   this.Payment = (this.Amount*((this.Rate/(1200))/(1-(Math.pow(1+(this.Rate/(1200)),((this.Term*12)*-1))))));



  // handle bi-weekly 

  if ( this.Periods == 26 ){

      this.Payment = this.Payment / 2;

   }

}



//============================================================================
// Loan object method that calculates the interest portion of a loan
//============================================================================

function calcInterest() {

   this.Interest = ((this.Payment*(this.Term*this.Periods))-this.Amount);

}



//============================================================================
// Loan object method that translates a selection drop down to a value
//============================================================================

function calcPeriods() {

   if (this.Frequency=="Monthly") { this.Periods=12 } else { this.Periods=26 }

}



//============================================================================
// Loan object method that shows the calculated amounts
//============================================================================

function Show(oView) {

   document.MORTGAGE.PAYMENT.value = calcRound(Mortgage.Payment)

   document.MORTGAGE.INTEREST.value = calcRound(Mortgage.Interest)

}



//============================================================================
// oRecord Constructor, defines what the Amortzation record looks like 
//============================================================================

function oRecord(Year, Interest, Principle, Balance){

   this.Year = Year;

   this.Interest = Interest;

   this.Principle = Principle;

   this.Balance = Balance;

}



//============================================================================
// addRecord defines how a record gets added to the container array
//============================================================================

function addRecord(Year, Interest, Principle, Balance){

   oTable[rec] = new oRecord(Year, Interest, Principle, Balance);

}



//============================================================================
// select_item Constructor, used to retrive the selected item from the dropdown 
// control on a form.
// name: 		form element name
// value:  		the value of the options that was selected
// return value:	selected item
//============================================================================

function select_item(name, value) {  

   this.name = name;

   this.value = value;

}



//============================================================================
// Common routine to retrieve the selected value from the drop down object
// select_object:	a drop down from control
// return value:	the selected objects name
//============================================================================

function get_selection(select_object) {   

   contents = new select_item();

   for(var i=0;i<select_object.options.length;i++)

      if(select_object.options[i].selected == true) {

        contents.name = select_object.options[i].text;

        contents.value = select_object.options[i].value;

      }      

   return(contents.name)

}



//============================================================================
// Common routine for rounding that also formats the results into US currency
// num: 		a number
// return value:  result is rounded and formated for currency $999,999.00
//============================================================================

function calcRound(num) {

   result="$"+Math.floor(num)+"." ;

   n = result.length;

   if (num>1000 && num<999999) {  

     result="$"+result.substring(1,n-4)+","+result.substring(n-4,n);

   }

   if (num>1000000) {  

     result = "$"+result.substring(1,n-7)+","+result.substring(n-7,n-4)+","+result.substring(n-4,n);

   }

   var cents=100*(num-Math.floor(num))+0.5;

   result += Math.floor(cents/10);

   result += Math.floor(cents%10);

   return(result)

}





//============================================================================
// A page specific routine to set the initial state when the page is reloaded.
//============================================================================

function setfocus() {   

   document.MORTGAGE.AMOUNT.focus();

   document.MORTGAGE.AMOUNT.select();

}



// unhide 

// -->

