//
// Something neat to remember about javascript.
// I can return a structure, i.e.,
// return {y : 30, f: 0.8, s: 0.0, name: "30y Conforming,No MI"};

//
// Variable for the currently selected tab.
// Defaults to the payment tab.
//
var selectedTab = 'payment';
var selectedTabNum = 1;

// Variable to record whether tab results are stale.
//
var curResultsArray = new Array();

//
// Callback function to change the calculator (tab).
// The argument is the anchor element associated with the selected tab.
//
function selectTab(e)
{
  // Get the newly selected tab from the passed element.
  new_tab = e.id.substring(2);

  // Hide the currently selected tab.
  // Display the selected tab.
  document.getElementById('td_' + selectedTab).className = 'tab';
  document.getElementById('td_' + new_tab).className = 'activetab';
  document.getElementById('a_' + selectedTab).className = 'tab';
  e.className = "tab activetab";
  document.getElementById('p_' + selectedTab).style.display = 'none';
  document.getElementById('p_' + new_tab).style.display = 'block';
  document.getElementById('r_' + selectedTab).style.display = 'none';
  document.getElementById('r_' + new_tab).style.display = 'block';

  // Reset the selectedTab variable.
  selectedTab = new_tab;

  // Store the selected tab number.
  selectedTabNum = document.getElementById('tab_' + new_tab).value/1;

  // Also store the selected tab in the window object.
  // I will need to access it if the user wants printable results.
  window.selectedTab = selectedTab;

  // No rate, so call getRate now.
  if (document.getElementById('rate' + selectedTabNum).value == '') {
    getRateCB();
  }
}

//
// Function to estimate the taxes and insurance based on the price.
//
function estimateTaxIns(e, tab)
{
  var price = stripCommas(e.value);
  document.getElementById('prop_tax' + tab).value = addCommas((price*stdPropTax).toFixed(2));
  document.getElementById('ins' + tab).value = addCommas((price*stdIns).toFixed(2));
}

//
// Function to make sure user enters an extra payment date later than
// current date and not past the chosen term.
//
function validateExtraPayDate(e, tab)
{
  if (validateDate(e)) {
    // Make sure the extra payment date is later than today's date.
    var today = new Date();
    var ftoday = formatDate(today, 'MM/dd/yyyy');
    if (compareDates(ftoday, 'M/d/yyyy', e.value, 'M/d/yyyy') >= 0) {
      alert('The extra payment date must be later than today.');
      e.focus();
      e.select();
      return(false);
    }

    // Make sure the extra payment date is earlier than the end of
    // the loan term.
    var term = 1*document.getElementById('term' + tab).value;
    var y = (1*today.getFullYear())+term;
    var m = today.getMonth();
    var pay_date = m + '/1/' + y;
    if (compareDates(e.value, 'M/d/yyyy', pay_date, 'M/d/yyyy') >= 0) {
      alert('The extra payment date must be earlier than the end of the loan term.');
      e.focus();
      e.select();
      return(false);
    }
    return(true);
  }
  else {
    return(false);
  }
}

//
// Function to make visible/invisible the taxes and insurance inputs.
//
function showTI(e, tab)
{
  // Reset the input type of the taxes and insurance inputs based on
  // the value of the input flag.
  tax_e = document.getElementById('prop_tax' + tab);
  ins_e = document.getElementById('ins' + tab);
  if (e.value == 0) {
    tax_e.readOnly = true
    tax_e.className = 'number_noedit';
    ins_e.readOnly = true
    ins_e.className = 'number_noedit';
  }
  else {
    tax_e.readOnly = false;
    tax_e.className = 'number';
    ins_e.readOnly = false;
    ins_e.className = 'number';
  }
}

