Files
2026-07-12 14:34:52 +04:00

255 lines
9.4 KiB
C++

#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<MoviesRepository>(
metadata.repositoryTableName("movies"));
hallsRepository_ = repositoryManager.getRepositoryAs<HallsRepository>(
metadata.repositoryTableName("halls"));
sessionsRepository_ = repositoryManager.getRepositoryAs<SessionsRepository>(
metadata.repositoryTableName("sessions"));
if (!bool(moviesRepository_ && hallsRepository_ && sessionsRepository_)) {
qFatal() << "Failed to initialize repositories";
}
}
void SessionGenerator::initializeMovieIdToDurationMap(
qint32 additionalMinutes) {
QVector<MovieDTO> 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<HallDTO> 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<qint32> hallIds = hallIdToReservationManager_.keys();
std::shuffle(hallIds.begin(), hallIds.end(), g);
QList<qint32> 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<qint32> &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);
}
}