// Gary Haines II
// CS 140-001
// P02.cpp

#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;

// Prototypes
void Get_Emp_And_Dept_Num(char &dept, int &emp, ifstream &inp);
void Office_Worker_Subroutine(ifstream &inp, ofstream &ooffice, int emp);
void Manuf_Worker_Subroutine(ifstream &inp, ofstream &omanu, int emp);
void Sales_Worker_Subroutine(ifstream &inp, ofstream &osales, int emp);
void Get_Hours_and_Pay_Input(double &hours, double &rate, ifstream &inp);
double Calculate_Pay(double hours, double rate);
double Calculate_Bonus(ifstream &inp);
void Get_Bonus_Input(int &product, int &number, ifstream &inp);
double Return_Profit(ifstream &inp);
void Write_To_File(int emp, double pay, ofstream &out);
double Write_Records_to_Report(ifstream &in, ofstream &report);

// Declare globals
const double WAGON_BONUS = 1.10;
const double SLED_BONUS = 1.25;
const double ROLLER_BONUS  = 1.50;
const double WAGON_COST = 25.28;
const double SLED_COST = 31.52;
const double ROLLER_COST = 21.65;

void main()
{
	// Declare object streams
	ifstream inp;
	ofstream ooffice, omanu, osales;
	ifstream ioffice, imanu, isales;
	ofstream report;
	
	// Declare main variables
	char dept;
	int emp;
	double office;
	double sales;
	double manu;

	// Open and test IO streams
	inp.open("inpdata.txt");
	if (inp.fail()) {
		cerr << "Error opening inpdata.txt\n";
		exit(1);
	}

	ooffice.open("office.txt");
	if (ooffice.fail())
	{
		cerr << "Error opening office.txt for output\n";
		inp.close();
		exit(1);
	}

	omanu.open("manu.txt");
	if (omanu.fail())
	{
		cerr << "Error opening manu.txt for output\n";
		inp.close();
		ooffice.close();
		exit(1);
	}

	osales.open("sales.txt");
	if (osales.fail())
	{
		cerr << "Error opening sales.txt for output\n";
		inp.close();
		ooffice.close();
		omanu.close();
		exit(1);
	}
	
	Get_Emp_And_Dept_Num(dept, emp, inp);

	// Read input file 
	while (!inp.eof())
	{
	
		switch(toupper(dept))
		{
		case 'O': Office_Worker_Subroutine(inp, ooffice, emp); break;
		case 'M': Manuf_Worker_Subroutine(inp, omanu, emp); break;
		case 'S': Sales_Worker_Subroutine(inp, osales, emp); break;
		}

		Get_Emp_And_Dept_Num(dept, emp, inp);

	}

	// Close IO streams
	inp.close();
	ooffice.close();
	omanu.close();
	osales.close();

	// Open and test IO streams for report
	ioffice.open("office.txt");
	if (ioffice.fail())
	{
		cerr << "Error opening office.txt for input\n";
		exit(1);
	}

	imanu.open("manu.txt");
	if (imanu.fail())
	{
		cerr << "Error opening manu.txt for input\n";
		ioffice.close();
		exit(1);
	}

	isales.open("sales.txt");
	if (isales.fail())
	{
		cerr << "Error opening sales.txt for input\n";
		ioffice.close();
		imanu.close();
		exit(1);
	}

	report.open("report.txt");
	if (report.fail())
	{
		cerr << "Error opening report.txt for output\n";
		ioffice.close();
		imanu.close();
		isales.close();
		exit(1);
	}

	// Formatting
	report.setf(ios::fixed);
	report.precision(2);

	report << "WBS PRODUCTION PAYROLL REPORT\n";
	report << "_____________________________\n\n";
	report << setw(25) << "Office Department\n";
	office = Write_Records_to_Report(ioffice, report);
	report << "Total:" << setw(23) << office << endl << endl;
	report << setw(25) << "Sales Department\n";
	sales = Write_Records_to_Report(isales, report);
	report << "Total:" << setw(23) << sales << endl << endl;
	report << setw(28) << "Manufacturing Department\n";
	manu = Write_Records_to_Report(imanu, report);
	report << "Total:" << setw(23) << manu << endl << endl;
	report << setw(25) << "WBS COMPANY TOTAL\n";
	report << setw(25) << "_________________\n";
	report << setw(12) << "$" << (office + sales + manu);

	// Close IO streams for report
	ioffice.close();
	imanu.close();
	isales.close();
	report.close();
	

}

// I was going to comment the rest of the program, but these function names are too descriptive to comment :(
void Get_Emp_And_Dept_Num(char &dept, int &emp, ifstream &inp)
{
	inp >> dept;
	inp >> emp;
}

void Office_Worker_Subroutine(ifstream &inp, ofstream &ooffice, int emp)
{
	double pay;
	double hours;
	double rate;
	Get_Hours_and_Pay_Input(hours, rate, inp);
	pay = Calculate_Pay(hours, rate);
	Write_To_File(emp, pay, ooffice);
}

void Manuf_Worker_Subroutine(ifstream &inp, ofstream &omanu, int emp)
{
	double pay;
	double hours;
	double rate;
	double bonus;
	Get_Hours_and_Pay_Input(hours, rate, inp);
	pay = Calculate_Pay(hours, rate);
	bonus = Calculate_Bonus(inp);
	pay += bonus;
	Write_To_File(emp, pay, omanu);
}

void Sales_Worker_Subroutine(ifstream &inp, ofstream &osales, int emp)
{
	double pay;
	double hours;
	double rate;
	double profit = 0;
	Get_Hours_and_Pay_Input(hours, rate, inp);
	pay = Calculate_Pay(hours, rate);
	int num_items;
	inp >> num_items;
	for(int i = 0; i < num_items; i++)
		profit += Return_Profit(inp);
	pay += profit;
	Write_To_File(emp, pay, osales);
}

void Get_Hours_and_Pay_Input(double &hours, double &rate, ifstream &inp)
{
	inp >> hours >> rate;
}

double Calculate_Pay(double hours, double rate)
{
	if (hours > 40)
		return((hours - 40) * 1.5 * rate + 40 * rate);
	else
		return(hours * rate);
}

double Calculate_Bonus(ifstream &inp)
{
	int product;
	int number;
	double bonus;
	Get_Bonus_Input(product, number, inp);
	switch(product)
	{
	case 1: bonus = (WAGON_BONUS * number); break;
	case 2: bonus = (SLED_BONUS * number); break;
	case 3: bonus = (ROLLER_BONUS * number); break;
	}
	return bonus;
}

void Get_Bonus_Input(int &product, int &number, ifstream &inp)
{
	inp >> product;
	inp >> number;
}

double Return_Profit(ifstream &inp)
{
	int type;
	double price;
	double profit;
	inp >> type;
	inp >> price;
	switch(type)
	{
	case 1: profit = ((price - WAGON_COST) * .15); break;
	case 2: profit = ((price - SLED_COST) * .15); break;
	case 3: profit = ((price - ROLLER_COST) * .15); break;
	}
	return profit;
}
void Write_To_File(int emp, double pay, ofstream &out)
{
	out << emp << " " << pay << endl;
}

double Write_Records_to_Report(ifstream &in, ofstream &report)
{
	double total = 0;
	int emp;
	double pay; 
	report << "Employee Number" << setw(14) << "Pay" << endl;
	in >> emp >> pay;
	while (!in.eof())
	{
		report << setw(10) << emp << setw(19) << pay << endl;
		total += pay;
		in >> emp >> pay;
	}
	report << setw(29) << "---------" << endl; 
	return total;	
}