//
// Callback function to get a suggested interest rate.
// I have the pass the result back to a handler function because the
// rate is displayed in an input element.
//
function getRateCB()
{
  // Get the inputs fields based on the selected tab.
  var term_inp = 'term' + selectedTabNum;
  var res_inp = 'residency' + selectedTabNum;
  var dp_inp = 'dp%' + selectedTabNum;
  var price_inp = 'price' + selectedTabNum;

  // Strip any commas out of the price.
  var e = document.getElementById(price_inp);
  if (e && ((price = e.value) != '')) {
    price = stripCommas(e.value);
  }
  else {
    // If the user hasn't entered a price, give up now.
    return;
  }

  // If the user hasn't entered a down payment, assume it.
  // If I don't have a down payment input, use the stdDP.
  var dp = stdDP;
  var e =  document.getElementById(dp_inp);
  if (e) {
    if (e.value != '') {
      dp = e.value;
    }
    else {
      dp = stdDP;
    }
  }

  // Set the hidden loan amount input.
  document.getElementById('amount0').value = price*(1-dp/100);

  // Set the rest of the hidden inputs.
  document.getElementById('term0').value = document.getElementById(term_inp).value;
  document.getElementById('res0').value = document.getElementById(res_inp).value;
  document.getElementById('dp0').value = dp;
  var cout_inp = 'cashout_flag' + selectedTabNum;

  // Pass the term and residency to the perl function.
  getBrokerRate(['term0', 'res0', 'amount0', 'dp0', cout_inp], [handleGetRate]);
}

//
// Handler function for the getRateCB.
//
function handleGetRate()
{
  var rate = arguments[0];
  document.getElementById('rate' + selectedTabNum).value = (rate/1).toFixed(3);
}

//
// Callback function to execute the calculations.
//
function formSubmitCB()
{
  // Get the selected tab div.
  var tab_div = document.getElementById('p_' + selectedTab);

  // Check that all parameters have values.
  var dp_flag = 0;
  var inp_array = getElementsByClass('number', tab_div, 'input');
  for (var i = 0; i < inp_array.length; i ++) {
    if (inp_array[i].value == '') {
      // We'll allow either dp$ or dp% to be empty.
      if ((inp_array[i].id.indexOf('dp') == 0) &&
          (dp_flag == 0)) {
        dp_flag ++;
      }
      else {
        alert('Please enter a value in all boxes.');
        inp_array[i].focus();
        inp_array[i].select();
        return(false);
      }
    }
  }

  // Call the calculator corresponding to the selectedTab.
  switch(selectedTabNum) {
    // Payment calculator
    case 1:
      resultsPayment();
      break;

    // How much can I afford calculator
    case 2:
      resultsAfford();
      break;

    //
    case 3:
      resultsDebt();
      break;

    //
    case 4:
      resultsExtraPay();
      break;

    //
    case 5:
      resultsRefi();
      break;

    //
    case 6:
      resultsRent();
      break;
  }

  // Reset the class of the result elements to show that the results
  // are current.
  changeResultClass('result_changed', 'result', 'r_' + selectedTab);
  curResultsArray[selectedTabNum] = true;
}

// Helper function to reset the className of the result elements.
//
function staleResults(tab)
{
  // If the results already are stale, just return.
  if (curResultsArray[tab]) {
    changeResultClass('result', 'result_changed', 'r_' + selectedTab);
    curResultsArray[tab] = false;
  }
}

//
// Results function for payment tab.
//
function resultsPayment()
{
  // Get my input values.
  // Strip any commas out of the price.
  var price = stripCommas(document.getElementById('price' + selectedTabNum).value);
  var dp = document.getElementById('dp%' + selectedTabNum).value/100;
  var yrate = document.getElementById('rate' + selectedTabNum).value/1;
  var years = document.getElementById('term' + selectedTabNum).value/1;

  // Calculate my payment and apr.
  var principal = price*(1-dp);
  var payment = getPayment(principal, yrate, years).toFixed(2);
  var apr = getAPR(principal, yrate, years, stdPurchAprCC);

  // Display the results.
  // Also display the loan amount.
  document.getElementById('payment' + selectedTabNum).innerHTML = '$ ' + addCommas(payment) + ' ';
  document.getElementById('apr' + selectedTabNum).innerHTML = (apr/1).toFixed(3) + '%';
  document.getElementById('principal' + selectedTabNum).innerHTML = '$ ' + addCommas(Math.round(principal)) + ' ';
  document.getElementById('disclaim' + selectedTabNum).style.display='block';

  // Store the payment in the hidden input field.
  document.Calculator.payment0.value = payment;

  // The LTV is greater than 80%.  MI may be necessary.
  document.getElementById('mi_disclaimer').style.display = (dp < 0.2) ? 'block' : 'none';
}

