var bDebug = 0 ;        // change to 1 for extra output
var nErrorNumber = -1.2345e-12 ;

function Execute(oForm)
{
   var iError = 0 ;
   var nPrincipal, nInputInterest, nPoints, nClosingCosts, iYears ;
   var nPropertyValue, nMonthlyTaxes, nHazardInsurance, nMortgageInsurance ;

   if ( (nPrincipal = Validate(oForm.loanamount.value, 0)) == nErrorNumber)
      iError = 100 ;
   else if ( (nInputInterest = Validate(oForm.interestrate.value, 0)) == nErrorNumber)
      iError = 110 ;
   else if ( (nPoints = Validate(oForm.points.value, 0)) == nErrorNumber)
      iError = 120 ;
   else if ( (nClosingCosts = Validate(oForm.closingcosts.value, 0)) == nErrorNumber)
      iError = 130 ;
   else if ( (iYears = Validate(oForm.years.value, 1)) == nErrorNumber)
      iError = 140 ;
   else if ( (nPropertyValue = Validate(oForm.propertyvalue.value, 0)) == nErrorNumber)
      iError = 150 ;
   else if ( (nMonthlyTaxes = Validate(oForm.monthlytaxes.value, 0)) == nErrorNumber)
      iError = 160 ;
   else if ( (nHazardInsurance = Validate(oForm.hazardinsurance.value, 0)) == nErrorNumber)
      iError = 170 ;
   else if ( (nMortgageInsurance = Validate(oForm.mortgageinsurance.value, 0)) == nErrorNumber)
      iError = 180 ;
   
   if (oForm.estimate.checked)
   {
       var nLVRatio, nMIRatio;
       
       nMonthlyTaxes = (nPropertyValue * 0.0136) / 12;
       nHazardInsurance = (nPropertyValue * 0.0024) / 12;
       nLVRatio = (nPrincipal/nPropertyValue);
       
       if (nLVRatio > .8)
       {
            switch(true)
            {
                case ((nLVRatio > .95) && (nLVRatio <= 1)):
                    nMIRatio = .0096;
                    break;
                case ((nLVRatio > .90) && (nLVRatio <= .95)):
                    nMIRatio = .0078;
                    break;
                case ((nLVRatio > .85) && (nLVRatio <= .90)):
                    nMIRatio = .0052;
                    break;
                case ((nLVRatio > .80) && (nLVRatio <= .85)):
                    nMIRatio = .0032;
                    break;
                default:
                    nMIRatio = 0;
            }
            
            nMortgageInsurance = (nPrincipal * nMIRatio) / 12;
       }
   }

   var iPpy = 12 ;
   var iMonths = 12 * iYears ;
   var iPeriods = iPpy * iYears ;
   var nPercent = nInputInterest / iPpy / 100 ;


   if (!iError)
   {
      var sMessage = "" ;
      if (nPrincipal == 0)
         sMessage = "Please enter a loan amount" ;
      else if (nPrincipal < 0)
         sMessage = "Loan amount must be positive" ;
      else if (nPercent == 0)
         sMessage = "Please enter a quoted interest rate" ;
      else if (nPercent < 0)
         sMessage = "Quoted interest rate must be positive" ;
//    else if (nPoints == 0)
//       sMessage = "Please enter points (%)" ;
      else if (nPoints < 0)
         sMessage = "Points (%) must be zero or positive" ;
//    else if (nClosingCosts == 0)
//       sMessage = "Please enter other closing costs" ;
      else if (nClosingCosts < 0)
         sMessage = "Other closing costs must be zero or positive" ;
      else if (iYears == 0)
         sMessage = "Please enter length of loan (in years)" ;
      else if (iYears < 0)
         sMessage = "Length of loan (in years) must be positive" ;
//      else if (nPropertyValue == 0)
         //sMessage = "Please enter a property value" ;
      else if (nPropertyValue < 0)
         sMessage = "Property value must be positive" ;
//      else if (nMonthlyTaxes == 0)
         //sMessage = "Please enter monthly real estate taxes" ;
      else if (nMonthlyTaxes < 0)
         sMessage = "Monthly real estate taxes must be positive" ;
//      else if (nHazardInsurance == 0)
         //sMessage = "Please enter monthly hazard insurance" ;
      else if (nHazardInsurance < 0)
         sMessage = "Monthly hazard insurance must be positive" ;
//      else if (nMortgageInsurance == 0)
         //sMessage = "Please enter monthly mortgage insurance" ;
      else if (nMortgageInsurance < 0)
         sMessage = "Monthly mortgage insurance must be positive" ;
      if (sMessage != "")
      {
         alert(sMessage) ;
      }
   }

   if (!iError)
   {
      var nPayment = nPrincipal / PresentValue(1, nPercent, iPeriods) ;
      nPayment = Round(nPayment + .005, 2) ;
      
      var nMonthlyCosts = nMonthlyTaxes + nHazardInsurance + nMortgageInsurance ;
      var nTotalPayment = nPayment + nMonthlyCosts ;
      
      
      var nFees = (nPercent * nPrincipal) / 2 ;
      var nPointsCost = nPoints * nPrincipal / 100 ;
      var nTotalCosts = nFees + nPointsCost + nClosingCosts ;
      var nEffectiveLoan = nPrincipal + nTotalCosts ;
      var nEffectivePayment = nEffectiveLoan / PresentValue(1, nPercent, iPeriods) ;

      var iCount = 100 ;         // loop limit
      var nX = nPercent, nPv ;

      while (iCount-- > 0 && Math.abs(nPrincipal
                - (nPv = PresentValue(nEffectivePayment,
                                        nX, iMonths))) > 5e-5)
         nX *= 1 + (nPv - nPrincipal) / nPrincipal ;

      nEffectivePc = Round(1200 * nX - .00005, 3) ;
      
      var nDownPayment = nPrincipal - nPropertyValue ;
      
      if (nDownPayment < 0)
      {
        nDownPayment = Math.abs(nDownPayment);
      }
      else if (nDownPayment > 0)
      {
        nDownPayment = 0-nDownPayment;
      }
      
      var nLVPercent = (nPrincipal / nPropertyValue) * 100 ;

      document.getElementById('resultvalue').innerHTML = DollarFormat(nTotalPayment, 0, 2);
      document.getElementById('payment').innerHTML = DollarFormat(nPayment, 0, 2);
      document.getElementById('retaxes').innerHTML = DollarFormat(nMonthlyTaxes, 0, 2);
      document.getElementById('hinsurance').innerHTML = DollarFormat(nHazardInsurance, 0, 2);
      document.getElementById('minsurance').innerHTML = DollarFormat(nMortgageInsurance, 0, 2);
      document.getElementById('totalpayment').innerHTML = DollarFormat(nTotalPayment, 0, 2);
      document.getElementById('upfrontcosts').innerHTML = DollarFormat(nTotalCosts, 0, 2);
      document.getElementById('apr').innerHTML = (Format(nEffectivePc, 0, 3) + " %");
      document.getElementById('ir').innerHTML = (Format(nInputInterest, 0, 3) + " %");
      document.getElementById('loanpoints').innerHTML = DollarFormat(nPointsCost, 0, 2);
      document.getElementById('downpayment').innerHTML = DollarFormat(nDownPayment, 0, 2);
      document.getElementById('lvratio').innerHTML = (Format(nLVPercent, 0, 0) + " %");
      document.getElementById('results').style.display = "";
   }

}

