mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-05-15 20:33:56 +02:00
158 lines
4.5 KiB
C++
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
|