//
// Results function for afford tab.
//
function resultsAfford()
{
  // Get my input values.
  var dp_per = document.getElementById('dp%' + selectedTabNum).value/100;
  var dp_amt = stripCommas(document.getElementById('dp$' + selectedTabNum).value)/1;
  var yrate = document.getElementById('rate' + selectedTabNum).value/1;
  var years = document.getElementById('term' + selectedTabNum).value/1;
  var inc = stripCommas(document.getElementById('income' + selectedTabNum).value)/1;
  var auto = stripCommas(document.getElementById('auto' + selectedTabNum).value)/1;
  var cc = stripCommas(document.getElementById('cc' + selectedTabNum).value)/1;
  var other = stripCommas(document.getElementById('loan' + selectedTabNum).value)/1;

  // Calculate the max mortgage payment based on the standard ratios.
  var max_front_pay = inc*stdFrontRatio/12;
  var max_back_pay = (inc*stdBackRatio/12)-(auto+cc+other);
  var max_pay = (max_front_pay < max_back_pay) ? max_front_pay : max_back_pay;

  // Account for the taxes and insurance.  Use the standard amounts.
  // Convert to monthly payment.
  max_pay /= (1+stdPropTax+stdIns);
  max_pay = (max_pay.toFixed(2))/1;
  document.getElementById('payment' + selectedTabNum).innerHTML = '$ ' + addCommas(max_pay) + ' ';
  document.Calculator.payment0.value = max_pay;

  // Our max mortgage amount is the PV of our payments over the term.
  var periods = 12*years;
  var rate = yrate/12/100;
  var max_loan = Math.round(getAnnuityPV(max_pay, rate, periods));
  document.getElementById('principal' + selectedTabNum).innerHTML = '$ ' + addCommas(max_loan) + ' ';

  // Use the down payment to determine the max home price.
  // Note that the user may have provided a down payment percentage or amount.
  if (dp_per > 0) {
    document.getElementById('value' + selectedTabNum).innerHTML = '$ ' + addCommas(Math.round(max_loan/(1-dp_per))) + ' ';
  } else {
    document.getElementById('value' + selectedTabNum).innerHTML = '$ ' + addCommas(Math.round(max_loan+dp_amt)) + ' ';
  }

  // Update the hidden loan amount input.
  document.Calculator.amount0.value = max_loan;

  // Get the APR.
  var apr = getAPR(max_loan, yrate, years, stdPurchAprCC);
  document.getElementById('apr' + selectedTabNum).innerHTML = (apr/1).toFixed(3) + '%';

  document.getElementById('disclaim' + selectedTabNum).style.display='block';

  // The LTV is greater than 80%.  MI may be necessary.
  document.getElementById('mi_disclaimer').style.display = (dp_per < 0.2) ? 'block' : 'none';
}

//
// Results function for debt tab.
//
function resultsDebt()
{
}

//
// Results function for extrapay tab.
//
function resultsExtraPay()
{
  // Get my input values.
  // Strip any commas out of the loan amount.
  var principal = stripCommas(document.getElementById('price' + selectedTabNum).value);
  var yrate = document.getElementById('rate' + selectedTabNum).value/1;
  var years = document.getElementById('term' + selectedTabNum).value/1;

  var mextra = stripCommas(document.getElementById('extra1').value)/1;
  var yextra = stripCommas(document.getElementById('extra2').value)/1;
  var extra1 = stripCommas(document.getElementById('extra3').value)/1;
  var extra_date = document.getElementById('extra3_date').value;

  // Calculate my payment.
  var payment = getPayment(principal, yrate, years).toFixed(2)/1;

  // Calculate in which period the user wants to make the extra payment.
  var xperiod = 0;
  if (extra1 > 0) {
    xperiod = getFuturePeriod(extra_date);
  }

  // Loop to figure out when the loan balance would reach 0.
  var balance = principal/1;
  var rate = yrate/1200;
  var periods = years*12;
  var tot_int = 0.0;

  for (var i = 1; (i <= periods) && (balance >= 0); i ++) {
    var interest = ((balance*rate).toFixed(2))/1;
    balance -= (mextra+payment-interest);
    tot_int += interest/1;

    // If this is the end of a year, add any extra yearly payment.
    if ((i % 12) == 0) {
      balance -= yextra;
    }

    // If this is the period for the extra payment, add it.
    if (i == xperiod) {
      balance -= extra1;
    }
  }

  // Determine the pay off date.
  var today = new Date();
  var pm = today.getMonth();
  var py = today.getFullYear();

  pm += (i % 12);
  if (pm > 12) {
    pm -= 12;
    py ++;
  }
  i --;
  py += Math.floor(i/12);
  var payoff = formatDate(new Date(pm + '/1/' + py), 'NNN yyyy');

  // Display the results.
  // Also display the loan amount.
  document.getElementById('payment' + selectedTabNum).innerHTML = '$ ' + addCommas(payment) + ' ';
  document.getElementById('payoff' + selectedTabNum).innerHTML = payoff + ' ';
  document.getElementById('periods' + selectedTabNum).innerHTML = (periods-i) + ' ';
  document.getElementById('disclaim' + selectedTabNum).style.display='block';

  // Store the loan payment and payment in the hidden input field.
  document.Calculator.amount0.value = principal;
  document.Calculator.payment0.value = payment;
}

