import java.util.Scanner;

/**
 * Raleigh's Parks and Recreation Department hires landscapers to care for and
 * maintain the city's parks.
 *
 * An employee has one of three skill levels; each with a hourly pay rate:
 *
 * <pre>
 * Skill Level - Hourly Pay Rate ($)
 * ---------------------------------
 * Level 1 - $19.00
 * Level 2 - $22.50
 * Level 3 - $25.75
 * </pre>
 *
 * All employees may opt in for insurance, which results in a deduction from
 * their pay check.
 *
 * <pre>
 * Deduction - Weekly Cost ($)
 * -------------------------------------
 * Option 1 - Medical Insurance - $24.50
 * Option 2 - Dental Insurance - $15.30
 * Option 3 - Vision Insurance - $5.25
 * </pre>
 *
 * Employees at skill level 3 may also opt to place up to 6% of their gross pay
 * into a retirement account.
 *
 * The following information is printed about the employee's pay check: 1)
 * employee's name 2) hours worked for a week 3) hourly pay rate 4) regular pay
 * for up to 40 hours worked 5) overtime pay (1.5 pay rate) for hours over 40
 * worked 6) gross pay (regular + overtime) 7) total deductions 8) net pay
 * (gross pay - total deductions)
 *
 * If the net pay is negative, meaning the deductions exceeds the gross pay,
 * then an error is printed.
 *
 * This program assumes a perfect user. There is no error checking for user
 * input.
 *
 * @author Sarah Heckman
 */
public class Paycheck {

    /* Hourly employment levels */
    /** Hourly employment level 1 */
    public static final int LEVEL_1 = 1;

    /** Hourly employment level 1 */
    public static final int LEVEL_2 = 2;

    /** Hourly employment level 1 */
    public static final int LEVEL_3 = 3;

    /* Pay rate for each hourly employment level */
    /** Pay rate for each hourly employment level 1 */
    public static final int LEVEL_1_PAY_RATE = 1900;

    /** Pay rate for each hourly employment level 2 */
    public static final int LEVEL_2_PAY_RATE = 2250;

    /** Pay rate for each hourly employment level 3 */
    public static final int LEVEL_3_PAY_RATE = 2575;

    /* Insurance costs */
    /** Medical Insurance costs */
    public static final int MEDICAL_INSURANCE = 2450;

    /** Dental Insurance costs */
    public static final int DENTAL_INSURANCE = 1530;
    
    /** Vision Insurance costs */
    public static final int VISION_INSURANCE = 525;

    /** Number of hours in a full time work week */
    public static final int REGULAR_PAY_MAX_HOURS = 40;

    /** Value for invalid items */
    public static final int INVALID = -1;

    /**
     * User interface for the Paycheck program.
     */
    public static void userInterface() {
        // Create shared console scanner
        Scanner console = new Scanner(System.in);

        // Name
        String name = getName(console);

        // Level
        int level = getLevel(console);

        // Hours Worked
        double hoursWorked = getHoursWorked(console);

        // Deductions - Y/N for each one
        int deductions = 0;
        deductions = getTotalDeductions(console);

        // Retirement
        int retirementPercentage = 0;
        if (level == LEVEL_3) {
            retirementPercentage = getRetirementPercentage(console);
        }

        // Print Results
        int payRate = getPayRate(level);
        int regularPay = calculateRegularPay(payRate, hoursWorked);
        int overtimePay = calculateOvertimePay(payRate, hoursWorked);
        int grossPay = calculateGrossPay(regularPay, overtimePay);
        int retirement = calculateRetirement(grossPay, retirementPercentage);
        int netPay = calculateNetPay(grossPay, deductions + retirement);
        if (netPay < 0) {
            System.out.println(
                    "Error calculating net pay.  Deductions exceed gross pay.");
        } else {
            System.out.printf("%-20s%10s%10s%10s%10s%10s%10s%10s\n", "Name",
                    "Hours", "PayRate", "Regular", "OT", "Gross", "Deduc.",
                    "Net");
            System.out.printf(
                    "%-20s%10.2f%10.2f%10.2f%10.2f%10.2f%10.2f%10.2f\n", name,
                    hoursWorked, payRate / 100.0, regularPay / 100.0,
                    overtimePay / 100.0, grossPay / 100.0,
                    (deductions + retirement) / 100.0, netPay / 100.0);
        }

        console.close();
    }

    /**
     * Returns the employee name entered by the user.
     *
     * @param console
     *            Scanner for reading from the console
     * @return employee name
     */
    public static String getName(Scanner console) {
        System.out.print("Employee Name: ");
        return console.nextLine();
    }

    /**
     * Returns the employee level entered by the user.
     *
     * @param console
     *            Scanner for reading from the console
     * @return employee level
     */
    public static int getLevel(Scanner console) {
        System.out.print("Employee Level: ");
        int level = console.nextInt();
        clearLine(console);
        return level;
    }

