// calculate the tax based on the income, the income bands,
// and the corresponding tax rates
function auxCalcTax(income, bands, rates) {
    
    var remainingIncome = income;
    var tax = 0;
    
    for (var i = 0; i != bands.length; i++) {
        var currentBand = Math.min(bands[i], remainingIncome);
        remainingIncome -= currentBand;
        tax += currentBand * rates[i];
    }
    
    return tax;
}

// Follow a binary search (recursive) algorith to find the correct taxable amount
function findTaxable(min, max, net, year, numChildren) {

    // First, use the mid-point to get a calculated net salary
    var gross = (min + max) / 2;
    var calculatedNet = Math.round((gross -
            0.985 * calcTax(gross, year, numChildren)) * 10) / 10;
    
    // Then, check which side of the calculated net salary our actaul net salary falls
    if (calculatedNet > net) {    // We're too high - keep the min, adjust the max
        return findTaxable(min, gross, net, year, numChildren);
    }
    
    if (calculatedNet < net) {    // We're too low - keep the max, adjust the min
        return findTaxable(gross, max, net, year, numChildren);
    }
    
    return gross;
}

// calculate the tax based on income, tax year and number of dependent children
function calcTax(income, year, numChildren) {
    var taxScale =  selectTaxRates(year);
    
    taxScale[0] = adjustForChildren(taxScale[0].slice(), numChildren);
    
    return auxCalcTax(income, taxScale[0], taxScale[1]);
}

// calculate the taxable income based on net income, tax year
// and number of dependent children
function invCalcTaxable(net, year, numChildren) {
    var taxScale = selectTaxRates(year);
    var topRate  = taxScale[1][taxScale[1].length -1];
    
    return findTaxable(net, net / topRate, net, year, numChildren);
    
}

// returns an array containing two arrays: tax bands (income) & tax rates (%)
function selectTaxRates(year) {
    switch (year) {
        case 2006: return [[11000,  2000, 10000, Infinity],
                            [0, 0.15, 0.30, 0.4]];
        case 2007: return [[12000, 18000, 45000, Infinity],
                            [0, 0.29, 0.39, 0.4]];
        case 2008: return [[12000, 18000, 45000, Infinity],
                            [0, 0.27, 0.37, 0.4]];
        case 2009: return [[12000, 18000, 45000, Infinity],
                            [0, 0.25, 0.35, 0.4]];
        case 2010: return [[12000, 4000, 6000, 4000, 6000, 8000, 20000, 40000, Infinity],
                            [0, 0.18, 0.24, 0.26, 0.32, 0.36, 0.38, 0.4, 0.45]];
   }
}

// Adjust the income bands based on the number o dependent children
// 'incomeΒands' is an array passed byVal
function adjustForChildren(incomeΒands, numChildren) {
    var adjustment = numChildren * 1000;    // an extra E1000 per child
    if (numChildren > 2) {    
        adjustment += 7000;    // E10000 at 3 children (+1000/child after that)
    }
    
    incomeΒands[0] += adjustment;
    
    for (var i = 1; i != incomeΒands && adjustment != 0; i++) {
        var delta = Math.min(incomeΒands[i], adjustment);
        incomeΒands[i] -= delta;
        adjustment -= delta;
    }
    
    return incomeΒands;
}

// Calculate the IKA contribution based on the gross salary, the tax year,
// whether the employee is an "old" insured person, and the IKA rate
function calcIKA(grossSalary, year, isOld, rate) {
    var cappedIncome;
    
    if (isOld) {
        switch (year) {
            case 2006: cappedIncome = 26712.00; break;
            case 2007: cappedIncome = 27780.00; break;
            case 2008: cappedIncome = 28757.25; break;
            case 2009: cappedIncome = 29187.00; break;
            case 2010: cappedIncome = 29187.00; break;
        }
    } else {
        switch (year) {
            case 2006: cappedIncome = 71071.14; break;
            case 2007: cappedIncome = 73913.98; break;
            case 2008: cappedIncome = 76553.80; break;
            case 2009: cappedIncome = 76553.80; break;
            case 2010: cappedIncome = 76553.80; break;      
        }
    }
    
    return rate * Math.min(grossSalary, cappedIncome);
}

// ignores surcharge
function calcMonthlyTSMEDE(monthlyGross, year, isOld, isFiveYears) {
    var healthMin  = 693.35;
    var healthMax  = isOld ? 2432.25 : 5546.80;
    var otherMax   = isOld ? 2080.00 : 5546.80;
    var otherMin   = 693.35;
    var mainRate   = isFiveYears ? 0.1367 : 0.0884;
    var healthRate = 0.0215;
    
    var payment = mainRate   * Math.max(Math.min(monthlyGross, otherMax), otherMin) +
            healthRate * Math.max(Math.min(monthlyGross, healthMax), healthMin);
    
    return payment + getMonthlyTSMEDESurcharge(isOld);
}

function adjustAnnualTSMEDE(isOld) {
    return getMonthlyTSMEDESurcharge(isOld) * 2;
}

function getMonthlyTSMEDESurcharge(isOld) {
    return isOld ? 83.20 : 58.24;
}

// Calculate the IKA contribution based on the *taxable* salary, the tax year
// and whether the employee is an "old" insured person
function invCalcIKA(taxableSalary, year, isOld, rate) {
    return calcIKA(taxableSalary / (1 - rate), year, isOld, rate);
}

function invCalcMonthlyTSMEDE(taxableMonthlySalary, year, isOld, isFiveYears) {
    var surcharge  = getMonthlyTSMEDESurcharge(isOld);
    var mainRate   = isFiveYears ? 0.1367 : 0.0884;
    var healthRate = 0.0215;
    
    var tempGross = (taxableMonthlySalary + surcharge) / (1 - mainRate - healthRate);
    
    return calcMonthlyTSMEDE(tempGross, year, isOld, isFiveYears);
}