// $Header: /web/src/rsearch/web/js/mortgageCalculator.js,v 1.3 2009/03/03 23:58:09 ahope Exp $

REA.MortgageCalculator = (function () {

    var DEFAULTS = {
        LOAN               : 200000,
        // NOTE: MUST ALSO UPDATE /web/js/rea/common.js AT THE SAME TIME
        INTEREST_RATE      : parseFloat(window.MORTGAGE_CALC_IR || 5.74),
        TERM               : 25,
        REPAYMENT_FREQUENCY: 'monthly',
        MAX_TERM           : 30
    };

    var repaymentsPerYear = {
        monthly    : 12,
		quarterly  : 4,
        fortnightly: 26,
        weekly     : 52
    };

    var LOAN,
        INTEREST_RATE,
        TERM,
        REPAYMENT_TYPE,
        CALC_EL;

    // Financial Calculations

    var calculatePayment = function (PV, IR, NP) {
        IR = formatInterestRate(IR);
        var PMT = (PV * IR) / (1 - Math.pow(1 + IR, -NP));
        return roundDecimals(PMT, 2);
    };

    var calculateBalance = function (PMT, IR, NP) {
        IR = formatInterestRate(IR);
        var PV = PMT * (1 - Math.pow(1 + IR, -NP)) / IR;
        return roundDecimals(PV, 2);
    };

    var calculateInterest = function (principal, IR) {
        IR = formatInterestRate(IR);
        return principal * IR;
    };

    var roundDecimals = function (num, decimals) {
        return (num * 1).toFixed(decimals);
    };

    var formatInterestRate = function (interestRate) {
        return stringToNumber(interestRate) / 100;
    };

    // Utility functions

    var openWindow = function () {
        window.open(this.href);
        return false;
    };

    var getParams = function () {
        var params, tmp, i,
            queryString = window.location.search,
            paramObj    = {};
        if (!queryString) {
            return;
        }
        params  = queryString.substring(1).split('&');
        i       = params.length;
        while (i--) {
            tmp = params[i].split('=');
            paramObj[tmp[0]] = tmp[1];
        }
        return paramObj;
    };

    var formatCurrency = function (a) {
        var amount = parseFloat(stringToNumber(a)),
            rgx = /(\d+)(\d{3})/,
            s;
        if (isNaN(amount)) {
            amount = 0.00;
        }
        amount = amount.toFixed(2);
        s = (amount).toString();
        while (rgx.test(s)) {
            s = s.replace(rgx, '$1' + ',' + '$2');
        }
        if (s.indexOf('$') < 0) {
            s = '$' + s;
        }
        return s;
    };

    var stringToNumber = function (s) {
        return (typeof s === 'string') ? parseFloat(s.replace(/[^\.\d]/g, '')) : s;
    };

    var validateLoanTerm = function (term) {
        term = parseInt(term, 10);
        return stringToNumber((term > DEFAULTS.MAX_TERM) ? DEFAULTS.MAX_TERM : term);
    };

    var setFormInputs = function () {
        // NOTE: calculate display value
        var displayLoan = formatCurrency(LOAN);
        // NOTE: Update inputs
        $J('#controls #loanAmount', CALC_EL).val(displayLoan);
        $J('#controls #interestRate', CALC_EL).val(INTEREST_RATE);
        $J('#controls #loanTerm', CALC_EL).val(TERM);
        $J('#controls #repaymentFrequency', CALC_EL).val(REPAYMENT_FREQUENCY);
        // TODO: set REPAYMENT_TYPE, default = full
    };

    var getFormInputs = function () {
        var displayLoan     = $J('#controls #loanAmount', CALC_EL).val(),
            displayInterest = $J('#controls #interestRate', CALC_EL).val(),
            displayTerm     = $J('#controls #loanTerm', CALC_EL).val();
        LOAN                = stringToNumber(displayLoan);      // NOTE: Validation
        TERM                = validateLoanTerm(displayTerm);    // NOTE: Validation
        REPAYMENT_FREQUENCY = $J('#controls #repaymentFrequency option:selected', CALC_EL).val();
        REPAYMENT_TYPE      = $J('#controls #repaymentType option:selected', CALC_EL).val();
        INTEREST_RATE       = stringToNumber(displayInterest);
        PPY                 = repaymentsPerYear[REPAYMENT_FREQUENCY.toLowerCase()];
        TOTAL_PAYMENTS      = TERM * PPY;
    };

    // Setup
    var initCalculator = function () {
        //var urlParams = getParams(); // TODO: handle no param situation
        //LOAN                = urlParams.amount                  || DEFAULTS.LOAN;
        //TERM                = validateLoanTerm(urlParams.years) || DEFAULTS.TERM;
        //INTEREST_RATE       = urlParams.interest                || DEFAULTS.INTEREST_RATE;
        //REPAYMENT_FREQUENCY = urlParams.frequency               || DEFAULTS.REPAYMENT_FREQUENCY;
		LOAN = 300000;
		TERM = 30;
		INTEREST_RATE = 5.81;
		REPAYMENT_FREQUENCY = 12;
        setFormInputs();
        renderGraph();
    };

    // Graphing

    var yaxisFormatter = function (val, axis) {
        if (val >= 100000) {
            return '<span style="color:white;">$' + (val / 1000).toFixed(axis.tickDecimals) + ' K</span>';
        } else {
            return '<span style="color:white;">$' + val.toFixed(axis.tickDecimals) + '</span>';
        }
    };

    var xaxisFormatter = function (val, axis) {
        return '<span style="color:white;">' + val.toFixed(axis.tickDecimals) + ' Years</span>';
    };

    var graphingOpts = {
        points: {show: true},
        lines : {show: true},
        grid  : {hoverable: true},
        xaxis : {tickFormatter: xaxisFormatter},
        yaxis : {tickFormatter: yaxisFormatter},
        grid  : {backgroundColor: '#FFF'}
    };

    var renderFull = function () {

        var totalData     = [],
            principalData = [],
            interestData  = [],
            i,
            j,
            principal,
            payment,
            total,
            amountOwed,
            graphData,
            ci = 0;

        // NOTE: used for display only
        var displayInterestTotal,
            displayPayment;

        payment = calculatePayment(LOAN, INTEREST_RATE / PPY, TOTAL_PAYMENTS);
        total   = amountOwed = payment * TOTAL_PAYMENTS;

        // NOTE: inital values
        totalData.push([0, total]);
        principalData.push([0, LOAN]);
        interestData.push([0, ci]);

        // NOTE: calculate results
        for (i = 1; i <= TOTAL_PAYMENTS; i++) {

            termRemaining = TOTAL_PAYMENTS - i;
            amountOwed    = amountOwed - payment;
            principal     = calculateBalance(payment, INTEREST_RATE / PPY, termRemaining);
            ci            += calculateInterest(principal, INTEREST_RATE);
            // NOTE: only plot points once per year
            if (!(termRemaining % PPY)) {
                j = i / PPY;
                totalData.push([j, amountOwed]);
                principalData.push([j, principal]);
                interestData.push([j, ci]);
            }
        }

        // NOTE: Due to rounding errors the last payment can cause the totalData to go below 0
        // this resets it as this should not be possible and the rounding is unlikely to be out
        // by more than a few dollars
        if (totalData[totalData.length - 1][1] < 0) {
            totalData[totalData.length - 1][1] = 0;
        }

        graphData = [
            {label: 'Total', data: totalData},
            {label: 'Principal', data: principalData}
        ];

        // NOTE: Update UI

        displayInterestTotal = formatCurrency(roundDecimals(total - LOAN, 2));
        displayPayment       = formatCurrency(roundDecimals(payment, 2));

        $J.plot($J('#graph', CALC_EL), graphData, graphingOpts);
        $J('#repayments', CALC_EL).html('<strong>' + REPAYMENT_FREQUENCY + ' repayment ' + displayPayment + '</strong>');
        $J('#totalInterest', CALC_EL).html('Total Interest payable ' + displayInterestTotal);

    };

    var renderInterestOnly = function () {

        var totalData     = [],
            principalData = [],
            i,
            j,
            principal,
            payment,
            total,
            amountOwed,
            graphData,
            ci = 0;

        // NOTE: These variables are used for display only
        var displayLoan,
            displayPayment,
            totalInterestRepayable;

        // cumulative interest
        for (i = 1; i <= TERM; i++) {
            ci += calculateInterest(LOAN, INTEREST_RATE);
        }

        total      = ci;
        amountOwed = ci + LOAN;
        payment    = ci / TOTAL_PAYMENTS;

        // NOTE: Set inital values
        principalData.push([0, LOAN]);
        totalData.push([0, amountOwed]);

        for (i = 1; i <= TERM; i++) {
            amountOwed = amountOwed - (payment * PPY);
            principalData.push([i, LOAN]);
            totalData.push([i, amountOwed]);
        }

        graphData = [
            {label: 'Total', data: totalData},
            {label: 'Principal', data: principalData}
        ];

        // Update UI
        displayPayment         = formatCurrency(roundDecimals(payment, 2));
        totalInterestRepayable = formatCurrency(roundDecimals(ci, 2));
        $J.plot($J('#graph', CALC_EL), graphData, graphingOpts);
        $J('#repayments', CALC_EL).html('<strong>' + REPAYMENT_FREQUENCY + ' repayment ' + displayPayment + '</strong>');
        $J('#totalInterest', CALC_EL).html('Total Interest payable ' + totalInterestRepayable);
    };

    var renderGraph = function () {
        // NOTE: validates and cleans input
        getFormInputs();
        setFormInputs();
        switch (REPAYMENT_TYPE) {
        case 'full':
            renderFull();
            break;
        case 'interest_only':
            renderInterestOnly();
            break;
        default:
            return false;
        }
    };

    return {
        init : function () {
            if ($J('#mortgageCalcFullWrapper').length > 0) {
                CALC_EL = $J('#mortgageCalcFull');
                $J('#controls #recalculate', CALC_EL).click(renderGraph);
                $J('a[rel*="external"]').click(openWindow);
                $J('#print', CALC_EL).click(function () {
                    print();
                    return false;
                });
                initCalculator();
            }
        }
    };

})();

$J(document).ready(function () {
    REA.MortgageCalculator.init();
});

