255 lines
9.4 KiB
C++
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);
|
||
|
|
}
|
||
|
|
}
|