#include #include #include #include #include #include #include #include #include void clear_screen(){ std::cout << "\033[H\033[2J\033[3J"; } // ========================= // Lowercase Helper // ========================= std::string toLower(const std::string& s) { std::string out; out.reserve(s.size()); for (char c : s) out.push_back(std::tolower((unsigned char)c)); return out; } // ========================= // Car Class // ========================= class Car { private: std::string year, make, model, engine, transmission, vin; public: Car(const std::string& y, const std::string& mk, const std::string& mdl, const std::string& eng, const std::string& trans, const std::string& v) : year(y), make(mk), model(mdl), engine(eng), transmission(trans), vin(v) {} const std::string& getYear() const { return year; } const std::string& getMake() const { return make; } const std::string& getModel() const { return model; } const std::string& getEngine() const { return engine; } const std::string& getTransmission() const { return transmission; } const std::string& getVin() const { return vin; } }; // ========================= // Load CSV // ========================= std::vector loadCarsFromCSV(const std::string& filename) { std::vector cars; std::ifstream file(filename); if (!file.is_open()) { std::cerr << "Failed to open file\n"; return cars; } std::string line; std::getline(file, line); // skip header while (std::getline(file, line)) { std::stringstream ss(line); std::string year, make, model, engine, transmission, vin; std::getline(ss, year, ','); std::getline(ss, make, ','); std::getline(ss, model, ','); std::getline(ss, engine, ','); std::getline(ss, transmission, ','); std::getline(ss, vin, ','); cars.emplace_back(year, make, model, engine, transmission, vin); } return cars; } // ========================= // Search Functions // ========================= std::vector findByVinContains(const std::vector& cars, const std::string& vin) { std::vector results; std::string target = toLower(vin); for (const auto& car : cars) { if (toLower(car.getVin()).find(target) != std::string::npos) results.push_back(car); } return results; } std::vector findByYear(const std::vector& cars, const std::string& year) { std::vector results; std::string target = toLower(year); for (const auto& car : cars) { if (toLower(car.getYear()) == target) results.push_back(car); } return results; } std::vector findByMake(const std::vector& cars, const std::string& make) { std::vector results; std::string target = toLower(make); for (const auto& car : cars) { if (toLower(car.getMake()) == target) results.push_back(car); } return results; } std::vector findByModelContains(const std::vector& cars, const std::string& text) { std::vector results; std::string target = toLower(text); for (const auto& car : cars) { if (toLower(car.getModel()).find(target) != std::string::npos) results.push_back(car); } return results; } // ========================= // Add Car // ========================= void addCarToCSV(const std::string& filename, const Car& car) { std::ofstream file(filename, std::ios::app); if (!file.is_open()) { std::cerr << "Failed to open file for writing\n"; return; } file << car.getYear() << "," << car.getMake() << "," << car.getModel() << "," << car.getEngine() << "," << car.getTransmission() << "," << car.getVin() << "\n"; } // ========================= // Rewrite CSV (for delete) // ========================= void rewriteCSV(const std::string& filename, const std::vector& cars) { std::ofstream file(filename, std::ios::trunc); if (!file.is_open()) { std::cerr << "Failed to rewrite CSV\n"; return; } file << "year,make,model,engine,transmission,vin\n"; for (const auto& c : cars) { file << c.getYear() << "," << c.getMake() << "," << c.getModel() << "," << c.getEngine() << "," << c.getTransmission() << "," << c.getVin() << "\n"; } } // ========================= // Export CSV // ========================= void exportResults(const std::string& filename, const std::vector& results) { std::ofstream file(filename, std::ios::trunc); if (!file.is_open()) { std::cerr << "Failed to export\n"; return; } file << "year,make,model,engine,transmission,vin\n"; for (const auto& c : results) { file << c.getYear() << "," << c.getMake() << "," << c.getModel() << "," << c.getEngine() << "," << c.getTransmission() << "," << c.getVin() << "\n"; } std::cout << "Exported " << results.size() << " cars to " << filename << "\n"; } // ========================= // Export Pretty Table // ========================= void exportScreen(const std::string& filename, const std::vector& cars) { std::ofstream file(filename, std::ios::trunc); if (!file.is_open()) { std::cerr << "Failed to export screen view\n"; return; } const int W_YEAR = 6; const int W_MAKE = 12; const int W_MODEL = 20; const int W_ENGINE = 15; const int W_TRANS = 18; const int W_VIN = 18; file << std::left << std::setw(W_YEAR) << "Year" << std::setw(W_MAKE) << "Make" << std::setw(W_MODEL) << "Model" << std::setw(W_ENGINE) << "Engine" << std::setw(W_TRANS) << "Transmission" << std::setw(W_VIN) << "VIN" << "\n"; file << std::string(W_YEAR + W_MAKE + W_MODEL + W_ENGINE + W_TRANS + W_VIN, '-') << "\n"; for (const auto& c : cars) { file << std::left << std::setw(W_YEAR) << c.getYear() << std::setw(W_MAKE) << c.getMake() << std::setw(W_MODEL) << c.getModel() << std::setw(W_ENGINE) << c.getEngine() << std::setw(W_TRANS) << c.getTransmission() << std::setw(W_VIN) << c.getVin() << "\n"; } std::cout << "Screen-style export saved to " << filename << "\n"; } // ========================= // Pretty Table Print // ========================= void printCars(const std::vector& cars) { const int W_YEAR = 6; const int W_MAKE = 12; const int W_MODEL = 20; const int W_ENGINE = 15; const int W_TRANS = 18; const int W_VIN = 18; std::cout << std::left << std::setw(W_YEAR) << "Year" << std::setw(W_MAKE) << "Make" << std::setw(W_MODEL) << "Model" << std::setw(W_ENGINE) << "Engine" << std::setw(W_TRANS) << "Transmission" << std::setw(W_VIN) << "VIN" << "\n"; std::cout << std::string(W_YEAR + W_MAKE + W_MODEL + W_ENGINE + W_TRANS + W_VIN, '-') << "\n"; for (const auto& c : cars) { std::cout << std::left << std::setw(W_YEAR) << c.getYear() << std::setw(W_MAKE) << c.getMake() << std::setw(W_MODEL) << c.getModel() << std::setw(W_ENGINE) << c.getEngine() << std::setw(W_TRANS) << c.getTransmission() << std::setw(W_VIN) << c.getVin() << "\n"; } } // ========================= // Search Command Handler // ========================= enum SearchCommand { CMD_CONTINUE, CMD_STOP, CMD_BACK }; SearchCommand handleSearchCommand(const std::string& input, std::vector& lastResults, const std::vector& cars) { std::string cmd = toLower(input); if (cmd == "export") { std::string filename; std::cout << "Enter filename: "; std::getline(std::cin, filename); exportResults(filename, lastResults); return CMD_STOP; } if (cmd == "exportscreen") { std::string filename; std::cout << "Enter filename: "; std::getline(std::cin, filename); exportScreen(filename, lastResults); return CMD_STOP; } if (cmd == "reset") { lastResults = cars; clear_screen(); return CMD_STOP; } if (cmd == "exit") { std::cout << "Goodbye.\n"; exit(0); } if (cmd == "back") { return CMD_BACK; } return CMD_CONTINUE; } // ========================= // Main // ========================= int main() { clear_screen(); std::vector cars = loadCarsFromCSV("test.csv"); std::vector lastResults = cars; while (true) { std::cout << "\nChoose: search, vin, add, delete, export, exportscreen, exit: "; std::string user_search; std::cin >> user_search; clear_screen(); std::cin.ignore(std::numeric_limits::max(), '\n'); // Guided Search Module if (user_search == "search") { lastResults = cars; std::vector makeSnapshot; std::vector modelSnapshot; // ========================= // MAKE STEP // ========================= make_step: { std::vector base = cars; std::string make; std::cout << "Enter Make (or export/reset/back/exit/exportscreen): "; std::getline(std::cin, make); switch (handleSearchCommand(make, lastResults, cars)) { case CMD_STOP: continue; case CMD_BACK: goto make_step; case CMD_CONTINUE: break; } makeSnapshot = findByMake(base, make); lastResults = makeSnapshot; printCars(lastResults); } // ========================= // MODEL STEP // ========================= model_step: { std::vector base = makeSnapshot; std::string model; std::cout << "\nEnter Model (or export/reset/back/exit/exportscreen): "; std::getline(std::cin, model); switch (handleSearchCommand(model, lastResults, cars)) { case CMD_STOP: continue; case CMD_BACK: lastResults = makeSnapshot; printCars(lastResults); goto make_step; case CMD_CONTINUE: break; } modelSnapshot = findByModelContains(base, model); lastResults = modelSnapshot; printCars(lastResults); } // ========================= // YEAR STEP // ========================= year_step: { std::vector base = modelSnapshot; std::string year; std::cout << "\nEnter Year (or export/reset/back/exit/exportscreen): "; std::getline(std::cin, year); switch (handleSearchCommand(year, lastResults, cars)) { case CMD_STOP: continue; case CMD_BACK: lastResults = modelSnapshot; printCars(lastResults); goto model_step; case CMD_CONTINUE: break; } lastResults = findByYear(base, year); printCars(lastResults); } } else if (user_search == "vin") { std::string vin; std::cout << "Enter VIN: "; std::getline(std::cin, vin); auto vinResults = findByVinContains(cars, vin); lastResults = vinResults; printCars(vinResults); } else if (user_search == "add") { std::string year, make, model, engine, transmission, vin; std::cout << "Enter year: "; std::getline(std::cin, year); std::cout << "Enter make: "; std::getline(std::cin, make); std::cout << "Enter model: "; std::getline(std::cin, model); std::cout << "Enter engine: "; std::getline(std::cin, engine); std::cout << "Enter transmission: "; std::getline(std::cin, transmission); std::cout << "Enter VIN: "; std::getline(std::cin, vin); Car newCar(year, make, model, engine, transmission, vin); addCarToCSV("test.csv", newCar); cars.push_back(newCar); lastResults = cars; std::cout << "\nCar added.\n"; } else if (user_search == "delete") { std::string vin; std::cout << "Enter VIN (full or partial): "; std::getline(std::cin, vin); auto matches = findByVinContains(cars, vin); if (matches.empty()) { std::cout << "No matches.\n"; continue; } std::cout << "\nMatches:\n"; for (size_t i = 0; i < matches.size(); i++) { std::cout << i << ":\n"; printCars({matches[i]}); } std::cout << "Enter index to delete: "; size_t idx; std::cin >> idx; std::cin.ignore(std::numeric_limits::max(), '\n'); if (idx >= matches.size()) { std::cout << "Invalid index.\n"; continue; } std::string vinToDelete = matches[idx].getVin(); cars.erase( std::remove_if(cars.begin(), cars.end(), [&](const Car& c) { return toLower(c.getVin()) == toLower(vinToDelete); }), cars.end() ); rewriteCSV("test.csv", cars); lastResults = cars; std::cout << "Car deleted.\n"; } else if (user_search == "export") { std::string filename; std::cout << "Enter filename: "; std::getline(std::cin, filename); exportResults(filename, lastResults); } else if (user_search == "exportscreen") { std::string filename; std::cout << "Enter filename: "; std::getline(std::cin, filename); exportScreen(filename, lastResults); } else if (user_search == "exit") { break; } else if (user_search == "clear"){ clear_screen(); } else { std::cout << "Unknown command.\n"; } } return 0; }