#include "reservation_manager.h" #include ReservationManager::ReservationManager(qsizetype dayRange, qsizetype dayBound, const DayManager &reference) : createdRecords_(0), dayBound_(dayBound), dayRange_(dayRange), excludedDays_(0), lastIndex_(-1), dayReference_(reference) { prepareDaysRange(); } void ReservationManager::setReference(const DayManager &reference) { dayReference_ = reference; days_.clear(); lastIndex_ = -1; prepareDaysRange(); } qsizetype ReservationManager::calculateAvailableDaysCount() const { qsizetype bound = dayBound_ != -1 ? dayBound_ : std::numeric_limits::max(); return bound - excludedDays_; } qsizetype ReservationManager::calculatePossibleReservations(qint64 requiredMs) const { qsizetype possibleReservations = std::accumulate( days_.cbegin(), days_.cend(), 0, [&](qsizetype sum, const DayManager manager) { return sum + manager.calculatePossibleReservations(requiredMs); }); qsizetype possibleReservationsByReference = dayReference_.calculatePossibleReservations(requiredMs); qsizetype futureReservationsCount = calculateAvailableDaysCount() - days_.size(); return possibleReservations + possibleReservationsByReference * futureReservationsCount; } qsizetype ReservationManager::calculateAvailableSlotsCount() const { return std::accumulate(days_.cbegin(), days_.cend(), 0, [&](qsizetype sum, const DayManager manager) { return sum + manager.slotCount(); }); } QPair ReservationManager::reserve(const QTime &duration) { if (!duration.isValid()) { qWarning() << "ReservationManager::reserve: duration is invalid"; return {}; } const qint64 requiredMs = duration.msecsSinceStartOfDay(); if (requiredMs <= 0) { qWarning() << "ReservationManager::reserve: duration should be greater than 0"; return {}; } if (days_.isEmpty()) { qWarning() << "ReservationManager::reserve: no available days"; return {}; } std::mt19937 g{std::random_device{}()}; QList dayIndexes = days_.keys(); std::shuffle(dayIndexes.begin(), dayIndexes.end(), g); for (qsizetype dayIndex : dayIndexes) { QPair result = reserve(dayIndex, duration); const auto &[beginDateTime, endTime] = result; if (beginDateTime.isValid() && endTime.isValid()) { ++createdRecords_; return result; } } // qWarning() << "ReservationManager::reserve: reservation failed"; return {}; } DayManager &ReservationManager::dayManager(qsizetype dayIndex) { auto it = days_.find(dayIndex); if (it != days_.end()) { return it.value(); } qCritical() << "ReservationManager::dayManager: dayIndex is out of range"; throw std::out_of_range("dayIndex is out of range"); } QPair ReservationManager::reserve(qsizetype dayIndex, const QTime &duration) { QTime beginTime, endTime; DayManager &dayManagerValue = dayManager(dayIndex); std::tie(beginTime, endTime) = dayManagerValue.reserve(duration); if (!dayManagerValue.duration().isValid()) { days_.remove(dayIndex); ++excludedDays_; } prepareDaysRange(); // Add new days after excluded days QDate beginDate = QDateTime::fromMSecsSinceEpoch(0).date().addDays(dayIndex); QDateTime beginDateTime(beginDate, beginTime); return {std::move(beginDateTime), std::move(endTime)}; } void ReservationManager::prepareDaysRange() { if (!dayReference_.duration().isValid()) { qWarning() << "ReservationManager::prepareDaysRange: reference is invalid"; return; } auto condition = [this](qsizetype currentSize) { qsizetype bound = dayBound_ != -1 ? dayBound_ : std::numeric_limits::max(); if (lastIndex_ + 1 < bound) { return currentSize < dayRange_; } return false; }; for (qsizetype size = days_.size(); condition(size); ++size) { days_[++lastIndex_] = DayManager(dayReference_); } }