var sBlanks = "                                             "
                + "                                          " ;

var nPowers = [
        0.0000000000000001,
        0.000000000000001,
        0.00000000000001,
        0.0000000000001,
        0.000000000001,
        0.00000000001,
        0.0000000001,
        0.000000001,
        0.00000001,
        0.0000001,
        0.000001,
        0.00001,
        0.0001,
        0.001,
        0.01,
        0.1,
        1.,
        10.,
        100.,
        1000.,
        10000.,
        100000.,
        1000000.,
        10000000.,
        100000000.,
        1000000000.,
        10000000000.] ;

function Power(n)
{
    return nPowers[n+16] ;
}

function ExpN(nX, iN)   // compute x ** n, where n is integral
{
   var nResult = 1 ;
   var bSign = 0 ;
   if (iN < 0)
   {
      bSign = 1 ;
      iN = -iN ;
   }
   while (iN > 0)
   {
      if (iN & 1)
         nResult *= nX ;
      nX *= nX ;
      iN >>= 1 ;
   }
   if (bSign)
      nResult = 1 / nResult ;
   return nResult ;
}

function PresentValue(nPayment, nPercent, iNumPeriods)
{
   var nAmount = (Math.abs(nPercent) > 1e-20)
         ? nPayment * (1 - ExpN(1 + nPercent, -iNumPeriods))
                                        / nPercent 
         : nPayment * iNumPeriods ;
   return nAmount ;
}

