//********************************************************
//
// Assignment 11 - Object Oriented Design
//
// Name: Seth Hin
//
// Class: C Programming, Spring 2026
//
// Date: April 24, 2026
//
// Description: An object oriented program design using
// C++ that will process our existing set of employees.
// It utilizes a class called Employee and generates an 
// array of objects that are used to store, calculate,
// and print out a simple report of inputted and calculated
// values.
//
//
// Object Oriented Design (using C++)
//
//********************************************************

#include <iomanip>   // std::setprecision, std::setw
#include <iostream>  // std::cout, std::fixed
#include <string>    // string functions

// define constants
#define EMP_SIZE 5
#define STD_HOURS 40.0
#define OT_RATE 1.5
#define MA_TAX_RATE 0.05
#define NH_TAX_RATE 0.0
#define VT_TAX_RATE 0.06
#define CA_TAX_RATE 0.07
#define DEFAULT_TAX_RATE 0.08
#define NAME_SIZE 20
#define TAX_STATE_SIZE 3
#define FED_TAX_RATE 0.25
#define FIRST_NAME_SIZE 10
#define LAST_NAME_SIZE 10

using namespace std;

// Employee class definition
class Employee
{
private:
    // Employee data members
    string firstName;
    string lastName;
    string taxState;
    int clockNumber;
    float wageRate;
    float hours;
    float overTimeHrs;
    float grossPay;
    float stateTax;
    float fedTax;
    float netPay;

    // Calculate overtime hours
    float calcOverTimeHrs()
    {
        if (hours > STD_HOURS)
            overTimeHrs = hours - STD_HOURS;
        else
            overTimeHrs = 0;

        return overTimeHrs;
    }

    // Calculate gross pay including overtime
    float calcGrossPay()
    {
        if (overTimeHrs > 0)
        {
            grossPay = (STD_HOURS * wageRate) +
                       (overTimeHrs * (wageRate * OT_RATE));
        }
        else
        {
            grossPay = wageRate * hours;
        }

        return grossPay;
    }

    // Calculate state tax based on state
    float calcStateTax()
    {
        float theStateTax = grossPay;

        if (taxState == "MA")
            theStateTax *= MA_TAX_RATE;
        else if (taxState == "VT")
            theStateTax *= VT_TAX_RATE;
        else if (taxState == "NH")
            theStateTax *= NH_TAX_RATE;
        else if (taxState == "CA")
            theStateTax *= CA_TAX_RATE;
        else
            theStateTax *= DEFAULT_TAX_RATE;

        return theStateTax;
    }

    // Calculate federal tax
    float calcFedTax()
    {
        return grossPay * FED_TAX_RATE;
    }

    // Calculate net pay
    float calcNetPay()
    {
        float totalTaxes = stateTax + fedTax;
        return grossPay - totalTaxes;
    }

public:
    // Default constructor
    Employee()
    {
        firstName = "";
        lastName = "";
        taxState = "";
        clockNumber = 0;
        wageRate = 0;
        hours = 0;
    }

    // Parameterized constructor
    Employee(string myFirstName, string myLastName, string myTaxState,
             int myClockNumber, float myWageRate, float myHours)
    {
        firstName = myFirstName;
        lastName = myLastName;

        // Convert tax state to uppercase
        if (islower(myTaxState[0])) myTaxState[0] = toupper(myTaxState[0]);
        if (islower(myTaxState[1])) myTaxState[1] = toupper(myTaxState[1]);

        taxState = myTaxState;
        clockNumber = myClockNumber;
        wageRate = myWageRate;
        hours = myHours;

        // Perform calculations
        overTimeHrs = calcOverTimeHrs();
        grossPay = calcGrossPay();
        stateTax = calcStateTax();   // FIXED
        fedTax = calcFedTax();       // FIXED
        netPay = calcNetPay();       // FIXED
    }

    // Getter functions
    string getFirstName() { return firstName; }
    string getLastName() { return lastName; }
    string getTaxState() { return taxState; }
    int getClockNumber() { return clockNumber; }
    float getWageRate() { return wageRate; }
    float getHours() { return hours; }
    float getOverTimeHrs() { return overTimeHrs; }
    float getGrossPay() { return grossPay; }

    float getStateTax() { return stateTax; }  // FIXED
    float getFedTax() { return fedTax; }      // FIXED
    float getNetPay() { return netPay; }      // FIXED

    // Print employee details
    void printEmployee(Employee e)
    {
        cout << "\n\n *** Entered Details are *** \n";
        cout << "\n First Name: " << e.getFirstName();
        cout << "\n Last Name: " << e.getLastName();
        cout << "\n Tax State: " << e.getTaxState();
        cout << "\n Clock Number: " << e.getClockNumber();
        cout << "\n Wage Rate: " << e.getWageRate();
        cout << "\n Hours: " << e.getHours();

        cout << "\n\n *** Calculated Values are *** \n";
        cout << "\n Overtime Hours : " << e.getOverTimeHrs();
        cout << "\n Gross Pay : $" << e.getGrossPay();
        cout << "\n State Tax : $" << e.getStateTax();   // FIXED
        cout << "\n Federal Tax : $" << e.getFedTax();   // FIXED
        cout << "\n Net Pay : $" << e.getNetPay();       // FIXED
        cout << "\n";
    }
};

// Main function
int main()
{
    string myFirstName, myLastName, myTaxState;
    int myClockNumber;
    float myWageRate, myHours;

    cout << fixed << setprecision(2);

    // Create array of Employee objects
    Employee e[EMP_SIZE];

    for (int i = 0; i < EMP_SIZE; ++i)
    {
        // Input employee data
        cout << "\n\n Enter Employee First Name: ";
        cin >> myFirstName;

        cout << "\n Enter Employee Last Name: ";
        cin >> myLastName;

        cout << "\n Enter Employee Tax State: ";
        cin >> myTaxState;

        cout << "\n Enter Employee Clock Number: ";
        cin >> myClockNumber;

        cout << "\n Enter Employee Hourly Wage Rate: ";
        cin >> myWageRate;

        cout << "\n Enter Employee Hours Worked for the Week: ";
        cin >> myHours;

        // Create object
        e[i] = Employee(myFirstName, myLastName, myTaxState,
                        myClockNumber, myWageRate, myHours);

        // Print object data
        e[i].printEmployee(e[i]);
    }

    return 0;
}