diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj index 8627061..6a269f5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj @@ -102,7 +102,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;%(AdditionalIncludeDirectories) + $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories) Console @@ -117,7 +117,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;%(AdditionalIncludeDirectories) + $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories) Console @@ -129,6 +129,7 @@ + @@ -156,6 +157,12 @@ + + + + + + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters index 73b9291..7e74b19 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters @@ -64,6 +64,12 @@ {8057b93d-51a9-42df-b06e-01ce395f6308} + + {ec639004-44c6-4bd6-9963-077adde82b5f} + + + {7aa8722e-adfa-466e-8211-de63f3b7892b} + @@ -141,6 +147,9 @@ Source Files\Models + + Source Files\DataStores\SharedMemory + @@ -251,5 +260,23 @@ Header Files\Views + + Header Files\DataStores\SharedMemory + + + Header Files\DataStores\SharedMemory + + + Header Files\DataStores\SharedMemory + + + Header Files\DataStores\SharedMemory + + + Header Files\DataStores\SharedMemory + + + Header Files\DataStores\SharedMemory + \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index e3a85b0..9bc1d86 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -6,6 +6,7 @@ Description: Implementation file containing the method definitions of the Author: Trenser Date:19-May-2026 */ + #include "ComboPackage.h" #include "Controller.h" #include "Enums.h" diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp index 3419f44..1cade32 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp @@ -9,6 +9,200 @@ Date: 19-May-2026 */ #include "DataStore.h" +#include "Config.h" +#include "SerializedRecords.h" +#include "FileHelper.h" + +/* +Function: DataStore +Description: Constructs the DataStore singleton and initializes + internal handles to their default values. +Parameters: + - None +Returns: + - None +*/ +DataStore::DataStore() : + m_globalMutex(NULL) {} + +/* +Function: ~DataStore +Description: Destroys the DataStore singleton and releases all + cached application objects owned by the datastore. + This includes users, notifications, services, + combo packages, inventory items, service bookings, + job cards, and invoices. +Parameters: + - None +Returns: + - None +*/ +DataStore::~DataStore() +{ + clearCache(m_userCache); + clearCache(m_notificationCache); + clearCache(m_serviceCache); + clearCache(m_comboPackageCache); + clearCache(m_inventoryItemCache); + clearCache(m_serviceBookingCache); + clearCache(m_jobCardCache); + clearCache(m_invoiceCache); +} + +/* +Function: initialize +Description: Initializes the shared-memory datastore. + Creates or opens the global datastore mutex, + configures all mapping metadata, and creates + or opens the file mappings used to persist + application data. After successful completion, + all datastore files are mapped into memory and + ready for use by the application. +Parameter: None +Return type: bool + - true : Initialization completed successfully. + - false : Failed to create the mutex or open + one or more file mappings. +*/ +bool DataStore::initialize() +{ + m_globalMutex = CreateMutexA(NULL, FALSE, "VehicleServiceSystemMutex"); + if (m_globalMutex == NULL) + { + return false; + } + if (!lockDataStore()) + { + CloseHandle(m_globalMutex); + m_globalMutex = NULL; + return false; + } + bool success = true; + do + { + util::ensureDirectoryExists(config::file::DIRECTORY); + m_users.fileName = config::file::USER_FILE; + m_users.recordSize = sizeof(SerializedUser); + m_notifications.fileName = config::file::NOTIFICATION_FILE; + m_notifications.recordSize = sizeof(SerializedNotification); + m_services.fileName = config::file::SERVICE_FILE; + m_services.recordSize = sizeof(SerializedService); + m_comboPackages.fileName = config::file::COMBOPACKAGE_FILE; + m_comboPackages.recordSize = sizeof(SerializedComboPackage); + m_inventoryItems.fileName = config::file::INVENTORYITEM_FILE; + m_inventoryItems.recordSize = sizeof(SerializedInventoryItem); + m_serviceBookings.fileName = config::file::SERVICEBOOKING_FILE; + m_serviceBookings.recordSize = sizeof(SerializedServiceBooking); + m_jobCards.fileName = config::file::JOBCARD_FILE; + m_jobCards.recordSize = sizeof(SerializedJobCard); + m_invoices.fileName = config::file::INVOICE_FILE; + m_invoices.recordSize = sizeof(SerializedInvoice); + m_serviceManagementObservers.fileName = config::file::SERVICEMANAGEMENTOBSERVERS; + m_serviceManagementObservers.recordSize = sizeof(SerializedObserver); + m_paymentManagementObservers.fileName = config::file::PAYMENTMANAGEMENTOBSERVERS; + m_paymentManagementObservers.recordSize = sizeof(SerializedObserver); + m_inventoryManagementObservers.fileName = config::file::INVENTORYMANAGEMENTOBSERVERS; + m_inventoryManagementObservers.recordSize = sizeof(SerializedObserver); + if (!SharedMemory::createOrOpenMapping(m_users)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_notifications)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_services)) + { + success = false; + break; + } + + if (!SharedMemory::createOrOpenMapping(m_comboPackages)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_inventoryItems)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_serviceBookings)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_jobCards)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_invoices)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_payments)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_serviceManagementObservers)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_paymentManagementObservers)) + { + success = false; + break; + } + if (!SharedMemory::createOrOpenMapping(m_inventoryManagementObservers)) + { + success = false; + break; + } + } while (false); + unlockDataStore(); + if (!success) + { + shutdown(); + } + return success; +} + +/* +Function: shutdown +Description: Releases all shared-memory resources owned by the + datastore. Closes every file mapping, unmaps all + mapped views, and releases the datastore mutex. + After this call, the datastore must be initialized + again before use. +Parameter: None +Return type: void +*/ +void DataStore::shutdown() +{ + SharedMemory::closeMapping(m_users); + SharedMemory::closeMapping(m_notifications); + SharedMemory::closeMapping(m_services); + SharedMemory::closeMapping(m_comboPackages); + SharedMemory::closeMapping(m_inventoryItems); + SharedMemory::closeMapping(m_serviceBookings); + SharedMemory::closeMapping(m_jobCards); + SharedMemory::closeMapping(m_invoices); + SharedMemory::closeMapping(m_payments); + SharedMemory::closeMapping(m_serviceManagementObservers); + SharedMemory::closeMapping(m_paymentManagementObservers); + SharedMemory::closeMapping(m_inventoryManagementObservers); + if (m_globalMutex != NULL) + { + CloseHandle(m_globalMutex); + m_globalMutex = NULL; + } +} /* Function: getInstance @@ -26,104 +220,346 @@ DataStore& DataStore::getInstance() /* Function: getUsers -Description: Retrieves the internal map of users. +Description: Retrieves all user records from the datastore. Parameters: - None Returns: - - Reference to util::Map containing all users. + - util::Map>: Collection of user records */ -util::Map& DataStore::getUsers() +util::Map>& DataStore::getUsers() { - return m_users; + return m_userCache; +} + +/* +Function: getNotifications +Description: Retrieves all notification records from the datastore. +Parameters: + - None +Returns: + - util::Map>: Collection of notification records +*/ +util::Map>& DataStore::getNotifications() +{ + return m_notificationCache; } /* Function: getServices -Description: Retrieves the internal map of services. +Description: Retrieves all service records from the datastore. Parameters: - None Returns: - - Reference to util::Map containing all services. + - util::Map>: Collection of service records */ -util::Map& DataStore::getServices() +util::Map>& DataStore::getServices() { - return m_services; + return m_serviceCache; } /* Function: getComboPackages -Description: Retrieves the internal map of combo packages. +Description: Retrieves all combo package records from the datastore. Parameters: - None Returns: - - Reference to util::Map containing all combo packages. + - util::Map>: Collection of combo package records */ -util::Map& DataStore::getComboPackages() +util::Map>& DataStore::getComboPackages() { - return m_comboPackages; -} - -/* -Function: getServiceBookings -Description: Retrieves the internal map of service bookings. -Parameters: - - None -Returns: - - Reference to util::Map containing all service bookings. -*/ -util::Map& DataStore::getServiceBookings() -{ - return m_serviceBookings; -} - -/* -Function: getJobCards -Description: Retrieves the internal map of job cards. -Parameters: - - None -Returns: - - Reference to util::Map containing all job cards. -*/ -util::Map& DataStore::getJobCards() -{ - return m_jobCards; + return m_comboPackageCache; } /* Function: getInventoryItems -Description: Retrieves the internal map of inventory items. +Description: Retrieves all inventory item records from the datastore. Parameters: - None Returns: - - Reference to util::Map containing all inventory items. + - util::Map>: Collection of inventory item records */ -util::Map& DataStore::getInventoryItems() +util::Map>& DataStore::getInventoryItems() { - return m_inventoryItems; + return m_inventoryItemCache; +} + +/* +Function: getServiceBookings +Description: Retrieves all service booking records from the datastore. +Parameters: + - None +Returns: + - util::Map>: Collection of service booking records +*/ +util::Map>& DataStore::getServiceBookings() +{ + return m_serviceBookingCache; +} + +/* +Function: getJobCards +Description: Retrieves all job card records from the datastore. +Parameters: + - None +Returns: + - util::Map>: Collection of job card records +*/ +util::Map>& DataStore::getJobCards() +{ + return m_jobCardCache; } /* Function: getInvoices -Description: Retrieves the internal map of invoices. +Description: Retrieves all invoice records from the datastore. Parameters: - None Returns: - - Reference to util::Map containing all invoices. + - util::Map>: Collection of invoice records */ -util::Map& DataStore::getInvoices() +util::Map>& DataStore::getInvoices() { - return m_invoices; + return m_invoiceCache; } /* -Function: getPayments -Description: Retrieves the internal map of payments. +Function: getServiceManagementObservers +Description: Retrieves all service management observer records from the datastore. Parameters: - None Returns: - - Reference to util::Map containing all payments. + - util::Map: Collection of observer records */ -util::Map& DataStore::getPayments() +util::Map DataStore::getServiceManagementObservers() { - return m_payments; -} \ No newline at end of file + return util::Map(); +} + +/* +Function: getPaymentManagementObservers +Description: Retrieves all payment management observer records from the datastore. +Parameters: + - None +Returns: + - util::Map: Collection of observer records +*/ +util::Map DataStore::getPaymentManagementObservers() +{ + return util::Map(); +} + +/* +Function: getInventoryManagementObservers +Description: Retrieves all inventory management observer records from the datastore. +Parameters: + - None +Returns: + - util::Map: Collection of observer records +*/ +util::Map DataStore::getInventoryManagementObservers() +{ + return util::Map(); +} + +/* +Function: saveUsers +Description: Persists all user records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveUsers() +{ +} + +/* +Function: saveNotifications +Description: Persists all notification records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveNotifications() +{ +} + +/* +Function: saveServices +Description: Persists all service records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveServices() +{ +} + +/* +Function: saveComboPackages +Description: Persists all combo package records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveComboPackages() +{ +} + +/* +Function: saveInventoryItems +Description: Persists all inventory item records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveInventoryItems() +{ +} + +/* +Function: saveServiceBookings +Description: Persists all service booking records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveServiceBookings() +{ +} + +/* +Function: saveJobCards +Description: Persists all job card records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveJobCards() +{ +} + +/* +Function: saveInvoices +Description: Persists all invoice records to the datastore. +Parameters: + - None +Returns: + - None +*/ +void DataStore::saveInvoices() +{ +} + +/* +Function: saveServiceManagementObservers +Description: Persists all service management observer records to the datastore. +Parameters: + - observers: util::Map>&, collection of observer records +Returns: + - None +*/ +void DataStore::saveServiceManagementObservers(util::Map& observers) +{ +} + +/* +Function: savePaymentManagementObservers +Description: Persists all payment management observer records to the datastore. +Parameters: + - observers: util::Map&, collection of observer records +Returns: + - None +*/ +void DataStore::savePaymentManagementObservers(util::Map& observers) +{ +} + +/* +Function: saveInventoryManagementObservers +Description: Persists all inventory management observer records to the datastore. +Parameters: + - observers: util::Map&, collection of observer records +Returns: + - None +*/ +void DataStore::saveInventoryManagementObservers(util::Map& observers) +{ +} + +/* +Function: lockDataStore +Description: Acquires exclusive access to the datastore. +Parameters: + - None +Returns: + - bool: True if the datastore was successfully locked, otherwise false +*/ +bool DataStore::lockDataStore() +{ + return false; +} + +/* +Function: unlockDataStore +Description: Releases exclusive access to the datastore. +Parameters: + - None +Returns: + - bool: True if the datastore was successfully unlocked, otherwise false +*/ +bool DataStore::unlockDataStore() +{ + return false; +} + +/* +Function: lockDataStore +Description: Acquires the datastore mutex, providing + exclusive access to the shared-memory + datastore. This function blocks until + the mutex becomes available or an error + occurs. +Parameter: None +Return type: + bool + - true : Mutex successfully acquired. + - false : Failed to acquire the mutex. +*/ +bool DataStore::lockDataStore() +{ + if (m_globalMutex == NULL) + { + return false; + } + DWORD result = WaitForSingleObject(m_globalMutex, INFINITE); + return result == WAIT_OBJECT_0; +} + +/* +Function: unlockDataStore +Description: Releases the datastore mutex after a + successful call to lockDataStore(), + allowing other processes to access the + shared-memory datastore. +Parameter: None +Return type: + bool + - true : Mutex successfully released. + - false : Failed to release the mutex. +*/ +bool DataStore::unlockDataStore() +{ + if (m_globalMutex == NULL) + { + return false; + } + return ReleaseMutex(m_globalMutex) != 0; +} + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h index cde9b4e..3950b11 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h @@ -6,42 +6,232 @@ Date: 19-May-2026 */ #pragma once +#include #include #include "Map.h" - +#include "MappingInfo.h" +#include "TrackedRecord.h" +#include "SharedMemory.h" class User; +class Notification; class Service; class ComboPackage; +class InventoryItem; class ServiceBooking; class JobCard; -class InventoryItem; class Invoice; -class Payment; class DataStore { private: - util::Map m_users; - util::Map m_services; - util::Map m_comboPackages; - util::Map m_serviceBookings; - util::Map m_jobCards; - util::Map m_inventoryItems; - util::Map m_invoices; - util::Map m_payments; - DataStore() {} -public: - static DataStore& getInstance(); + DataStore(); + ~DataStore(); DataStore(const DataStore&) = delete; DataStore& operator=(const DataStore&) = delete; DataStore(DataStore&&) = delete; DataStore& operator=(DataStore&&) = delete; - util::Map& getUsers(); - util::Map& getServices(); - util::Map& getComboPackages(); - util::Map& getServiceBookings(); - util::Map& getJobCards(); - util::Map& getInventoryItems(); - util::Map& getInvoices(); - util::Map& getPayments(); -}; \ No newline at end of file + HANDLE m_globalMutex; + MappingInfo m_users; + MappingInfo m_notifications; + MappingInfo m_services; + MappingInfo m_comboPackages; + MappingInfo m_inventoryItems; + MappingInfo m_serviceBookings; + MappingInfo m_jobCards; + MappingInfo m_invoices; + MappingInfo m_payments; + MappingInfo m_serviceManagementObservers; + MappingInfo m_paymentManagementObservers; + MappingInfo m_inventoryManagementObservers; + util::Map> m_userCache; + util::Map> m_notificationCache; + util::Map> m_serviceCache; + util::Map> m_comboPackageCache; + util::Map> m_inventoryItemCache; + util::Map> m_serviceBookingCache; + util::Map> m_jobCardCache; + util::Map> m_invoiceCache; +public: + static DataStore& getInstance(); + bool initialize(); + void shutdown(); + util::Map>& getUsers(); + util::Map>& getNotifications(); + util::Map>& getServices(); + util::Map>& getComboPackages(); + util::Map>& getInventoryItems(); + util::Map>& getServiceBookings(); + util::Map>& getJobCards(); + util::Map>& getInvoices(); + util::Map getServiceManagementObservers(); + util::Map getPaymentManagementObservers(); + util::Map getInventoryManagementObservers(); + void saveUsers(); + void saveNotifications(); + void saveServices(); + void saveComboPackages(); + void saveInventoryItems(); + void saveServiceBookings(); + void saveJobCards(); + void saveInvoices(); + void saveServiceManagementObservers(util::Map& observers); + void savePaymentManagementObservers(util::Map& observers); + void saveInventoryManagementObservers(util::Map& observers); + bool lockDataStore(); + bool unlockDataStore(); +private: + template + util::Map> loadRecords(MappingInfo& mapping); + template + void saveRecords(MappingInfo& mapping, util::Map>& records); + template void clearCache(util::Map>&cache); + template void refreshCache(util::Map>&cache, util::Map>&refreshedCache); +}; + +/* +Function: loadRecords +Description: Loads all serialized records from the specified + shared-memory mapping, deserializes them into + application objects, and returns them as a map + of tracked records. Each loaded record is marked + as CLEAN and assigned its corresponding slot index + within the mapping so that future modifications + can be written back efficiently. +Parameter: + - mapping: Reference to the mapping containing the + serialized records. +Return type: + util::Map> + A map containing all loaded records keyed by + their unique identifier. +*/ +template +util::Map> DataStore::loadRecords(MappingInfo& mapping) +{ + util::Map> records; + SharedMemory::ensureLatestMapping(mapping); + size_t recordCount = SharedMemory::getRecordCount(mapping); + for (size_t index = 0; index < recordCount; ++index) + { + TSerialized* serialized = static_cast(SharedMemory::getRecordAddress(mapping,index)); + TObject* object = TObject::deserialize(*serialized); + TrackedRecord trackedRecord; + trackedRecord.data = object; + trackedRecord.state = RecordState::CLEAN; + trackedRecord.slotIndex = index; + records.insert(object->getId(), trackedRecord); + } + return records; +} + +/* +Function: saveRecords +Description: Persists all modified and newly added records + contained in the provided map to the specified + shared-memory mapping. Modified records overwrite + their existing slots, while new records are + appended to the end of the mapping. Records marked + as CLEAN are ignored. +Parameter: + - mapping: Reference to the mapping where records are + stored. + - records: Map containing the records to be persisted. +Return type: void +*/ +template void DataStore::saveRecords(MappingInfo& mapping, util::Map>& records) +{ + SharedMemory::ensureLatestMapping(mapping); + for (int index = 0; index < records.getSize(); ++index) + { + TrackedRecord& record = records.getValueAt(index); + if (record.state == RecordState::CLEAN) + { + continue; + } + TSerialized serialized = record.data->serialize(); + if (record.state == RecordState::MODIFIED) + { + TSerialized* destination = static_cast(SharedMemory::getRecordAddress(mapping, record.slotIndex)); + if (destination) + { + *destination = serialized; + } + } + else if (record.state == RecordState::NEW_RECORD) + { + if (!SharedMemory::ensureCapacityForInsert(mapping)) + { + continue; + } + size_t recordCount = SharedMemory::getRecordCount(mapping); + TSerialized* destination = static_cast(SharedMemory::getRecordAddress(mapping,recordCount)); + *destination = serialized; + SharedMemory::setRecordCount(mapping, recordCount + 1); + record.slotIndex = recordCount; + } + record.state = RecordState::CLEAN; + } +} + +/* +Function: clearCache +Description: Releases all objects owned by the cache and + clears the cache contents. +Parameters: + - cache: Cache to be cleared. +Returns: + - None +*/ +template +void DataStore::clearCache(util::Map>&cache) +{ + for (int index = 0; index < cache.getSize(); ++index) + { + delete cache.getValueAt(index).data; + cache.getValueAt(index).data = nullptr; + } + cache.clear(); +} + +/* +Function: refreshCache +Description: Refreshes the cache while preserving object addresses + for records that already exist. Existing objects are + updated in-place so that pointers held elsewhere remain + valid after the refresh. +Parameters: + - cache: Existing cache to refresh. + - refreshedCache: Newly loaded cache contents. +Returns: + - None +*/ +template +void DataStore::refreshCache(util::Map>& cache, util::Map>& refreshedCache) +{ + util::Map> oldCache = cache; + cache.clear(); + for (int index = 0; index < refreshedCache.getSize(); ++index) + { + const std::string& id = refreshedCache.getKeyAt(index); + TrackedRecord& refreshedRecord = refreshedCache.getValueAt(index); + int oldIndex = oldCache.find(id); + if (oldIndex != -1) + { + TrackedRecord& oldRecord = oldCache.getValueAt(oldIndex); + *oldRecord.data = *refreshedRecord.data; + oldRecord.slotIndex = refreshedRecord.slotIndex; + oldRecord.state = refreshedRecord.state; + delete refreshedRecord.data; + refreshedRecord.data = oldRecord.data; + } + cache.insert(id, refreshedRecord); + } + for (int index = 0; index < oldCache.getSize(); ++index) + { + const std::string& id = oldCache.getKeyAt(index); + if (cache.find(id) == -1) + { + delete oldCache.getValueAt(index).data; + } + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/FileHeader.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/FileHeader.h new file mode 100644 index 0000000..929dbf4 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/FileHeader.h @@ -0,0 +1,17 @@ +/* +File: FileHeader.h +Description: Defines the FileHeader structure used to store + metadata for binary record files, including + record count and capacity. +Author: Trenser +Created: 10-June-2026 +*/ + +#pragma once +#include + +struct FileHeader +{ + size_t recordCount; + size_t capacity; +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/MappingInfo.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/MappingInfo.h new file mode 100644 index 0000000..ebd5123 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/MappingInfo.h @@ -0,0 +1,29 @@ +/* +File: MappingInfo.h +Description: Defines the MappingInfo structure used for + managing Windows file mapping operations. + Stores handles, mapped view pointer, + file metadata, and capacity information. +Author: Trenser +Created: 10-June-2026 +*/ + +#pragma once +#include +#include + +struct MappingInfo +{ + HANDLE fileHandle; + HANDLE mappingHandle; + void* mappedView; + std::string fileName; + size_t recordSize; + size_t mappedCapacity; + MappingInfo() + : fileHandle(NULL), + mappingHandle(NULL), + mappedView(nullptr), + recordSize(0), + mappedCapacity(0) {} +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/RecordState.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/RecordState.h new file mode 100644 index 0000000..95402fd --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/RecordState.h @@ -0,0 +1,17 @@ +/* +File: RecordState.h +Description: Defines the RecordState enumeration used to + represent the state of a record in storage. + States include CLEAN, NEW_RECORD, and MODIFIED. +Author: Trenser +Created: 10-June-2026 +*/ + +#pragma once + +enum class RecordState : int +{ + CLEAN, + NEW_RECORD, + MODIFIED +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SerializedRecords.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SerializedRecords.h new file mode 100644 index 0000000..2d18842 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SerializedRecords.h @@ -0,0 +1,109 @@ +/* +File: SerializedRecords.h +Description: Defines serialized structures for persistent storage + and retrieval of system entities including User, + Notification, Service, ComboPackage, InventoryItem, + ServiceBooking, JobCard, Invoice, and Observer. + These structures use fixed-size character arrays + and primitive types for binary serialization. +Author: Trenser +Created: 10-June-2026 +*/ + +#pragma once +#include "Utility.h" +#include "Enums.h" +#include "Timestamp.h" + +struct SerializedUser +{ + char id[64]; + char username[64]; + char password[64]; + char name[128]; + char phone[32]; + char email[128]; + util::UserType userType; + util::State status; +}; + +struct SerializedNotification +{ + char id[64]; + char recipientUserId[64]; + char title[128]; + char message[1024]; + util::Timestamp createdAt; + util::State state; +}; + +struct SerializedService +{ + char id[64]; + char name[128]; + char inventoryItemIDs[1024]; + double laborCost; + util::State status; +}; + +struct SerializedComboPackage +{ + char id[64]; + char packageName[128]; + double discountPercentage; + char serviceIDs[1024]; + util::State status; +}; + +struct SerializedInventoryItem +{ + char id[64]; + char partName[128]; + int quantity; + double price; + util::State status; +}; + +struct SerializedServiceBooking +{ + char id[64]; + util::ServiceJobStatus status; + char serviceIDs[1024]; + char customerId[64]; + char vehicleNumber[64]; + char vehicleBrand[64]; + char vehicleModel[64]; + char assignedTechnicianId[64]; + double discountPercentage; +}; + +struct SerializedJobCard +{ + char id[64]; + char bookingId[64]; + char serviceId[64]; + char technicianId[64]; + util::Timestamp assignedDate; + util::ServiceJobStatus status; + util::Timestamp completionDate; +}; + +struct SerializedInvoice +{ + char id[64]; + char bookingId[64]; + util::Timestamp invoiceDate; + char partIDs[1024]; + double laborCost; + double partsCost; + double discountPercentage; + double totalAmount; + util::Timestamp paymentDate; + util::PaymentMode paymentMethod; + util::PaymentStatus status; +}; + +struct SerializedObserver +{ + char id[64]; +}; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp new file mode 100644 index 0000000..6a10c9f --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp @@ -0,0 +1,385 @@ +/* +File: SharedMemory.cpp +Description: Implements shared memory utilities for managing + Windows file mapping operations. Provides functions + to create, open, resize, and close mappings, as well + as access headers, records, and ensure synchronization + across processes. +Author: Trenser +Created: 11-June-2026 +*/ + +#include "SharedMemory.h" +#include "Config.h" + +/* +Function: invalidateMapping +Description: Releases all mapping resources and resets the mapping to an invalid state. +Parameters: + - mapping: MappingInfo&, mapping information and handles +Returns: + - None +*/ +static void invalidateMapping(MappingInfo& mapping) +{ + if (mapping.mappedView != nullptr) + { + UnmapViewOfFile(mapping.mappedView); + mapping.mappedView = nullptr; + } + if (mapping.mappingHandle != NULL) + { + CloseHandle(mapping.mappingHandle); + mapping.mappingHandle = NULL; + } + if (mapping.fileHandle != INVALID_HANDLE_VALUE) + { + CloseHandle(mapping.fileHandle); + mapping.fileHandle = INVALID_HANDLE_VALUE; + } + mapping.mappedCapacity = 0; +} + +/* +Function: createOrOpenMapping +Description: Creates or opens a file mapping and maps it into the process address space. +Parameters: + - mapping: MappingInfo&, mapping information and handles +Returns: + - bool: True if the mapping was successfully created/opened, otherwise false +*/ +bool SharedMemory::createOrOpenMapping(MappingInfo& mapping) +{ + if (mapping.recordSize == 0) + { + return false; + } + mapping.fileHandle = + CreateFileA( + mapping.fileName.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (mapping.fileHandle == INVALID_HANDLE_VALUE) + { + return false; + } + LARGE_INTEGER fileSize; + if (!GetFileSizeEx(mapping.fileHandle, &fileSize)) + { + invalidateMapping(mapping); + return false; + } + bool isNewFile = (fileSize.QuadPart == 0); + const size_t initialCapacity = config::file::INITIAL_CAPACITY; + if (isNewFile) + { + LARGE_INTEGER newSize; + newSize.QuadPart = sizeof(FileHeader) + initialCapacity * mapping.recordSize; + if (!SetFilePointerEx(mapping.fileHandle, newSize, NULL, FILE_BEGIN)) + { + invalidateMapping(mapping); + return false; + } + if (!SetEndOfFile(mapping.fileHandle)) + { + invalidateMapping(mapping); + return false; + } + } + mapping.mappingHandle = + CreateFileMappingA( + mapping.fileHandle, + NULL, + PAGE_READWRITE, + 0, + 0, + NULL); + if (mapping.mappingHandle == NULL) + { + invalidateMapping(mapping); + return false; + } + mapping.mappedView = + MapViewOfFile( + mapping.mappingHandle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + 0); + if (mapping.mappedView == nullptr) + { + invalidateMapping(mapping); + return false; + } + FileHeader* header = getHeader(mapping); + if (header == nullptr) + { + invalidateMapping(mapping); + return false; + } + if (isNewFile) + { + header->recordCount = 0; + header->capacity = initialCapacity; + } + mapping.mappedCapacity = header->capacity; + return true; +} + +/* +Function: closeMapping +Description: Unmaps and closes all resources associated with a file mapping. +Parameters: + - mapping: MappingInfo&, mapping to close +Returns: + - None +*/ +void SharedMemory::closeMapping(MappingInfo& mapping) +{ + invalidateMapping(mapping); +} + +/* +Function: getHeader +Description: Returns the file header stored at the beginning of the mapped memory region. +Parameters: + - mapping: MappingInfo&, mapping information and handles +Returns: + - FileHeader*: Pointer to the file header, or nullptr if the mapping is not valid +*/ +FileHeader* SharedMemory::getHeader(MappingInfo& mapping) +{ + if (mapping.mappedView == nullptr) + { + return nullptr; + } + return reinterpret_cast(mapping.mappedView); +} + +/* +Function: getRecordAddress +Description: Returns the address of a record at the specified index within the mapped memory region. +Parameters: + - mapping: MappingInfo&, mapping information and handles + - index: size_t, record index +Returns: + - void*: Pointer to the record, or nullptr if the mapping is not valid +*/ +void* SharedMemory::getRecordAddress(MappingInfo& mapping, size_t index) +{ + if (mapping.mappedView == nullptr) + { + return nullptr; + } + return reinterpret_cast(mapping.mappedView) + sizeof(FileHeader) + index * mapping.recordSize; +} + +/* +Function: getRecordCount +Description: Returns the number of records currently stored in the mapping. +Parameters: + - mapping: MappingInfo&, mapping information and handles +Returns: + - size_t: Number of records in the mapping +*/ +size_t SharedMemory::getRecordCount(MappingInfo& mapping) +{ + FileHeader* header = getHeader(mapping); + if (header == nullptr) + { + return 0; + } + return header->recordCount; +} + +/* +Function: setRecordCount +Description: Updates the number of records stored in the mapping. +Parameters: + - mapping: MappingInfo&, mapping information and handles + - count: size_t, new record count +Returns: + - None +*/ +void SharedMemory::setRecordCount(MappingInfo& mapping, size_t count) +{ + FileHeader* header = getHeader(mapping); + if (header == nullptr) + { + return; + } + header->recordCount = count; +} + +/* +Function: getCapacity +Description: Returns the current capacity of the mapping. +Parameters: + - mapping: MappingInfo&, mapping information and handles +Returns: + - size_t: Maximum number of records that can be stored in the mapping +*/ +size_t SharedMemory::getCapacity(MappingInfo& mapping) +{ + FileHeader* header = getHeader(mapping); + if (header == nullptr) + { + return 0; + } + return header->capacity; +} + +/* +Function: resizeMapping +Description: Resizes the file mapping to the specified capacity. +Parameters: + - mapping: MappingInfo&, mapping information and handles + - newCapacity: size_t, new mapping capacity +Returns: + - bool: True if the resize succeeded, otherwise false +*/ +bool SharedMemory::resizeMapping(MappingInfo& mapping, size_t newCapacity) +{ + FileHeader* header = getHeader(mapping); + if (header == nullptr) + { + invalidateMapping(mapping); + return false; + } + header->capacity = newCapacity; + if (!FlushViewOfFile(mapping.mappedView, sizeof(FileHeader))) + { + return false; + } + if (!UnmapViewOfFile(mapping.mappedView)) + { + return false; + } + mapping.mappedView = nullptr; + CloseHandle(mapping.mappingHandle); + mapping.mappingHandle = NULL; + LARGE_INTEGER newSize; + newSize.QuadPart = sizeof(FileHeader) + newCapacity * mapping.recordSize; + if (!SetFilePointerEx(mapping.fileHandle, newSize, NULL, FILE_BEGIN)) + { + invalidateMapping(mapping); + return false; + } + if (!SetEndOfFile(mapping.fileHandle)) + { + invalidateMapping(mapping); + return false; + } + mapping.mappingHandle = + CreateFileMappingA( + mapping.fileHandle, + NULL, + PAGE_READWRITE, + 0, + 0, + NULL); + if (mapping.mappingHandle == NULL) + { + invalidateMapping(mapping); + return false; + } + mapping.mappedView = + MapViewOfFile( + mapping.mappingHandle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + 0); + if (mapping.mappedView == nullptr) + { + invalidateMapping(mapping); + return false; + } + mapping.mappedCapacity = newCapacity; + return true; +} + +/* +Function: ensureCapacityForInsert +Description: Ensures that the mapping has space for at least one additional record, growing it if necessary. +Parameters: + - mapping: MappingInfo&, mapping information and handles +Returns: + - bool: True if capacity is available, otherwise false +*/ +bool SharedMemory::ensureCapacityForInsert(MappingInfo& mapping) +{ + size_t recordCount = getRecordCount(mapping); + size_t capacity = getCapacity(mapping); + if (recordCount < capacity) + { + return true; + } + return resizeMapping(mapping, capacity * 2); +} + +/* +Function: ensureLatestMapping +Description: Remaps the file if another process has resized it. +Parameters: + - mapping: MappingInfo&, mapping information and handles +Returns: + - bool: True if the mapping is valid and up to date, otherwise false +*/ +bool SharedMemory::ensureLatestMapping(MappingInfo& mapping) +{ + FileHeader* header = getHeader(mapping); + if (header == nullptr) + { + return false; + } + if (header->capacity == mapping.mappedCapacity) + { + return true; + } + if (!UnmapViewOfFile(mapping.mappedView)) + { + invalidateMapping(mapping); + return false; + } + mapping.mappedView = nullptr; + CloseHandle(mapping.mappingHandle); + mapping.mappingHandle = NULL; + mapping.mappingHandle = + CreateFileMappingA( + mapping.fileHandle, + NULL, + PAGE_READWRITE, + 0, + 0, + NULL); + if (mapping.mappingHandle == NULL) + { + invalidateMapping(mapping); + return false; + } + mapping.mappedView = + MapViewOfFile( + mapping.mappingHandle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + 0); + if (mapping.mappedView == nullptr) + { + invalidateMapping(mapping); + return false; + } + header = getHeader(mapping); + if (header == nullptr) + { + invalidateMapping(mapping); + return false; + } + mapping.mappedCapacity = header->capacity; + return true; +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.h new file mode 100644 index 0000000..a288ab3 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.h @@ -0,0 +1,29 @@ +/* +File: SharedMemory.h +Description: Declares functions for managing Windows file + mapping and shared memory operations. Provides + utilities for creating, resizing, and closing + mappings, as well as accessing headers and + record data. +Author: Trenser +Created: 10-June-2026 +*/ + +#pragma once +#include +#include "MappingInfo.h" +#include "FileHeader.h" + +namespace SharedMemory +{ + bool createOrOpenMapping(MappingInfo& mapping); + void closeMapping(MappingInfo& mapping); + bool ensureLatestMapping(MappingInfo& mapping); + bool resizeMapping(MappingInfo& mapping, size_t newCapacity); + FileHeader* getHeader(MappingInfo& mapping); + void* getRecordAddress(MappingInfo& mapping, size_t index); + size_t getRecordCount(MappingInfo& mapping); + void setRecordCount(MappingInfo& mapping, size_t count); + size_t getCapacity(MappingInfo& mapping); + bool ensureCapacityForInsert(MappingInfo& mapping); +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/TrackedRecord.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/TrackedRecord.h new file mode 100644 index 0000000..5ff9ac9 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/TrackedRecord.h @@ -0,0 +1,33 @@ +/* +File: TrackedRecord.h +Description: Defines the TrackedRecord template structure used + to manage objects with associated record state and + slot index. Supports tracking of CLEAN, NEW_RECORD, + and MODIFIED states for persistence and synchronization. +Author: Trenser +Created: 10-June-2026 +*/ + +#pragma once +#include "RecordState.h" + +static const size_t INVALID_SLOT = static_cast(-1); + +template +struct TrackedRecord +{ + T* data; + RecordState state; + size_t slotIndex; + TrackedRecord() + : data(nullptr), + state(RecordState::CLEAN), + slotIndex(INVALID_SLOT) {} + TrackedRecord( + T* object, + RecordState recordState, + size_t slot) + : data(object), + state(recordState), + slotIndex(slot) {} +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h index 6b9f518..b448872 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h @@ -6,6 +6,7 @@ Description: Header file declaring the UserManagementService class, which manage Author: Trenser Date:19-May-2026 */ + #pragma once #include #include "Map.h" diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Config.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Config.h index b0bd19d..2eef19d 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Config.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Config.h @@ -28,16 +28,18 @@ namespace config namespace file { - constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.csv"; - constexpr const char* USER_FILE = "files/User.csv"; - constexpr const char* NOTIFICATION_FILE = "files/Notification.csv"; - constexpr const char* SERVICE_FILE = "files/Service.csv"; - constexpr const char* COMBOPACKAGE_FILE = "files/ComboPackage.csv"; - constexpr const char* SERVICEBOOKING_FILE = "files/ServiceBooking.csv"; - constexpr const char* JOBCARD_FILE = "files/JobCard.csv"; - constexpr const char* INVOICE_FILE = "files/Invoice.csv"; - constexpr const char* SERVICEMANAGEMENTOBSERVERS = "files/ServiceManagementObservers.csv"; - constexpr const char* PAYMENTMANAGEMENTOBSERVERS = "files/PaymentManagementObservers.csv"; - constexpr const char* INVENTORYMANAGEMENTOBSERVERS = "files/InventoryManagementObservers.csv"; + const size_t INITIAL_CAPACITY = 100; + constexpr const char* DIRECTORY = "files/"; + constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat"; + constexpr const char* USER_FILE = "files/User.dat"; + constexpr const char* NOTIFICATION_FILE = "files/Notification.dat"; + constexpr const char* SERVICE_FILE = "files/Service.dat"; + constexpr const char* COMBOPACKAGE_FILE = "files/ComboPackage.dat"; + constexpr const char* SERVICEBOOKING_FILE = "files/ServiceBooking.dat"; + constexpr const char* JOBCARD_FILE = "files/JobCard.dat"; + constexpr const char* INVOICE_FILE = "files/Invoice.dat"; + constexpr const char* SERVICEMANAGEMENTOBSERVERS = "files/ServiceManagementObservers.dat"; + constexpr const char* PAYMENTMANAGEMENTOBSERVERS = "files/PaymentManagementObservers.dat"; + constexpr const char* INVENTORYMANAGEMENTOBSERVERS = "files/InventoryManagementObservers.dat"; } } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h index 7585abc..b908f51 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h @@ -12,28 +12,28 @@ Date: 19-May-2026 namespace util { - enum class UserType + enum class UserType : int { ADMIN, TECHNICIAN, CUSTOMER }; - enum class PaymentMode + enum class PaymentMode : int { ONLINE, OFFLINE, NOTSET }; - enum class PaymentStatus + enum class PaymentStatus : int { PENDING, COMPLETED, PAID }; - enum class ServiceJobStatus + enum class ServiceJobStatus : int { PENDING, STARTED, @@ -42,7 +42,7 @@ namespace util CANCELLED }; - enum class State + enum class State : int { ACTIVE, INACTIVE diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileHelper.h index 2b3e94a..c8bf96f 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileHelper.h @@ -106,4 +106,4 @@ namespace util file << records[index] << '\n'; } } -} +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h index 75d8bbc..dffc199 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace util { @@ -54,6 +55,48 @@ namespace util value = cleanedValue; } + /* + * Function: readPassword + * Description: Reads a password from console without echoing characters; + * displays '*' for each character typed, handles backspace, + * and cleans commas from the result. + * Parameters: + * value - reference to a string where the password will be stored + * Returns: + * void - no return value + */ + inline void readPassword(std::string& value) + { + value.clear(); + char currentCharacter; + while ((currentCharacter = _getch()) != '\r') + { + if (currentCharacter == '\b') + { + if (!value.empty()) + { + value.pop_back(); + std::cout << "\b \b"; + } + } + else + { + value += currentCharacter; + std::cout << '*'; + } + } + std::cout << std::endl; + std::string cleanedValue; + for (int iterator = 0; iterator < value.length(); iterator++) + { + if (value[iterator] != ',') + { + cleanedValue += value[iterator]; + } + } + value = cleanedValue; + } + /* * Function: pressEnter * Description: Pauses execution until the user presses Enter. diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h index 300d5c4..9b6bc9d 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h @@ -99,4 +99,80 @@ namespace util auto observerIDs = service->getObserverIDs(); util::saveRecords(filePath, observerIDs); } + + template + Map getObjects(const Map>& trackedRecords); + + template + Map getConstObjects(const Map>& trackedRecords); + + template + TrackedRecord createNewRecord(TObject* object); +} + +/* +Function: getObjects +Description: Extracts the object pointers from a tracked-record + collection and returns them as a map keyed by the + same identifiers. +Parameters: + - trackedRecords: Collection of tracked records. +Returns: + - Map: Collection of object pointers. +*/ +template +util::Map util::getObjects(const util::Map>& trackedRecords) +{ + util::Map objects; + for (int index = 0; index < trackedRecords.getSize(); ++index) + { + const std::string& key = trackedRecords.getKeyAt(index); + TObject* object = trackedRecords.getValueAt(index).data; + objects.insert(key, object); + } + return objects; +} + +/* +Function: getConstObjects +Description: Extracts the object pointers from a tracked-record + collection and returns them as a read-only map + keyed by the same identifiers. +Parameters: + - trackedRecords: Collection of tracked records. +Returns: + - Map: + Collection of read-only object pointers. +*/ +template +util::Map util::getConstObjects( + const util::Map>& trackedRecords) +{ + util::Map objects; + for (int index = 0; index < trackedRecords.getSize(); ++index) + { + const std::string& key = trackedRecords.getKeyAt(index); + const TObject* object = trackedRecords.getValueAt(index).data; + objects.insert(key, object); + } + return objects; +} + +/* +Function: createNewRecord +Description: Creates a tracked record for a newly created + object. The record is initialized with + NEW_RECORD state. +Parameters: + - object: Pointer to the newly created object. +Returns: + - TrackedRecord: Initialized tracked record. +*/ +template +TrackedRecord util::createNewRecord(TObject* object) +{ + TrackedRecord record; + record.data = object; + record.state = RecordState::NEW_RECORD; + return record; } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index 3e56d99..0d60f97 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -30,7 +30,6 @@ Description: Displays the customer menu and handles user input until logout is s Parameter: None Return type: void */ - void CustomerMenu::showMenu() { while (true) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 83720c0..c6ebaa6 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -914,7 +914,7 @@ inline void changePasswordHelper(Controller& controller) util::clear(); std::cout << "Change Password\n"; std::cout << "Enter new password: "; - util::read(newPassword); + util::readPassword(newPassword); if (!util::isPasswordValid(newPassword)) { std::cout << "Error: Password is not strong enough!\n"; @@ -928,7 +928,7 @@ inline void changePasswordHelper(Controller& controller) continue; } std::cout << "Confirm new password: "; - util::read(confirmedPassword); + util::readPassword(confirmedPassword); if (confirmedPassword != newPassword) { std::cout << "Passwords are different. Try again\n"; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h index a17ccb1..2d118a0 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h @@ -22,4 +22,4 @@ public: void viewNotifications(); void logout(); void changePassword(); -}; +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp index 841e2ea..4596d9b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp @@ -106,7 +106,7 @@ void UserInterface::login() std::cout << "Enter username: "; util::read(username); std::cout << "Enter password: "; - util::read(password); + util::readPassword(password); if (m_controller.login(username, password)) { const User* authenticatedUser = m_controller.getAuthenticatedUser(); @@ -167,7 +167,7 @@ void UserInterface::registerCustomer() return; } std::cout << "Enter password: "; - util::read(password); + util::readPassword(password); if (!util::isPasswordValid(password)) { std::cout << "Error: Password is invalid!"; @@ -185,4 +185,4 @@ void UserInterface::registerCustomer() m_controller.createCustomer(username, name, password, email, phone); std::cout << "Registration is successful"; util::pressEnter(); -} +} \ No newline at end of file