//
// Results function for refi tab.
//
function resultsRefi()
{
  // Get my input values.
  // Strip any commas out of the dollar amounts.
  var balance = stripCommas(document.getElementById('balance' + selectedTabNum).value)/1;
  var old_payment = stripCommas(document.getElementById('old_payment' + selectedTabNum).value)/1;
  var dp = document.getElementById('dp%' + selectedTabNum).value/100;
  var yrate = document.getElementById('rate' + selectedTabNum).value/1;
  var years = document.getElementById('term' + selectedTabNum).value/1;

  // The current payment includes taxes and insurance.
  // Subtract the taxes and insurance from the old payment.
  var ti_flag = document.getElementById('ti_flag' + selectedTabNum).value;
  if (ti_flag == 1) {
    var tax = document.getElementById('prop_tax' + selectedTabNum).value/12;
    var ins = document.getElementById('ins' + selectedTabNum).value/12;
    old_payment -= (tax+ins);
  }

  // Let's roll the closing costs into the new loan for calculating title fees.
  // Multiply by 1.01 to account for the origination fee.
  var principal = 1.01*(balance+stdRefiAprCC+stdNonAprCC);

  // The title fees depend on how old the existing title policy is.
  var closed = document.getElementById('close_year' + selectedTabNum).value;
  var today = new Date();
//  var this_year = today.toLocaleFormat("%Y");
  var this_year = today.getFullYear();
  var diff = (this_year/1)-(closed/1);
  var title = getTitleFees(principal, balance, diff, 0);

  // Now, compute the actual new loan amount to include
  // the title costs and prepaid interest.
  principal += (title.toFixed(2))/1+((15*principal*yrate/(365*100)).toFixed(2))/1;

  // Calculate my payment and apr.
  var payment = getPayment(principal, yrate, years).toFixed(2);
  var apr = getAPR(principal, yrate, years, stdRefiAprCC);

  // Display the results.
  document.getElementById('payment' + selectedTabNum).innerHTML = '$ ' + addCommas(payment) + ' ';
  document.getElementById('apr' + selectedTabNum).innerHTML = (apr/1).toFixed(3) + '%';

  // Store the payment and loan amount in the hidden input fields.
  document.Calculator.payment0.value = payment;
  document.Calculator.amount0.value = principal;

  // The LTV is greater than 80%.  MI may be necessary.
  document.getElementById('mi_disclaimer').style.display = (dp < 0.2) ? 'block' : 'none';

  // The new payment is greater than the old.
  if (payment >= old_payment) {
    // Display the 'hi' disclaimer.
    document.getElementById('disclaim_hi' + selectedTabNum).style.display='block';
    document.getElementById('disclaim_lo' + selectedTabNum).style.display='none';

    // Set the savings to 0.
    document.getElementById('diff' + selectedTabNum).innerHTML = '$ 0';
    document.getElementById('even' + selectedTabNum).innerHTML = '&nbsp;';
  }
  else {
    // Iterate to find the payment after which our new payment has paid off
    // our closing costs.  Seed the periods iterator with the dividend of
    // the balance difference and the payment difference.  Our present value
    // calculation uses the standard discount rate.
    var diff_pay = old_payment-payment;
    var diff_bal = principal-balance;
    var periods = 12*years;
    var mrate = stdDiscountRate/12/100;

    var eff_periods = diff_bal/diff_pay;
    var count = 25;
    var effPV;

    while ((count -- > 0) &&
           (Math.abs(diff_bal-(effPV = getAnnuityPV(diff_pay, mrate, eff_periods))) > 1.0)) {
       eff_periods *= 1-(effPV-diff_bal)/diff_bal;
    }

    eff_periods = Math.ceil(eff_periods);

    // Show the savings and months to pay off.
    document.getElementById('diff' + selectedTabNum).innerHTML = '$ ' + (diff_pay/1).toFixed(2) + ' ';
    document.getElementById('even' + selectedTabNum).innerHTML = eff_periods + ((eff_periods == 1) ? ' month' : ' months');

    // Display the 'lo' disclaimer.
    document.getElementById('disclaim_hi' + selectedTabNum).style.display='none';
    document.getElementById('disclaim_lo' + selectedTabNum).style.display='block';

    // Show the payment without absorbing closing costs.
    var pay2 = getPayment(balance, yrate, years);
    document.getElementById('payment_lo' + selectedTabNum).innerHTML = addCommas((pay2/1).toFixed(2));
  }
}

