Created
November 30, 2019 05:41
-
-
Save matteing/11976688a4f6e48b84ec133356707639 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Nombre: Sergio Mattei | |
ID: 801183252 | |
Class/Seccion: CCOM 3033 SEC 001 | |
Nombre de archivo: main_mattei_4a.cpp | |
Descripción: This program calculates the salary for employees based on a simple database format, and places results in another file. | |
Notes: This was fun to make. | |
I went a little overboard improving user experience details (like adding friendly colors), but it's just who I am. | |
I really like making things work nicely. | |
*/ | |
#include <iostream> | |
#include <fstream> | |
#include <string> | |
#include <iomanip> | |
#include <vector> | |
using namespace std; | |
// Define constants | |
const int WINDOW_WIDTH = 80; | |
const int WINDOW_COL_SIZE = WINDOW_WIDTH / 5; | |
const int FILE_WIDTH = 150; | |
const int FILE_COL_SIZE = FILE_WIDTH / 9; | |
// UX: Define a few colors (escape sequences) to make things less awful | |
const string T_RESET = "\x1B[0m"; | |
const string T_RED = "\x1B[31m"; | |
const string T_GRN = "\x1B[32m"; | |
const string T_YEL = "\x1B[33m"; | |
// Declare structs | |
struct Employee | |
{ | |
int id; | |
string name; | |
string period; | |
string ssn; | |
double hours; | |
double salary; | |
double extra; | |
double gross; | |
double deductions; | |
double net; | |
}; | |
// Declare functions | |
void askForFilenames(ifstream &, ofstream &); | |
void askRerun(string &); | |
double calculateGross(double, double, double); | |
double calculateExtra(double, double); | |
double calculateDeductions(double); | |
double calculateNet(double, double); | |
void calculateAllSalaryData(Employee &); | |
void printTermTableHeading(); | |
void printTermTableRow(Employee); | |
void printTermTotal(double); | |
void printFileTableHeading(ofstream &); | |
void printFilePersonRowData(ofstream &, Employee); | |
void printFileSalaryRowData(ofstream &, Employee); | |
void printFileTotal(ofstream &, double); | |
void parseEmployeeFile(ifstream &, vector<Employee> &); | |
void printRows(ofstream &, vector<Employee> &); | |
void sortEmployeesByName(vector<Employee> &); | |
void askEmployeesToCalc(vector<Employee> &employees) { | |
int newSize = employees.size(); | |
cout << "How many employees should we process? [1-" << employees.size() << "]: "; | |
string s; // better UX | |
getline(cin, s); | |
newSize = stoi(s); | |
if (newSize > employees.size()) return; | |
if (newSize < 1) { | |
cout << T_RED << "Invalid size." << T_RESET; | |
} | |
employees.resize(newSize); | |
} | |
void askSearch(string &searching) { | |
cout << endl; | |
cout << T_YEL << "Do a search? (y/N) " << T_RESET; | |
getline(cin, searching); | |
} | |
int searchEmployees(vector<Employee> &employees) { | |
string query; | |
cout << "Write your query: "; | |
getline(cin, query); | |
int first = 0; | |
int last = employees.size() - 1; | |
bool found = false; | |
int pos = -1; | |
int middle; | |
while (!found && first <= last) { | |
middle = (first + last) / 2; | |
if (employees[middle].name == query) { | |
pos = middle; | |
found = true; | |
} else if (employees[middle].name > query) { | |
last = middle - 1; | |
} else { | |
first = middle + 1; | |
} | |
} | |
return pos; | |
} | |
void calculateTotal(vector<Employee> employees, double &total) { | |
for (Employee e : employees) { | |
total += e.net; | |
} | |
} | |
int main() | |
{ | |
// note: see askRerun function | |
string again; | |
do | |
{ | |
string searching; // note: see askSearch function | |
ifstream fileToRead; | |
ofstream fileToWrite; | |
vector<Employee> employees; | |
askForFilenames(fileToRead, fileToWrite); | |
do { | |
bool found = false; | |
int foundPos = -1; | |
// parse file && add to employee vector | |
double total = 0.0; // set running total | |
parseEmployeeFile(fileToRead, employees); | |
if (searching == "y" || searching == "Y") { | |
foundPos = searchEmployees(employees); | |
if (foundPos < 0) { | |
cout << T_RED << "No results found." << T_RESET; | |
break; // i know... | |
} else { | |
// clear vect temporarily | |
Employee foundItem; | |
foundItem = employees[foundPos]; | |
employees.clear(); | |
employees.push_back(foundItem); | |
} | |
} else { | |
askEmployeesToCalc(employees); | |
} | |
calculateTotal(employees, total); | |
cout << "\n"; | |
printTermTableHeading(); | |
printFileTableHeading(fileToWrite); | |
printRows(fileToWrite, employees); | |
// Write total to cout | |
printTermTotal(total); | |
// Now send total to file. | |
printFileTotal(fileToWrite, total); | |
askSearch(searching); | |
} while (searching == "y" || searching == "Y"); | |
// Close all files | |
fileToRead.close(); | |
fileToWrite.close(); | |
askRerun(again); | |
} while (again == "y" || again == "Y"); | |
return 0; | |
} | |
void askForFilenames(ifstream &fileToRead, ofstream &fileToWrite) | |
{ | |
string fileName; | |
// Open stream to file. | |
do | |
{ | |
if (fileToRead.fail()) | |
{ | |
cout << T_RED + "Wrong filename." + T_RESET << endl; | |
} | |
cout << "Input name of file to read: "; | |
getline(cin, fileName); | |
fileToRead.open(fileName.c_str()); // apparently the VM doesn't bundle C++11. | |
} while (!fileToRead); | |
cout << "Input name of file to write results: "; | |
getline(cin, fileName); | |
fileToWrite.open(fileName.c_str()); | |
} | |
void printTermTableHeading() | |
{ | |
cout << setw((WINDOW_WIDTH / 2) + 7) << "NOMINA DE EMPRESA" << endl; | |
cout << "\n"; | |
cout << left << setw(WINDOW_COL_SIZE) << "NOMBRE" | |
<< setw(WINDOW_COL_SIZE) << "SSN" | |
<< setw(WINDOW_COL_SIZE) << "HORAS" | |
<< setw(WINDOW_COL_SIZE) << "SALARIO/HORA" | |
<< setw(WINDOW_COL_SIZE) << "SALARIO/SEMANA" << endl; | |
// This took a lot of work to get right. | |
// So turns out that setfill has to go before setw, and for it to work a character must be printed. | |
cout << setfill('=') << setw(WINDOW_WIDTH) << "" << endl; | |
// Reset fill character for next setw's. | |
cout << setfill(' ') << fixed << setprecision(2) << showpoint; | |
} | |
void printFileTableHeading(ofstream &fileToWrite) | |
{ | |
fileToWrite << setw((FILE_WIDTH / 2) + 7) << "NOMINA DE EMPRESA" << endl; | |
fileToWrite << "\n"; | |
fileToWrite << left << setw(FILE_COL_SIZE) << "PERIODO" | |
<< setw(FILE_COL_SIZE) << "NOMBRE" | |
<< setw(FILE_COL_SIZE) << "SSN" | |
<< setw(FILE_COL_SIZE) << "HORAS" | |
<< setw(FILE_COL_SIZE) << "SALARIO" | |
<< setw(FILE_COL_SIZE) << "BRUTO EXTRA" | |
<< setw(FILE_COL_SIZE) << "TOTAL BRUTO" | |
<< setw(FILE_COL_SIZE) << "DEDUC" | |
<< setw(FILE_COL_SIZE) << "TOTAL NETO" << endl; | |
fileToWrite << setfill('=') << setw(FILE_WIDTH) << "" << endl; | |
fileToWrite << setfill(' ') << fixed << setprecision(2) << showpoint; | |
} | |
void printTermTableRow(Employee e) | |
{ | |
cout << setw(WINDOW_COL_SIZE) << e.name; | |
cout << setw(WINDOW_COL_SIZE) << e.ssn; | |
cout << setw(WINDOW_COL_SIZE) << e.hours; | |
cout << setw(WINDOW_COL_SIZE) << e.salary; | |
cout << setw(WINDOW_COL_SIZE) << e.net; | |
cout << endl; | |
} | |
void calculateAllSalaryData(Employee &e) { | |
double extra, gross, deductions, net; | |
extra = calculateExtra(e.salary, e.hours); | |
gross = calculateGross(e.salary, e.hours, extra); | |
deductions = calculateDeductions(gross); | |
net = calculateNet(gross, deductions); | |
e.extra = extra; | |
e.gross = gross; | |
e.deductions = deductions; | |
e.net = net; | |
} | |
void printFilePersonRowData(ofstream &fileToWrite, Employee e) | |
{ | |
fileToWrite << setw(FILE_COL_SIZE) << e.period; | |
fileToWrite << setw(FILE_COL_SIZE) << e.name; | |
fileToWrite << setw(FILE_COL_SIZE) << e.ssn; | |
} | |
double calculateGross(double salary, double hours, double extra) | |
{ | |
return (salary * hours) + extra; | |
} | |
double calculateExtra(double salary, double hours) | |
{ | |
double extra; | |
double extraDifference = hours - 40; | |
if (extraDifference > 0) | |
{ | |
// double the hourly wage for the difference in hours | |
extra = extraDifference * salary; | |
} | |
else | |
{ | |
extra = 0.0; | |
} | |
return extra; | |
} | |
double calculateDeductions(double gross) | |
{ | |
return gross * 0.18; | |
} | |
double calculateNet(double gross, double deductions) | |
{ | |
return gross - deductions; | |
} | |
void printFileSalaryRowData(ofstream &fileToWrite, Employee e) | |
{ | |
// print row data | |
fileToWrite << setw(FILE_COL_SIZE) << e.hours; | |
fileToWrite << setw(FILE_COL_SIZE) << e.salary; | |
fileToWrite << setw(FILE_COL_SIZE) << e.extra; | |
fileToWrite << setw(FILE_COL_SIZE) << e.gross; | |
fileToWrite << setw(FILE_COL_SIZE) << e.deductions; | |
fileToWrite << setw(FILE_COL_SIZE) << e.net; | |
} | |
void printTermTotal(double total) | |
{ | |
cout << "\n"; | |
cout << right << setw(WINDOW_WIDTH - 6) << T_GRN << "Total pagado: " << T_RESET << total << endl; | |
} | |
void printFileTotal(ofstream &fileToWrite, double total) | |
{ | |
fileToWrite << "\n"; | |
fileToWrite << right << setw(FILE_WIDTH - 6) << "Total pagado: " << total; | |
} | |
void askRerun(string &again) | |
{ | |
// note: I used a string type for user experience. | |
// getline handles \n better than using cin, which messes up the stdin buffer | |
// it's a mess | |
cout << endl; | |
cout << T_YEL << "Run again? (y/N) " << T_RESET; | |
getline(cin, again); | |
} | |
void parseEmployeeFile(ifstream &file, vector<Employee> &employees) { | |
int index = 0; | |
string period, name, ssn; | |
double net = 0.0, gross = 0.0, deductions = 0.0, extra = 0.0, hours = 0.0, salary = 0.0; | |
while (file >> period >> name >> ssn >> hours >> salary) | |
{ | |
Employee e = { | |
index, name, period, ssn, hours, salary}; | |
calculateAllSalaryData(e); | |
employees.push_back(e); | |
index++; // update ID counter | |
} | |
sortEmployeesByName(employees); | |
} | |
void printRows(ofstream &file, vector<Employee> &employees) { | |
for (Employee e : employees) { | |
// Write terminal row | |
printTermTableRow(e); | |
// Write row data (file) | |
printFilePersonRowData(file, e); | |
printFileSalaryRowData(file, e); | |
// end row... | |
file << endl; | |
} | |
} | |
void sortEmployeesByName(vector<Employee> &employees) { | |
for (int start = 0; start < employees.size() - 1; start++) { | |
Employee min = employees[start]; | |
int minInd = start; | |
for (int i = start; i < employees.size(); i++) { | |
if (employees[i].name < min.name) { | |
min = employees[i]; | |
minInd = i; | |
} | |
} | |
employees[minInd] = employees[start]; | |
employees[start] = min; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment