AyuGramDesktop/Telegram/SourceFiles/data/business/data_business_common.cpp
2024-03-08 10:53:58 +04:00

158 lines
4.5 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/business/data_business_common.h"
namespace Data {
namespace {
constexpr auto kDay = WorkingInterval::kDay;
constexpr auto kWeek = WorkingInterval::kWeek;
constexpr auto kInNextDayMax = WorkingInterval::kInNextDayMax;
[[nodiscard]] WorkingIntervals SortAndMerge(WorkingIntervals intervals) {
auto &list = intervals.list;
ranges::sort(list, ranges::less(), &WorkingInterval::start);
for (auto i = 0, count = int(list.size()); i != count; ++i) {
if (i && list[i] && list[i -1] && list[i].start <= list[i - 1].end) {
list[i - 1] = list[i - 1].united(list[i]);
list[i] = {};
}
if (!list[i]) {
list.erase(list.begin() + i);
--i;
--count;
}
}
return intervals;
}
[[nodiscard]] WorkingIntervals MoveTailToFront(WorkingIntervals intervals) {
auto &list = intervals.list;
auto after = WorkingInterval{ kWeek, kWeek + kDay };
while (!list.empty()) {
if (const auto tail = list.back().intersected(after)) {
list.back().end = tail.start;
if (!list.back()) {
list.pop_back();
}
list.insert(begin(list), tail.shifted(-kWeek));
} else {
break;
}
}
return intervals;
}
} // namespace
WorkingIntervals WorkingIntervals::normalized() const {
return SortAndMerge(MoveTailToFront(SortAndMerge(*this)));
}
WorkingIntervals ExtractDayIntervals(
const WorkingIntervals &intervals,
int dayIndex) {
Expects(dayIndex >= 0 && dayIndex < 7);
auto result = WorkingIntervals();
auto &list = result.list;
for (const auto &interval : intervals.list) {
const auto now = interval.intersected(
{ (dayIndex - 1) * kDay, (dayIndex + 2) * kDay });
const auto after = interval.intersected(
{ (dayIndex + 6) * kDay, (dayIndex + 9) * kDay });
const auto before = interval.intersected(
{ (dayIndex - 8) * kDay, (dayIndex - 5) * kDay });
if (now) {
list.push_back(now.shifted(-dayIndex * kDay));
}
if (after) {
list.push_back(after.shifted(-(dayIndex + 7) * kDay));
}
if (before) {
list.push_back(before.shifted(-(dayIndex - 7) * kDay));
}
}
result = result.normalized();
const auto outside = [&](WorkingInterval interval) {
return (interval.end <= 0) || (interval.start >= kDay);
};
list.erase(ranges::remove_if(list, outside), end(list));
if (!list.empty() && list.back().start <= 0 && list.back().end >= kDay) {
list.back() = { 0, kDay };
} else if (!list.empty() && (list.back().end > kDay + kInNextDayMax)) {
list.back() = list.back().intersected({ 0, kDay });
}
if (!list.empty() && list.front().start <= 0) {
if (list.front().start < 0
&& list.front().end <= kInNextDayMax
&& list.front().start > -kDay) {
list.erase(begin(list));
} else {
list.front() = list.front().intersected({ 0, kDay });
if (!list.front()) {
list.erase(begin(list));
}
}
}
return result;
}
WorkingIntervals RemoveDayIntervals(
const WorkingIntervals &intervals,
int dayIndex) {
auto result = intervals.normalized();
auto &list = result.list;
const auto day = WorkingInterval{ 0, kDay };
const auto shifted = day.shifted(dayIndex * kDay);
auto before = WorkingInterval{ 0, shifted.start };
auto after = WorkingInterval{ shifted.end, kWeek };
for (auto i = 0, count = int(list.size()); i != count; ++i) {
if (list[i].end <= shifted.start || list[i].start >= shifted.end) {
continue;
} else if (list[i].end <= shifted.start + kInNextDayMax
&& (list[i].start < shifted.start
|| (!dayIndex // This 'Sunday' finishing on next day <= 6:00.
&& list[i].start == shifted.start
&& list.back().end >= kWeek))) {
continue;
} else if (const auto first = list[i].intersected(before)) {
list[i] = first;
if (const auto second = list[i].intersected(after)) {
list.push_back(second);
}
} else if (const auto second = list[i].intersected(after)) {
list[i] = second;
} else {
list.erase(list.begin() + i);
--i;
--count;
}
}
return result.normalized();
}
WorkingIntervals ReplaceDayIntervals(
const WorkingIntervals &intervals,
int dayIndex,
WorkingIntervals replacement) {
auto result = RemoveDayIntervals(intervals, dayIndex);
const auto first = result.list.insert(
end(result.list),
begin(replacement.list),
end(replacement.list));
for (auto &interval : ranges::subrange(first, end(result.list))) {
interval = interval.shifted(dayIndex * kDay);
}
return result.normalized();
}
} // namespace Data