//
// Results function for rent tab.
//
function resultsRent()
{
  // Get my input values.
  // Strip any commas out of the dollar amounts.
  var price = stripCommas(document.getElementById('price' + selectedTabNum).value)/1;
  var dp = document.getElementById('dp%' + selectedTabNum).value/100;
  var yrate = document.getElementById('rate' + selectedTabNum).value/1;
  var years = document.getElementById('term' + selectedTabNum).value/1;
  var rent = stripCommas(document.getElementById('rent' + selectedTabNum).value)/1;
  var tax_rate = document.getElementById('inc_tax' + selectedTabNum).value/100;
  var app_rate = document.getElementById('app_rate' + selectedTabNum).value/12/100;
  var inv_rate = document.getElementById('inv_rate' + selectedTabNum).value/12/100;
  var inf_rate = document.getElementById('inf_rate' + selectedTabNum).value/12/100;
  var tax = stripCommas(document.getElementById('prop_tax' + selectedTabNum).value)/12;
  var ins = stripCommas(document.getElementById('ins' + selectedTabNum).value)/12;
  var move = stripCommas(document.getElementById('move' + selectedTabNum).value)/1;

  // Calculate the principal and total closing costs.
  var principal = Math.round(price*(1-dp));
  var cc = stdPurchAprCC+stdNonAprCC+(principal*0.01)+((15*principal*yrate/(365*100)).toFixed(2))/1;

  // Calculate my payment and apr.
  var payment = getPayment(principal, yrate, years).toFixed(2);
  var apr = getAPR(principal, yrate, years, stdPurchAprCC);

  // Display the results.
  document.getElementById('payment' + selectedTabNum).innerHTML = '$ ' + addCommas(payment) + ' ';
  document.getElementById('apr' + selectedTabNum).innerHTML = (apr/1).toFixed(3) + '%';

  // Store the payment in the hidden input field.
  document.Calculator.payment0.value = payment;

  // The LTV is greater than 80%.  MI may be necessary.
  document.getElementById('mi_disclaimer').style.display = (dp < 0.2) ? 'block' : 'none';

  // Seed the break even periods based on the ratio that includes the closing
  // costs and the mortgage and rent payments.
  var mmove = move*12;
  var eff_periods = Math.min(Math.ceil(cc/(rent-(payment*0.8))), mmove);

  // First, calculate the PV of the buy terms.
  // Use a standard number for maintenance costs.
  var mrate = yrate/12/100;
  var init_costs = cc+(price*dp);
  var maint = stdMaint*price/12;
  var buy_pv = calcBuyPV(price, principal, init_costs, payment, eff_periods, mrate, inf_rate, app_rate, tax_rate, ins, tax, maint);

  // Now, let's calculate the PV of the rent terms.
  // Assume I'll have the init_costs for savings.
  var rent_pv = calcRentPV(rent, init_costs, eff_periods, inf_rate, inv_rate);

  // Iterate to find the payment after which our mortgage is cheaper
  // than renting.
  var count = 25;
  var effPV;

  while ((count -- > 0) &&
         (Math.abs(rent_pv-buy_pv) > 1.0)) {
    eff_periods *= 1+(buy_pv-rent_pv)/rent_pv;

    buy_pv = calcBuyPV(price, principal, init_costs, payment, eff_periods, mrate, inf_rate, app_rate, tax_rate, ins, tax, maint);
    rent_pv = calcRentPV(rent, init_costs, eff_periods, inf_rate, inv_rate);
  }

  eff_periods = Math.ceil(eff_periods);

  // Calculate the buy and rent PVs when the user plans to move.
  // Show the user the savings.
  buy_pv = calcBuyPV(price, principal, init_costs, payment, mmove, mrate, inf_rate, app_rate, tax_rate, ins, tax, maint);
  rent_pv = calcRentPV(rent, init_costs, mmove, inf_rate, inv_rate);
  var save = rent_pv-buy_pv;

  // The break even periods exceeds our loan term.
  // Thus, it is better to rent than buy.
  if ((eff_periods > mmove) || (eff_periods < 0)) {
    // Display the 'lo' disclaimer.
    document.getElementById('move_hi' + selectedTabNum).innerHTML = move;
    document.getElementById('savings_hi' + selectedTabNum).innerHTML = addCommas(Math.round(-save/1));
    document.getElementById('disclaim_lo' + selectedTabNum).style.display='none';
    document.getElementById('disclaim_hi' + selectedTabNum).style.display='block';
    document.getElementById('even' + selectedTabNum).innerHTML = '&nbsp;'
  }
  else {
    // Display the break even months.
    document.getElementById('even' + selectedTabNum).innerHTML = eff_periods + ((eff_periods == 1) ? ' month' : ' months');

    // Display the 'lo' disclaimer.
    document.getElementById('move_lo' + selectedTabNum).innerHTML = move;
    document.getElementById('savings_lo' + selectedTabNum).innerHTML = addCommas(Math.round(save/1));
    document.getElementById('disclaim_hi' + selectedTabNum).style.display='none';
    document.getElementById('disclaim_lo' + selectedTabNum).style.display='block';
  }
}

