
import java.util.*;

public class RetirementCalculatorModel
{
    /* input fields */
    private HashMap<String, Double> myFields;

    public RetirementCalculatorModel()
    {
        myFields = new HashMap<String, Double>();
        reset();
    }

    public void setField(String name, double value)
    {
        myFields.put(name, value);
    }

    public double getField(String name)
    {
        return (myFields.containsKey(name)) ? myFields.get(name) : 0;
    }

    public void reset()
    {
        myFields.clear();

        setField("current income", 0);
        setField("income wanted", 0);
        setField("employer pension", 0);
        setField("part time income", 0);
        setField("other income", 0);
        setField("age", 30);
        setField("retirement age", 65);
        setField("savings", 0);
        setField("life expectancy", 82);

        calculate();
    }

    public void calculate()
    {
        setField("social security", calculateSocialSecurity());
        setField("amount to make up",
                getField("income wanted") -
                getField("social security") -
                getField("employer pension") -
                getField("part time income") -
                getField("other income"));
        setField("amount to save",
                getField("amount to make up") * calculateMakeUpFactor());
        setField("early retirement penalty",
                getField("social security") * calculateEarlyRetirementFactor());
        setField("estimated savings",
                getField("savings") * calculateSavingsFactor());
        setField("total additional savings needed",
                getField("amount to save") +
                getField("early retirement penalty") -
                getField("estimated savings"));
        setField("annual savings needed",
                getField("total additional savings needed") *
                calculateTotalSavingsFactor());
    }

    private double calculateMakeUpFactor()
    {
        int retire_age_index = (int) getField("retirement age");
        int life_expectancy_index = (int) getField("life expectancy");

        if      (retire_age_index == 55)        retire_age_index = 0;
        else if (retire_age_index == 60)        retire_age_index = 1;
        else if (retire_age_index == 70)        retire_age_index = 3;
        else                                    retire_age_index = 2;

        if      (life_expectancy_index == 86)   life_expectancy_index = 1;
        else if (life_expectancy_index == 89)   life_expectancy_index = 2;
        else if (life_expectancy_index == 92)   life_expectancy_index = 3;
        else if (life_expectancy_index == 94)   life_expectancy_index = 4;
        else if (life_expectancy_index == 97)   life_expectancy_index = 5;
        else                                    life_expectancy_index = 0;

        final double makeup_factors[] = {
            18.79, 20.53, 21.71, 22.79, 23.46, 24.40,
            16.31, 18.32, 19.68, 20.93, 21.71, 22.79,
            13.45, 15.77, 17.35, 18.79, 19.68, 20.93,
            10.15, 12.83, 14.65, 16.31, 17.35, 18.79
        };

        return makeup_factors[retire_age_index * 6 + life_expectancy_index];
    }

    private double calculateEarlyRetirementFactor()
    {
        int retire_age_index = (int) getField("retirement age");
        if      (retire_age_index == 55)        return 8.8;
        else if (retire_age_index == 60)        return 4.7;
        else                                    return 0.0;
    }
    
    private double calculateSocialSecurity()
    {
        double current_income = getField("current income");
        if      (current_income < 25000.0)
            return 8000.0;
        else if (current_income <= 40000.0)
            return 12000.0;
        else
            return 14500.0;
    }

    private double calculateSavingsFactor()
    {
        int savings_factor_index = calculateFiveYearsToRetirement() - 2;
        double savings_factors[] = {
            1.3, 1.6, 1.8, 2.1, 2.4, 2.8, 3.3
        };
        return savings_factors[savings_factor_index];
    }
    
    private double calculateTotalSavingsFactor()
    {
        int total_savings_factor_index = calculateFiveYearsToRetirement() - 2;
        double total_savings_factors[] = {
            0.085, 0.052, 0.036, 0.027, 0.020, 0.016, 0.013
        };
        return total_savings_factors[total_savings_factor_index];
    }

    private int calculateFiveYearsToRetirement()
    {
        double retire_age = getField("retirement age");
        double current_age = getField("age");
        double years_to_retirement = retire_age - current_age;
        int five_years_to_retirement =
            (int) ((years_to_retirement + 2.5) / 5.0);
        if (five_years_to_retirement < 2)
            five_years_to_retirement = 2;
        if (five_years_to_retirement > 8)
            five_years_to_retirement = 8;
        return five_years_to_retirement;
    }
}
