132 lines
4.1 KiB
C++
132 lines
4.1 KiB
C++
|
|
#include "reservation_manager.h"
|
||
|
|
|
||
|
|
#include <QRandomGenerator>
|
||
|
|
|
||
|
|
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<qsizetype>::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<QDateTime, QTime> 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<qsizetype> dayIndexes = days_.keys();
|
||
|
|
std::shuffle(dayIndexes.begin(), dayIndexes.end(), g);
|
||
|
|
|
||
|
|
for (qsizetype dayIndex : dayIndexes) {
|
||
|
|
QPair<QDateTime, QTime> 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<QDateTime, QTime> 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<qsizetype>::max();
|
||
|
|
if (lastIndex_ + 1 < bound) {
|
||
|
|
return currentSize < dayRange_;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
|
||
|
|
for (qsizetype size = days_.size(); condition(size); ++size) {
|
||
|
|
days_[++lastIndex_] = DayManager(dayReference_);
|
||
|
|
}
|
||
|
|
}
|