var CascadeCalc = (function() {
    var $form;
    
    var data = {
        rates : {
            national_insurance : {
                employee : {
                    lower : 12,
                    upper : 2
                },
                employer : 13.8
            },
            income_tax : {
                basic : 20,
                higher : 40,
                additional : 50
            }
        },
        allowances : {
            personal : 7475
        },
        limits : {
            income_tax : {
                basic_rate : 35000,
                higher_rate : 150000
            },
            national_insurance : {
                lower : 102,
                upper : 817,
                primary_threshold : 139,
                secondary_threshold : 136
            },
            income : 100000
        }
    }
    
    var personal_allowance = function(annual_income) {
        var allowance = data.allowances.personal;
        
        annual_income = Math.round(annual_income);
        
        if (annual_income > data.limits.income) {
            allowance -= (annual_income - data.limits.income) / 2
        }
        
        return Math.max(allowance, 0);
    }
    
    var taxable_wage = function(gross_wage, expenses) {
        var last     = gross_wage;
        var current  = 0;
        var converge = 0.001;
        var limit    = 100;
        
        gross_wage = Math.round(gross_wage);
        expenses   = Math.round(expenses || 0);
        
        while (Math.abs(current - last) > converge && --limit > 0) {
            last    = current;
            current = Math.round((gross_wage - expenses - last - data.limits.national_insurance.secondary_threshold * 52)
                * data.rates.national_insurance.employer) / 100;
        }
        
        return Math.round((gross_wage - expenses - Math.max(0, current)) * 100) / 100;
    }
    
    var income_tax = function(gross_wage) {
        var taxable     = Math.max(gross_wage - personal_allowance(gross_wage), 0);
        
        var basic_rate      = Math.round(Math.min(taxable, data.limits.income_tax.basic_rate)
            * data.rates.income_tax.basic) / 100;
        var higher_rate     = Math.round((Math.min(taxable, data.limits.income_tax.higher_rate)
            - data.limits.income_tax.basic_rate) * data.rates.income_tax.higher) / 100;
        var additional_rate = Math.round((taxable - data.limits.income_tax.higher_rate)
            * data.rates.income_tax.additional) / 100;
        
        return Math.round((Math.max(0, basic_rate) + Math.max(0, higher_rate) + Math.max(0, additional_rate)) * 100) / 100;
    }
    
    var national_insurance = function(gross_wage) {
        var standard = Math.round((Math.min(gross_wage, data.limits.national_insurance.upper * 52)
            - data.limits.national_insurance.primary_threshold * 52) * data.rates.national_insurance.employee.lower) / 100;
        var upper    = Math.round((gross_wage - data.limits.national_insurance.upper * 52)
            * data.rates.national_insurance.employee.upper) / 100;
        
        return Math.round((Math.max(0, standard) + Math.max(0, upper)) * 100) / 100;
    }
    
    var net_annual_wage = function(gross_wage, expenses) {
        var taxable = taxable_wage(gross_wage, expenses);
        var tax = income_tax(taxable);
        var ni  = national_insurance(taxable);
        
        return Math.round((taxable - tax - ni) * 100) / 100;
    }
    
    return {
        init: function() {
            $form = $('#salary-calculator');
            
            $('#salary-calculator-submit').bind('click', function() {
                var form_data = {};
                var gross_wage, deductions, expenses, net_salary, taxable, tax, ni, received;

                $.each($form.serializeArray(), function(_, kv) {
                    form_data[kv.name] = kv.value;
                });

                gross_wage = ((parseFloat(form_data.salary) * parseInt(form_data.salary_multiplier, 10) * 52) || 0);
                deductions = ((parseFloat(form_data.deductions) * parseInt(form_data.deductions_multiplier, 10)) || 0);
                expenses   = ((parseFloat(form_data.expenses_1) * parseInt(form_data.expenses_1_multiplier, 10)) || 0);
                expenses  += ((parseFloat(form_data.expenses_2) * parseInt(form_data.expenses_2_multiplier, 10)) || 0);
                expenses  += ((parseFloat(form_data.expenses_3) * parseInt(form_data.expenses_3_multiplier, 10)) || 0);
                expenses  += ((parseFloat(form_data.expenses_4) * parseInt(form_data.expenses_4_multiplier, 10)) || 0);
                
                taxable    = taxable_wage(gross_wage, deductions + expenses);
                tax        = income_tax(taxable);
                ni         = national_insurance(taxable);
                net_salary = net_annual_wage(gross_wage, deductions + expenses);
                received   = Math.round((net_salary + expenses) * 100) / 100;
                
                $('#result-taxable-salary').text(taxable.toFixed(2));
                $('#result-income-tax').text(tax.toFixed(2));
                $('#result-national-insurance').text(ni.toFixed(2));
                $('#result-net-salary').text(net_salary.toFixed(2));
                $('#result-total-received').text(received.toFixed(2));
                
                return false;
            });
        }
    }
})();

$(document).ready(function() {
    CascadeCalc.init();
});