    /**
     * Returns the hours worked for a given employee as entered by the user.
     *
     * @param console
     *            Scanner for reading from the console
     * @return hours worked
     */
    public static double getHoursWorked(Scanner console) {
        System.out.print("Hours Worked: ");
        double hoursWorked = console.nextDouble();
        clearLine(console);
        return hoursWorked;
    }

    /**
     * Returns the total amount of deductions for a given employee as entered by
     * the user.
     *
     * @param console
     *            Scanner for reading from the console
     * @return total deductions
     */
    public static int getTotalDeductions(Scanner console) {
        int deductions = 0;

        System.out.print("Medical Insurance (Y/N): ");
        String med = console.nextLine();

        System.out.print("Dental Insurance (Y/N): ");
        String den = console.nextLine();

        System.out.print("Vision Insurance (Y/N): ");
        String vis = console.nextLine();

        if (med.toLowerCase().startsWith("y")) {
            deductions += MEDICAL_INSURANCE;
        }

        if (den.toLowerCase().startsWith("y")) {
            deductions += DENTAL_INSURANCE;
        }

        if (vis.toLowerCase().startsWith("y")) {
            deductions += VISION_INSURANCE;
        }

        return deductions;
    }

    /**
     * Returns the retirement contribution percentage for a given employee as
     * entered by the user.
     *
     * @param console
     *            Scanner for reading from the console
     * @return retirement percentage
     */
    public static int getRetirementPercentage(Scanner console) {
        System.out.print("Retirement Percentage (0-6): ");
        int retPercentage = console.nextInt();
        clearLine(console);
        return retPercentage;
    }

    /**
     * Helper method to clear out the rest of a line.
     *
     * @param console
     *            Canner for reading from the console
     */
    private static void clearLine(Scanner console) {
        console.nextLine(); // Clears the line and discards any input
    }

    /**
     * Returns the employee's pay rate given their employment level.
     *
     * @param level
     *            employment level
     * @return employee's pay rate
     */
    public static int getPayRate(int level) {
        if (level == LEVEL_1) {
            return LEVEL_1_PAY_RATE;
        }
        if (level == LEVEL_2) {
            return LEVEL_2_PAY_RATE;
        }
        if (level == LEVEL_3) {
            return LEVEL_3_PAY_RATE;
        }
        return INVALID;
    }

    /**
     * Returns the employee's regular pay for the hours worked up to the first
     * REGULAR_PAY_MAX_HOURS hours worked.
     *
     * @param payRate
     *            employee's pay rate
     * @param hoursWorked
     *            number of hours worked by the employee
     * @return employee's regular pay
     */
    public static int calculateRegularPay(int payRate, double hoursWorked) {
        if (hoursWorked > REGULAR_PAY_MAX_HOURS) {
            return payRate * REGULAR_PAY_MAX_HOURS;
        }
        return (int) (payRate * hoursWorked);
    }

    /**
     * Returns the employee's overtime pay for the hours worked over the
     * REGULAR_PAY_MAX_HOURS.
     *
     * @param payRate
     *            employee's pay rate
     * @param hoursWorked
     *            number of hours worked by the employee
     * @return employee's overtime pay
     */
    public static int calculateOvertimePay(int payRate, double hoursWorked) {
        if (hoursWorked > REGULAR_PAY_MAX_HOURS) {
            return (int) ( (payRate + (payRate / 2))
                    * (hoursWorked - REGULAR_PAY_MAX_HOURS));
        }
        return 0;
    }

    /**
     * Returns the employee's gross pay, which is the sum of regular pay and
     * overtime pay.
     *
     * @param regularPay
     *            employee's regular pay
     * @param overtimePay
     *            employee's overtime pay
     * @return employee's gross pay
     */
    public static int calculateGrossPay(int regularPay, int overtimePay) {
        return regularPay + overtimePay;
    }

    /**
     * Returns the employee's retirement deduction.
     *
     * @param grossPay
     *            employee's gross pay
     * @param retirementPercentage
     *            percentage employee contributes to retirement
     * @return employee's retirement deduction
     */
    public static int calculateRetirement(int grossPay,
            int retirementPercentage) {
        if (retirementPercentage == 0) {
            return 0;
        }
        return (grossPay * retirementPercentage) / 100;
    }

    /**
     * Returns the employee's net pay, which is the difference between gross pay
     * and deductions.
     *
     * @param grossPay
     *            employee's gross pay
     * @param deductions
     *            employee's deductions
     * @return employee's net pay
     */
    public static int calculateNetPay(int grossPay, int deductions) {
        return grossPay - deductions;
    }

    /**
     * Starts the program.
     *
     * @param args
     *            command line arguments
     */
    public static void main(String[] args) {
        userInterface();
    }

}
