2024-04-11 11:52:26 -05:00
|
|
|
//
|
|
|
|
// Created by caleb on 4/10/24.
|
|
|
|
//
|
|
|
|
#include <fstream>
|
|
|
|
#include <cstdio>
|
2024-04-12 21:59:01 -05:00
|
|
|
#include <ctime>
|
|
|
|
#include <boost/algorithm/string.hpp>
|
2024-04-11 11:52:26 -05:00
|
|
|
#include <boost/archive/text_oarchive.hpp>
|
|
|
|
#include <boost/archive/text_iarchive.hpp>
|
|
|
|
#include <boost/serialization/utility.hpp>
|
|
|
|
#include <boost/serialization/vector.hpp>
|
2024-04-12 21:59:01 -05:00
|
|
|
#include <iostream>
|
|
|
|
#include <ranges>
|
2024-04-11 11:52:26 -05:00
|
|
|
#include "userData.h"
|
2024-04-12 21:59:01 -05:00
|
|
|
#include "simpleMenu.h"
|
2024-04-11 11:52:26 -05:00
|
|
|
|
2024-04-12 21:59:01 -05:00
|
|
|
std::tm enterDate() {
|
|
|
|
std::string temp;
|
|
|
|
std::tm tm;
|
|
|
|
std::printf("Enter day: ");
|
|
|
|
std::getline(std::cin, temp);
|
|
|
|
std::sscanf(temp.c_str(), "%i", &tm.tm_mday);
|
|
|
|
std::printf("Enter month: ");
|
|
|
|
std::getline(std::cin, temp);
|
|
|
|
std::sscanf(temp.c_str(), "%i", &tm.tm_mon);
|
|
|
|
std::printf("Enter year: ");
|
|
|
|
std::getline(std::cin, temp);
|
|
|
|
std::sscanf(temp.c_str(), "%i", &tm.tm_year);
|
|
|
|
tm.tm_mon -= 1;
|
|
|
|
tm.tm_year -= 1900;
|
|
|
|
tm.tm_hour = 0, tm.tm_min = 0, tm.tm_sec = 0;
|
|
|
|
return tm;
|
|
|
|
}
|
|
|
|
|
|
|
|
userData enterRecord() {
|
|
|
|
auto pUserData = new userData();
|
|
|
|
std::printf("Entering a new record...\n");
|
|
|
|
|
|
|
|
std::printf("Enter name (spaces allowed): ");
|
|
|
|
std::getline(std::cin, pUserData->name);
|
|
|
|
|
|
|
|
std::printf("Enter address: ");
|
|
|
|
std::getline(std::cin, pUserData->address);
|
|
|
|
|
|
|
|
std::printf("Enter city: ");
|
|
|
|
std::getline(std::cin, pUserData->city);
|
|
|
|
|
|
|
|
std::printf("Enter state: ");
|
|
|
|
std::getline(std::cin, pUserData->state);
|
|
|
|
|
|
|
|
std::printf("Enter ZIP code: ");
|
|
|
|
std::getline(std::cin, pUserData->zip);
|
|
|
|
|
|
|
|
std::printf("Enter phone #: ");
|
|
|
|
std::getline(std::cin, pUserData->phone);
|
2024-04-12 23:06:18 -05:00
|
|
|
while (true) {
|
2024-04-12 21:59:01 -05:00
|
|
|
std::printf("Enter account balance: $");
|
|
|
|
std::string temp;
|
|
|
|
std::getline(std::cin, temp);
|
2024-04-12 22:42:46 -05:00
|
|
|
try {
|
|
|
|
pUserData->accountBal = std::stod(temp);
|
|
|
|
if (pUserData->accountBal < 0) {
|
2024-04-12 23:06:18 -05:00
|
|
|
throw std::invalid_argument("less than zero");
|
2024-04-12 22:42:46 -05:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} catch (const std::invalid_argument &e) {
|
|
|
|
std::cerr << "Invalid input for balance. Please enter a valid number." << std::endl;
|
|
|
|
}
|
2024-04-12 23:06:18 -05:00
|
|
|
}
|
2024-04-12 21:59:01 -05:00
|
|
|
std::printf("Entering date of last payment...\n");
|
|
|
|
std::tm tm = enterDate();
|
|
|
|
pUserData->dateOfLastPayment = std::mktime(&tm);
|
|
|
|
|
|
|
|
return *pUserData;
|
|
|
|
}
|
|
|
|
|
|
|
|
userData *findRecord(const std::vector<userData>& data) {
|
|
|
|
std::printf("Here's the list of entries: \n%s\n", displayData(data).c_str());
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
std::printf("Enter the name for the entry you want to search for\n(we're searching for substrings, so you don't have to type out the full thing): ");
|
|
|
|
std::string userInput;
|
|
|
|
std::getline(std::cin, userInput);
|
|
|
|
|
|
|
|
// attempt to find entry
|
|
|
|
std::printf("Looking for %s...\n", userInput.c_str());
|
|
|
|
for (auto& entry : data) {
|
|
|
|
std::string lowerName = boost::algorithm::to_lower_copy(entry.name);
|
|
|
|
if (lowerName.find(boost::algorithm::to_lower_copy(userInput)) != std::string::npos) {
|
|
|
|
std::printf("%s\nIs this the entry you wanted (y/n)? ", displayData(entry).c_str());
|
|
|
|
std::getline(std::cin, userInput);
|
|
|
|
boost::algorithm::to_lower(userInput);
|
|
|
|
if (userInput == "y") {
|
|
|
|
return &entry; // Return pointer to the found entry directly
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Unable to find entry... Press enter to continue.");
|
|
|
|
std::getline(std::cin, userInput);
|
|
|
|
boost::algorithm::to_lower(userInput);
|
|
|
|
}
|
|
|
|
}
|
2024-04-11 11:52:26 -05:00
|
|
|
|
2024-04-12 21:59:01 -05:00
|
|
|
void deleteEntry(std::vector<userData>& data) {
|
|
|
|
std::printf("What entry would you like to delete?");
|
|
|
|
userData *entryToDelete = findRecord(data);
|
2024-04-11 11:52:26 -05:00
|
|
|
|
2024-04-12 21:59:01 -05:00
|
|
|
for(int i = 0; i < data.size(); ++i) {
|
|
|
|
if (entryToDelete->name == data[i].name) {
|
|
|
|
data.erase(data.begin() + i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateData(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void changeEntry(std::vector<userData>& data) {
|
|
|
|
std::printf("What entry would you like to modify?");
|
|
|
|
userData* selectedEntry = findRecord(data);
|
|
|
|
std::vector<std::string> menuItems = structContents(selectedEntry);
|
|
|
|
int selection = simpleMenu(menuItems, "What data would you like to modify?");
|
|
|
|
switch (selection) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case 9: {
|
|
|
|
std::printf("Old value: %s\nEnter new name (spaces allowed): ", selectedEntry->name.c_str());
|
|
|
|
std::getline(std::cin, selectedEntry->name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1: {
|
|
|
|
std::printf("Old value: %s\nEnter new address: ", selectedEntry->address.c_str());
|
|
|
|
std::getline(std::cin, selectedEntry->address);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 2: {
|
|
|
|
std::printf("Old value: %s\nEnter new city: ", selectedEntry->city.c_str());
|
|
|
|
std::getline(std::cin, selectedEntry->city);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3: {
|
|
|
|
std::printf("Old value: %s\nEnter new state: ", selectedEntry->state.c_str());
|
|
|
|
std::getline(std::cin, selectedEntry->state);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 4: {
|
|
|
|
std::printf("Old value: %s\nEnter new ZIP: ", selectedEntry->zip.c_str());
|
|
|
|
std::getline(std::cin, selectedEntry->zip);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 5: {
|
|
|
|
std::printf("Old value: %s\nEnter new phone #: ", selectedEntry->phone.c_str());
|
|
|
|
std::getline(std::cin, selectedEntry->phone);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 6: {
|
2024-04-12 23:06:18 -05:00
|
|
|
while (true) {
|
|
|
|
std::printf("Old value: %.2lf\nEnter new balance: $", selectedEntry->accountBal);
|
|
|
|
std::string temp;
|
|
|
|
std::getline(std::cin, temp);
|
|
|
|
try {
|
2024-04-12 21:59:01 -05:00
|
|
|
selectedEntry->accountBal = std::stod(temp);
|
2024-04-12 22:42:46 -05:00
|
|
|
if (selectedEntry->accountBal < 0) {
|
2024-04-12 23:06:18 -05:00
|
|
|
throw std::invalid_argument("less than zero");
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2024-04-12 21:59:01 -05:00
|
|
|
} catch (const std::invalid_argument &e) {
|
|
|
|
std::cerr << "Invalid input for balance. Please enter a valid number." << std::endl;
|
|
|
|
}
|
2024-04-12 23:06:18 -05:00
|
|
|
}
|
2024-04-12 21:59:01 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 7: {
|
|
|
|
std::printf("Old value: %s\nEntering new date of last payment...\n",
|
|
|
|
std::put_time(std::localtime(&selectedEntry->dateOfLastPayment), "%c"));
|
|
|
|
std::tm tm = enterDate();
|
|
|
|
selectedEntry->dateOfLastPayment = std::mktime(&tm);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateData(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> structContents(const userData *entry) {
|
|
|
|
std::vector<std::string> structItems;
|
|
|
|
structItems.emplace_back("Name: " + entry->name);
|
|
|
|
structItems.emplace_back("Address: " + entry->address);
|
|
|
|
structItems.emplace_back("City: " + entry->city);
|
|
|
|
structItems.emplace_back("State: " + entry->state);
|
|
|
|
structItems.emplace_back("ZIP: " + entry->zip);
|
|
|
|
structItems.emplace_back("Phone #: " + entry->phone);
|
|
|
|
|
|
|
|
// Format account balance
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "Account Balance: $" << std::fixed << std::setprecision(2) << entry->accountBal;
|
|
|
|
structItems.emplace_back(ss.str());
|
|
|
|
|
|
|
|
// Get gregorian calendar date of unix timestamp
|
|
|
|
structItems.emplace_back("Date of Last Payment: " + std::string(ctime(&entry->dateOfLastPayment)));
|
|
|
|
return structItems;
|
|
|
|
}
|
2024-04-11 11:52:26 -05:00
|
|
|
|
2024-04-12 21:59:01 -05:00
|
|
|
std::string displayData(const userData& entry) {
|
|
|
|
std::vector<std::string> data = structContents(&entry);
|
|
|
|
std::stringstream ss;
|
|
|
|
for(auto str: data) {
|
|
|
|
ss << str << "\n";
|
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
2024-04-11 11:52:26 -05:00
|
|
|
std::string displayData(std::vector<userData> data) {
|
|
|
|
std::string returnString = "";
|
2024-04-12 21:59:01 -05:00
|
|
|
//std::printf("vector size: %i\n", static_cast<int>(data.size()));
|
2024-04-11 11:52:26 -05:00
|
|
|
for (int i = 0; i < data.size(); ++i) {
|
|
|
|
userData currentUserData = data[i];
|
2024-04-12 21:59:01 -05:00
|
|
|
returnString.append(DASHES).append(" entry ").append(std::to_string(i + 1)).append(DASHES).append("\n");
|
|
|
|
returnString.append(displayData(currentUserData));
|
2024-04-11 11:52:26 -05:00
|
|
|
}
|
|
|
|
return returnString;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool fileExists (const std::string& name) {
|
|
|
|
std::ifstream f(name.c_str());
|
|
|
|
return f.good();
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateData(std::vector<userData> data) {
|
2024-04-12 21:59:01 -05:00
|
|
|
// delete the old data
|
|
|
|
std::remove("data.dat");
|
|
|
|
|
2024-04-11 11:52:26 -05:00
|
|
|
// Serialize the vector
|
|
|
|
std::stringstream ss;
|
|
|
|
boost::archive::text_oarchive oa(ss);
|
|
|
|
oa << data;
|
|
|
|
|
|
|
|
// Save the contents
|
|
|
|
std::ofstream outputFile("data.dat");
|
|
|
|
if (outputFile.is_open()) {
|
|
|
|
outputFile << ss.str();
|
|
|
|
outputFile.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<userData> getData() {
|
|
|
|
std::vector<userData> data;
|
|
|
|
if (!fileExists("data.dat")) {
|
2024-04-12 21:59:01 -05:00
|
|
|
std::printf("Warning! No datafile detected! Prompting for data entry...\n");
|
|
|
|
auto pUserData = enterRecord();
|
|
|
|
data.emplace_back(pUserData);
|
2024-04-11 11:52:26 -05:00
|
|
|
updateData(data);
|
|
|
|
} else {
|
|
|
|
// Deserialize and read the data from the file
|
|
|
|
std::ifstream inputFile("data.dat", std::ios::binary);
|
|
|
|
boost::archive::text_iarchive ia(inputFile);
|
|
|
|
ia >> data;
|
|
|
|
}
|
|
|
|
return data;
|
2024-04-12 23:06:18 -05:00
|
|
|
}
|