//
// Helper function to calculate the buy PV.
//
function calcBuyPV(price, principal, init_costs, payment, periods, mrate, inf_rate, app_rate, tax_rate, ins, tax, maint)
{
  // We're going to assume insurance escalates at the inflation rate.
  // Thus, we don't need to PV it.  Also assume the maintenance escalates
  // at the inflation rate.  The taxes escalate at the appreciation rate
  // and get discounted at the inflation rate.
  var tot_mort = getPV((payment*periods), inf_rate, periods);
  var tot_ins = ins*periods;
  var maint = maint*periods;
  var tot_tax = tax*periods*Math.pow(1+app_rate, periods);
  tot_tax = getPV(tot_tax, inf_rate, periods);

  // To calculate our equity, we need to know the loan balance.
  // Then, apply the appreciation rate to the price, then PV it.
  // Assume the seller will pay realtor commissions to sell.
  var loan = getLoanBalance(principal, payment, mrate, periods);
  var equity = ((price*Math.pow(1+app_rate, periods))*(1-stdRealtorComm))-loan.balance;
  equity = getPV(equity, inf_rate, periods);

  // To calculate the income tax savings, I simply going to assume I have
  // total interest at some point in the future.  This is an approximation
  // because we actually pay more interest in the early years.  Thus, the
  // PV would be a bit larger.  Add the PV of the property taxes because
  // they also are deductible.
  var savings = getPV(loan.interest, inf_rate, periods);
  savings += (tax/1);
  savings *= tax_rate;

  // Add it all up.
  var pv = init_costs+tot_mort+tot_ins+maint+tot_tax-(equity+savings);

  return(pv);
}

//
// Helper function to calculate the rent PV.
//
function calcRentPV(rent, init_costs, periods, inf_rate, inv_rate)
{
  // Assume a standard of one month deposit.  The deposit doesn't grow, so
  // discount the returned deposit amount.  Assume the rent escalates at
  // the inflation rate, so I don't need to PV it.
  var dep = rent;
  var tot_rent = rent*periods;
  var ret_dep = getPV(dep, inf_rate, periods);

  // Assume we're saving the difference between the mortgage init_costs
  // and the rent initial costs, the deposit, at the inv_rate.  Use an
  // effective rate that subtracts out the inflation rate.
  var save = (init_costs-dep)*(Math.pow(1+(inv_rate-inf_rate), periods)-1);

  // Add it all up.
  var pv = dep+tot_rent-(ret_dep+save);

  return(pv);
}

//
// Helper function to calculate the loan balance and total interest paid
// at a given period in the future.
//
function getLoanBalance(principal, payment, rate, periods)
{
  var balance = principal;
  var tot_int = 0.0;
  payment = payment/1;

  for (var i = 0; i < periods; i ++) {
    var interest = ((balance*rate).toFixed(2))/1;
    balance -= (payment-interest);
    tot_int += interest/1;
  }

  return{balance : balance, interest : tot_int};
}

//
// Helper function to calculate the MI.
//
function calcMI()
{
}

//
// Callback function to create an amortization table for the results.
// The table is displayed in a popup window.
//
function showAmortTableCB()
{
  // Get the parameters for calculating the amortization table.
  // Strip commas and dollar signs, as necessary.
  var amount = stripCommas(document.Calculator.amount0.value);
  var term = document.Calculator.term0.value;
  var rate = document.getElementById('rate' + selectedTabNum).value;
  var payment = document.Calculator.payment0.value;

  // If the user has selected the extra payment tab,
  // grab the extra payment parameters.
  var xm = 0;
  var xy = 0;
  var x1 = 0;
  var xperiod = 0;
  if (selectedTabNum == 4) {
    xm = stripCommas(document.getElementById('extra1').value);
    xy = stripCommas(document.getElementById('extra2').value);
    x1 = stripCommas(document.getElementById('extra3').value);
    var x_date = document.getElementById('extra3_date').value;

    if (x1 > 0) {
      xperiod = getFuturePeriod(x_date);
    }
  }

  // Trap if the parameters I need haven't been entered.
  if ((amount == '') || (term == '') || (rate == '') || (payment == '')) {
   alert("I need more information to be able to calculate\nthe amortization table for you.");
  }

  // Append the parameters needed to calculate the amortization table
  // onto the end of the query string.
  else {
    window.open("/cgi-bin/CalcAmortTable.pl?amount=" + amount + "&term=" + term + "&rate=" + rate + "&payment=" + payment + "&xpay_m=" + xm + "&xpay_y=" + xy + "&xpay_1=" + x1 + "&xperiod=" + xperiod);
  }

  return(false);
}

function getAPR(principal, yrate, years, fixedCosts)
{
  // Use standard numbers for closing costs.
  var cc = fixedCosts+(0.01*principal);
  var points = 0.0;

  // Add 15 days interest to the closing costs.
  cc += (15*principal*yrate/(365*100));

  var periods = 12*years;
  var rate = yrate/12/100;
  var fc = (points*principal/100) + cc;

  var effLoan = principal+fc;
  var effPay = effLoan/getAnnuityPV(1, rate, periods);

  // Iterate to get the APR.
  var count = 25;
  var effPV;
  var x = rate;

  while ((count -- > 0) &&
         (Math.abs(principal - (effPV = getAnnuityPV(effPay, x, periods))) > 5e-5)) {
    x *= 1+(effPV-principal)/principal;
  }

  var apr = roundFloat(1200*x-0.0005, 3);

  return(apr);
}

//
// This is an annuity PV formula.
//
function getAnnuityPV(payment, rate, periods)
{
  var pv = (Math.abs(rate) > 1e-20) ? (payment*(1-Math.pow(1+rate, -periods))/rate) : (payment * periods);
  return(pv);
}

//
// This is a straight PV formula.
//
function getPV(fv, rate, periods)
{
  var pv = fv/(Math.pow(1+rate, periods));
  return(pv);
}

function getPayment(principal, yrate, years)
{
  var rate = yrate/(12*100);
  var periods = years*12;
  var payment = (principal*rate)/(1-Math.pow((1+rate), (-1*periods)));

  return(payment);
}

function getFuturePeriod(fdate)
{
  var fd = new Date(fdate);
  var fm = fd.getMonth()/1;
  var fy = fd.getFullYear()/1;

  var today = new Date();
  var tm = today.getMonth()/1;
  var ty = today.getFullYear()/1;

  xperiods = (fy-ty)*12+(fm-tm);

  return(xperiods);
}

function roundFloat(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 ;
   if (iD > 0)
      nFp = Math.round(nFp * Power(iD)) / Power(iD) ;
   nVal = iSign * (iInt + nFp) ;
   return nVal ;
}

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