function Round(nVal, iD)
{
   var iSign = 1 ;
   if (nVal < 0)
   {
      nVal = - nVal ;
      iSign = -1 ;
   }
   var iInt = Math.round(nVal) ;
   if (iD > 0)
      iInt = Math.floor(nVal) ;
   var nFp = nVal - iInt ;
// alert ('iInt, nFp = ' + iInt + ", " + nFp) ;
   if (iD > 0)
      nFp = Math.round(nFp * Power(iD)) / Power(iD) ;
   nVal = iSign * (iInt + nFp) ;
   return nVal ;
}

function Validate(sVal, bInt)
{
   var sMessage = "" ;
   var bDot = 0, bE = 0, iState = 0 ;
   var sCh, iK ;
   var bInvalid = 0 ;
   var nValue = bInt ? parseInt(sVal) : parseFloat(sVal) ;

   for (iK = 0 ; sMessage == "" && iK < sVal.length ; ++iK)
   {
      sCh = sVal.charAt(iK) ;
      if (sCh == " ")
      {
         if (iState > 0)
            iState = 9 ;
      }
      else
      {
         if (iState == 9)
            sMessage = "Number '" + sVal + "' has an embedded blank" ;
         else if (sCh == '.' && !bInt)
         {
            if (bDot || bE)
               bInvalid = 1 ;
            else
               bDot = 1 ;
         }
         else if ((sCh == 'e' || sCh == 'E') && !bInt)
         {
            if (bE)
               bInvalid = 1 ;
            else
            {
               bE = 1 ;
               iState = 6 ;
            }
         }
         else if (sCh == '+' || sCh == '-')
         {
            if (iState == 0 || iState == 6)
               ++iState ;
            else
               sMessage = "Number '" + sVal + "' contains a sign "
                                + "in an illegal position"
         }
         else if (sCh >= '0' && sCh <= '9')
         {
            if (iState == 1 || iState == 7)
               ++iState ;
            else if (iState == 0 || iState == 6)
               iState += 2 ;
         }
         else
            bInvalid = 1 ;
      }
      if (bInvalid)
         sMessage = "Number '" + sVal + "' contains"
                        + " invalid non-numeric character(s)" ;
   }

   if (sMessage == "")
      if (iState == 1 || iState == 6 || iState == 7)
         sMessage = "Illegal number: " + sVal ;
      else if (iState == 0)
         nValue = 0 ;
   if (sMessage != "")
   {
      alert(sMessage) ;
      nValue = nErrorNumber ;
   }
   return nValue
}

// DollarFormat -- could be jazzed up to produce "CR" or "DB"
function DollarFormat(nVal, iW, iD)
{
   return GenFmt(nVal, iW, iD, 1) ;
}

function Format(nVal, iW, iD)
{
   return GenFmt(nVal, iW, iD, 0) ;
}

function GenFmt(nVal, iW, iD, bDollar) // format val into w chars,
                        // d digs after decimal point
{
   var sOut = "" ;
   var iSign = 0 ;
   nVal = Round(nVal, iD) ;
   if (nVal < 0)
   {
      nVal = - nVal ;
      iSign = 1 ;
   }
   var iInt = Math.round(nVal) ;
   if (iD > 0)
      iInt = Math.floor(nVal) ;
   var nFp = nVal - iInt ;
   var iDigs = 1 ;
   if (iInt > 9)
      iDigs = Math.floor(Math.log(iInt+.1)/Math.log(10)) + 1 ;
   var iLeft = iW - iSign - (bDollar ? 1 : 0) ;
   if (iD > 0)
      iLeft -= iD + 1 ;
   if (iLeft > iDigs)
      sOut += sBlanks.substring(0, iLeft - iDigs) ;
   if (iSign)
      sOut += '-' ;
   if (bDollar)
      sOut += '$' ;
   sOut += iInt ;
   if (iD > 0)
   {
      nFp = Math.round((1 + nFp) * Power(iD)) ;
      sOut += '.' + String(nFp).substring(1) ;
   }
   return sOut ;
}