#include "session_generator.h" #include "create_session_request.h" #include "hall_dto.h" #include "halls_repository.h" #include "movie_dto.h" #include "movies_repository.h" #include "repository_manager.h" #include "repository_result.h" #include "schema_metadata.h" #include "sessions_repository.h" SessionGenerator::SessionGenerator( const ReservationManager &reservationReference) : BaseGenerator("Session"), reservationReference_(reservationReference) { initializeRepositories(); // First qint32 extraTime = 45; // Extra time for cleaning the room initializeMovieIdToDurationMap(extraTime); // After initializing repositories initializeBounds(); // After initializing movieIdToDuration initializeDayManager(); // After initializing bounds initializeHallIdToReservationManagerMap(); // After initializing dayManager } void SessionGenerator::initializeRepositories() { RepositoryManager &repositoryManager = RepositoryManager::instance(); SchemaMetadata metadata = SchemaMetadata::defaultSchema(); moviesRepository_ = repositoryManager.getRepositoryAs( metadata.repositoryTableName("movies")); hallsRepository_ = repositoryManager.getRepositoryAs( metadata.repositoryTableName("halls")); sessionsRepository_ = repositoryManager.getRepositoryAs( metadata.repositoryTableName("sessions")); if (!bool(moviesRepository_ && hallsRepository_ && sessionsRepository_)) { qFatal() << "Failed to initialize repositories"; } } void SessionGenerator::initializeMovieIdToDurationMap( qint32 additionalMinutes) { QVector movies; RepositoryResult result = moviesRepository_->getAllMovies(movies); if (!result.success) { qFatal() << "Failed to retrieve movies"; } for (const MovieDTO &movie : movies) { movieIdToDurationMinutes_[movie.movieId()] = movie.duration() + additionalMinutes; } if (movieIdToDurationMinutes_.isEmpty()) { qFatal() << "Failed to initialize movieIdToDuration"; } qInfo() << "Number of movies:" << movieIdToDurationMinutes_.size(); } void SessionGenerator::initializeBounds() { qint32 lowerBoundReservationMin = *std::min_element( movieIdToDurationMinutes_.cbegin(), movieIdToDurationMinutes_.cend()); lowerBoundReservationMs_ = lowerBoundReservationMin * 60'000; // 60 * 1000 qint32 upperBoundReservationMin = *std::max_element( movieIdToDurationMinutes_.cbegin(), movieIdToDurationMinutes_.cend()); upperBoundReservationMs_ = upperBoundReservationMin * 60'000; // 60 * 1000 qInfo() << "Lower bound reservation in Ms:" << lowerBoundReservationMs_; qInfo() << "Upper bound reservation in Ms:" << upperBoundReservationMs_; } void SessionGenerator::initializeDayManager() { QTime minDuration = QTime::fromMSecsSinceStartOfDay(lowerBoundReservationMs_); DayManager dayManager(reservationReference_.reference()); dayManager.setMinDuration(minDuration); reservationReference_.setReference(dayManager); if (!reservationReference_.reference().minDuration().isValid()) { qFatal() << "Failed to initialize dayManager"; } qInfo() << "Day manager: Min duration:" << reservationReference_.reference().minDuration(); qInfo() << "Day manager: Slot count:" << reservationReference_.reference().slotCount(); } void SessionGenerator::initializeHallIdToReservationManagerMap() { QVector halls; RepositoryResult result = hallsRepository_->getAllHalls(halls); if (!result.success) { qFatal() << "Failed to retrieve halls"; } for (const HallDTO &hall : halls) { hallIdToReservationManager_[hall.hallId()] = reservationReference_; } if (hallIdToReservationManager_.isEmpty()) { qFatal() << "Failed to initialize hallIdToReservationManager"; } qInfo() << "Number of halls:" << hallIdToReservationManager_.size(); } RepositoryResult SessionGenerator::createRecord() { CreateSessionRequest request; request.setBeginAt(reservationContext_.beginAt); request.setHallId(reservationContext_.hallId); request.setMovieId(reservationContext_.movieId); request.setTicketPrice(reservationContext_.ticketPrice); RepositoryResult result = sessionsRepository_->createSession(request); return result; } QString SessionGenerator::createFailureMessage(const QString &errorMessage) const { QString additionalInfo = QString("Additional info: Hall id: %1 Begin at: %2") .arg(reservationContext_.hallId) .arg(reservationContext_.beginAt.toString("yyyy-MM-dd hh:mm:ss")); QString failureMessage = "Failure:\n\t%1\n\tError message: %2"; return failureMessage.arg(additionalInfo).arg(errorMessage); } QString SessionGenerator::createSuccessMessage() const { qint32 hallId = reservationContext_.hallId; const ReservationManager &manager = hallIdToReservationManager_.value(hallId); QTime duration = calculateDuration(reservationContext_); // return QString("Success: TAD: %1 TAS: %2 EId: %3 AD: %4 AS: %5 CR: %6 B: %7 // D: %8") return QString("Success: TAD: %1 TAS: %2 EId: %3 AD: %4 AS: %5 CR: %6") .arg(calculateAvailableDaysCount()) // Total available days .arg(calculateAvailableSlotsCount()) // Total available slots .arg(hallId) // Entity id .arg(manager.calculateAvailableDaysCount()) // Available days for the // current hall .arg(manager.calculateAvailableSlotsCount()) // Available slots for the // current hall .arg(manager.createdRecords()); // Created records for the // current hall // .arg(reservationContext_.beginAt.toString( // // "yyyy-MM-dd hh:mm:ss")) // Begin // // of created record // .arg(duration.toString("hh:mm:ss")); // Duration of created record } qsizetype SessionGenerator::calculateRemainingCapacity() const { // Maximum number of sessions that can be created return std::accumulate(hallIdToReservationManager_.cbegin(), hallIdToReservationManager_.cend(), 0, [&](qsizetype sum, const ReservationManager &manager) { return sum + manager.calculatePossibleReservations( lowerBoundReservationMs_); }); }; bool SessionGenerator::prepareData() { std::random_device rd; std::mt19937 g{rd()}; QList hallIds = hallIdToReservationManager_.keys(); std::shuffle(hallIds.begin(), hallIds.end(), g); QList movieIds = movieIdToDurationMinutes_.keys(); std::shuffle(movieIds.begin(), movieIds.end(), g); for (qint32 hallId : hallIds) { if (prepareData(hallId, movieIds)) { return true; } } qWarning() << "No available halls"; return false; } bool SessionGenerator::prepareData(qint32 hallId, const QList &movieIds) { for (qint32 movieId : movieIds) { ReservationManager &manager = hallIdToReservationManager_[hallId]; auto [beginDateTime, endTime] = manager.reserve(duration(movieId)); if (!beginDateTime.isValid() || !endTime.isValid()) { continue; } const QDate epochDate = QDateTime::fromMSecsSinceEpoch(0).date(); const qint64 deltaDays = epochDate.daysTo(QDate(2025, 1, 1)); const QDate newBeginDate = beginDateTime.date().addDays(deltaDays); const QTime beginTime = beginDateTime.time(); reservationContext_ = ReservationContext{ QDateTime(std::move(newBeginDate), std::move(beginTime)), std::move(endTime), bounded(10'000, 50'000) / 100.0, hallId, movieId, }; return true; } qCritical() << "SessionGenerator::prepareData: No available movies for hall with id" << hallId; return false; } QTime SessionGenerator::duration(qint32 movieId) const { qint32 durationMin = movieIdToDurationMinutes_[movieId]; qint64 durationMs = durationMin * 60'000; // 60 * 1000 QTime durationTime = QTime::fromMSecsSinceStartOfDay(durationMs); return durationTime; } qsizetype SessionGenerator::calculateAvailableDaysCount() const { return std::accumulate(hallIdToReservationManager_.cbegin(), hallIdToReservationManager_.cend(), 0, [&](int sum, const ReservationManager &manager) { return sum + manager.calculateAvailableDaysCount(); }); } qsizetype SessionGenerator::calculateAvailableSlotsCount() const { return std::accumulate(hallIdToReservationManager_.cbegin(), hallIdToReservationManager_.cend(), 0, [&](int sum, const ReservationManager &manager) { return sum + manager.calculateAvailableSlotsCount(); }); } QTime SessionGenerator::calculateDuration(ReservationContext context) const { QTime beginTime = context.beginAt.time(); QTime endTime = context.endTime; qint64 durationMs = beginTime.msecsTo(endTime); return QTime::fromMSecsSinceStartOfDay(durationMs); } void SessionGenerator::clearStaleData() { qint64 hallId = reservationContext_.hallId; if (hallIdToReservationManager_[hallId].calculateAvailableDaysCount() == 0) { qWarning() << "No available days for hall" << hallId; hallIdToReservationManager_.remove(hallId); } }