// // Created by trotfunky on 02/10/2021. // #include "LicenceOperations.h" void dbError(const std::string& errorMessage, char* dbError) { std::cerr << errorMessage << " : " << std::endl << dbError << std::endl; sqlite3_free(dbError); } int addNewLicence(sqlite3* db, const std::string& licenceID) { // Shift the hash two places down to fit properly in an SQLite integer std::string idHash = std::to_string(std::hash{}(licenceID) >> 2); char* errorMessage = nullptr; int errorCode; errorCode = sqlite3_exec(db, ("INSERT INTO " + pointsTable + " VALUES (" + idHash + ", '" + licenceID + "', 12, 0, 0, 0, 0);").c_str(), nullptr, nullptr, &errorMessage); if (errorCode) { dbError("Error adding new licence with ID " + licenceID, errorMessage); } return errorCode; } int applyOffence(sqlite3* db, const std::string& licenceID, int lostPoints, offenceClass offenceClass) { // Shift the hash two places down to fit properly in an SQLite integer std::string idHash = std::to_string(std::hash{}(licenceID) >> 2); char* errorMessage = nullptr; int errorCode; char** licenceInfo = nullptr; // Retrieve points and grave offence info, that's all we need. errorCode = sqlite3_get_table(db, ("SELECT " + pointsColumn + "," + graveOffenceColumn + ", " + onePointCountdownColumn + " FROM " + pointsTable + " WHERE " + keyColumn + " = " + idHash + ";").c_str(), &licenceInfo, nullptr, nullptr, &errorMessage); if (errorCode) { dbError("Error getting info for licence " + licenceID, errorMessage); return errorCode; } int points = std::stoi(licenceInfo[3]); bool hasGraveOffence = std::stoi(licenceInfo[4]); // Can only change from false to true for offences of class 4 or 5 bool newGraveOffence = offenceClass > offenceClass::Three && !hasGraveOffence; int newTenYearCountdown = -1; // Only set for the first new offence when at maximum points, clears if class five offence if (points == 12 && offenceClass < offenceClass::Five) { newTenYearCountdown = 3653; } else if (offenceClass == offenceClass::Five) { newTenYearCountdown = 0; } int newCountdown; int onePointCountdown = std::stoi(licenceInfo[5]); int newOnePointCountdown = -1; // This minimizes affected rows for one point offences when it's the first offence at maximum points. // Not sure if that's useful. if (lostPoints == 1 && points == 12) { newCountdown = 183; } else { newCountdown = (2 + (hasGraveOffence || newGraveOffence)) * 365; if (lostPoints == 1) { newOnePointCountdown = 183; } else if (onePointCountdown) { newOnePointCountdown = 0; } } points -= lostPoints; // Licence is revoked, reset everything. if (points <= 0) { points = 0; newCountdown = 0; newOnePointCountdown = 0; newTenYearCountdown = 0; } errorCode = sqlite3_exec( db, ("UPDATE " + pointsTable + " SET " + pointsColumn + " = " + std::to_string(points) + ", " + countdownColumn + " = " + std::to_string(newCountdown) + (newOnePointCountdown >= 0 ? ", " + onePointCountdownColumn + " = " + std::to_string(newOnePointCountdown) : "") + (newTenYearCountdown >= 0 ? ", " + tenYearsCountdownColumn + " = " + std::to_string(newTenYearCountdown) : "") + (newGraveOffence ? ", " + graveOffenceColumn + " = 1" : "") + " WHERE " + keyColumn + " = " + idHash + ";").c_str(), nullptr, nullptr, &errorMessage); if (errorCode) { dbError("Error updating licence " + licenceID, errorMessage); } return errorCode; } int countdown(void* db, int columnCount, char** rowData, char** columnNames) { char* errorMessage = nullptr; int errorCode; int points = std::stoi(rowData[1]); int newPoints = -1; int countdown = std::stoi(rowData[2]); int onePointCoutdown = std::stoi(rowData[3]); int tenYearCountdown = std::stoi(rowData[4]); if (tenYearCountdown == 1 || countdown == 1) { // If resetting the counters, don't do anything else return reset((sqlite3*)db, rowData[0]); } else if (onePointCoutdown == 1) { newPoints = points + 1; } countdown -= 1; onePointCoutdown -= 1; tenYearCountdown -= 1; errorCode = sqlite3_exec( (sqlite3*)db, ("UPDATE " + pointsTable + " SET " + countdownColumn + " = " + std::to_string(countdown) + (newPoints >= 0 ? ", " + pointsColumn + " = " + std::to_string(newPoints) : "") + (onePointCoutdown >= 0 ? ", " + onePointCountdownColumn + " = " + std::to_string(onePointCoutdown) : "") + (tenYearCountdown >= 0 ? ", " + tenYearsCountdownColumn + " = " + std::to_string(tenYearCountdown) : "") + " WHERE " + keyColumn + " = " + rowData[0]).c_str(), nullptr, nullptr, &errorMessage); if (errorCode) { dbError("Error while updating coutdowns for licence hash " + std::string(rowData[0]), errorMessage); } return errorCode; } int reset(sqlite3* db, const std::string& idHash) { char* errorMessage = nullptr; int errorCode; errorCode = sqlite3_exec(db, ("UPDATE " + pointsTable + " SET " + pointsColumn + " = 12, " + countdownColumn + " = 0," + onePointCountdownColumn + " = 0," + tenYearsCountdownColumn + " = 0," + " WHERE " + keyColumn + " = " + idHash).c_str(), nullptr, nullptr, &errorMessage); if (errorCode) { dbError("Error resetting licence " + idHash, errorMessage); } return errorCode; }