File indexing completed on 2024-12-01 04:19:21
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KOPENINGHOURS_SELECTORS_P_H 0008 #define KOPENINGHOURS_SELECTORS_P_H 0009 0010 #include "interval.h" 0011 0012 #include <memory> 0013 0014 namespace KOpeningHours { 0015 0016 class OpeningHoursPrivate; 0017 0018 namespace Capability { 0019 enum RequiredCapabilities { 0020 None = 0, 0021 PublicHoliday = 1, 0022 SchoolHoliday = 2, 0023 Location = 4, 0024 NotImplemented = 8, 0025 Interval = 16, 0026 PointInTime = 32, 0027 }; 0028 } 0029 0030 /** Result from selector evaluation. */ 0031 class SelectorResult { 0032 public: 0033 /** Selector will never match. */ 0034 inline SelectorResult(bool = false) : m_matching(false) {} 0035 /** Selector will match in @p offset seconds. */ 0036 inline SelectorResult(qint64 offset) 0037 : m_offset(offset) 0038 , m_matching(offset >= 0) 0039 {} 0040 /** Selector matches for @p interval. */ 0041 inline SelectorResult(const Interval &interval) : m_interval(interval) {} 0042 0043 inline bool operator<(const SelectorResult &other) const { 0044 if (m_matching == other.m_matching) { 0045 if (m_offset == other.m_offset) { 0046 return m_interval < other.m_interval; 0047 } 0048 return m_offset < other.m_offset; 0049 } 0050 return m_matching && !other.m_matching; 0051 } 0052 0053 inline bool canMatch() const { return m_matching; } 0054 inline int64_t matchOffset() const { return m_offset; } 0055 inline Interval interval() const { return m_interval; } 0056 0057 private: 0058 Interval m_interval; 0059 int64_t m_offset = 0; 0060 bool m_matching = true; 0061 }; 0062 0063 // see https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification, the below names/types follow that 0064 0065 template <typename T> 0066 void appendSelector(T* firstSelector, std::unique_ptr<T> &&selector) 0067 { 0068 while(firstSelector->next) { 0069 firstSelector = firstSelector->next.get(); 0070 } 0071 firstSelector->next = std::move(selector); 0072 } 0073 0074 template <typename T> 0075 void appendSelector(T* firstSelector, T* selector) 0076 { 0077 return appendSelector(firstSelector, std::unique_ptr<T>(selector)); 0078 } 0079 0080 template <typename T> 0081 T* lastSelector(T* firstSelector) 0082 { 0083 while (firstSelector && firstSelector->next) { 0084 firstSelector = firstSelector->next.get(); 0085 } 0086 return firstSelector; 0087 } 0088 0089 /** Time */ 0090 class Time 0091 { 0092 public: 0093 static bool isValid(Time t); 0094 static void convertFromAm(Time &t); 0095 static void convertFromPm(Time &t); 0096 static Time parse(const char *begin, const char *end); 0097 QByteArray toExpression(bool end) const; 0098 0099 enum Event { 0100 NoEvent, 0101 Dawn, 0102 Sunrise, 0103 Sunset, 0104 Dusk, 0105 }; 0106 Event event; 0107 int hour; 0108 int minute; 0109 0110 }; 0111 0112 inline constexpr bool operator==(Time lhs, Time rhs) 0113 { 0114 return lhs.event == rhs.event 0115 && lhs.hour == rhs.hour 0116 && lhs.minute == rhs.minute; 0117 } 0118 0119 /** Time span selector. */ 0120 class Timespan 0121 { 0122 public: 0123 int requiredCapabilities() const; 0124 bool isMultiDay(QDate date, OpeningHoursPrivate *context) const; 0125 SelectorResult nextInterval(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; 0126 QByteArray toExpression() const; 0127 Time adjustedEnd() const; 0128 bool operator==(Timespan &other) const; 0129 0130 Time begin = { Time::NoEvent, -1, -1 }; 0131 Time end = { Time::NoEvent, -1, -1 }; 0132 int interval = 0; 0133 bool openEnd = false; 0134 bool pointInTime = false; 0135 std::unique_ptr<Timespan> next; 0136 }; 0137 0138 struct NthEntry { 0139 int begin; 0140 int end; 0141 QByteArray toExpression() const; 0142 }; 0143 0144 /** Nth week days, like 1-2,4,6-8 */ 0145 class NthSequence 0146 { 0147 public: 0148 void add(NthEntry range); 0149 QByteArray toExpression() const; 0150 std::vector<NthEntry> sequence; 0151 }; 0152 0153 /** Weekday range. */ 0154 class WeekdayRange 0155 { 0156 public: 0157 int requiredCapabilities() const; 0158 SelectorResult nextInterval(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; 0159 SelectorResult nextIntervalLocal(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; 0160 QByteArray toExpression() const; 0161 void simplify(); 0162 0163 uint8_t beginDay = 0; // Mo=1, Tu=2, ..., Su=7 0164 uint8_t endDay = 0; 0165 std::unique_ptr<NthSequence> nthSequence; 0166 int16_t offset = 0; 0167 enum Holiday : uint8_t { 0168 NoHoliday = 0, 0169 PublicHoliday = 1, 0170 SchoolHoliday = 2, 0171 }; 0172 Holiday holiday = NoHoliday; 0173 std::unique_ptr<WeekdayRange> next; 0174 std::unique_ptr<WeekdayRange> lhsAndSelector; 0175 std::unique_ptr<WeekdayRange> rhsAndSelector; 0176 }; 0177 0178 /** Week */ 0179 class Week 0180 { 0181 public: 0182 int requiredCapabilities() const; 0183 SelectorResult nextInterval(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; 0184 QByteArray toExpression() const; 0185 0186 uint8_t beginWeek = 0; 0187 uint8_t endWeek = 0; 0188 uint8_t interval = 1; 0189 std::unique_ptr<Week> next; 0190 }; 0191 0192 /** Day or weekday-based offset to a Date. */ 0193 class DateOffset 0194 { 0195 public: 0196 bool operator==(DateOffset other) const; 0197 DateOffset &operator+=(DateOffset other); 0198 0199 int16_t dayOffset; 0200 int8_t weekday; 0201 int8_t nthWeekday; 0202 }; 0203 0204 class MonthdayRange; 0205 0206 /** Date */ 0207 class Date 0208 { 0209 public: 0210 QByteArray toExpression(const Date &refDate, const MonthdayRange &prev) const; 0211 bool operator==(Date other) const; 0212 bool operator!=(Date other) const { return !operator==(other); } 0213 bool hasOffset() const; 0214 0215 int year; 0216 int month; 0217 int day; 0218 enum VariableDate : uint8_t { 0219 FixedDate, 0220 Easter 0221 }; 0222 VariableDate variableDate; 0223 DateOffset offset; 0224 }; 0225 0226 /** Monthday range. */ 0227 class MonthdayRange 0228 { 0229 public: 0230 int requiredCapabilities() const; 0231 SelectorResult nextInterval(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; 0232 QByteArray toExpression(const MonthdayRange &prev) const; 0233 void simplify(); 0234 0235 Date begin = { 0, 0, 0, Date::FixedDate, { 0, 0, 0 } }; 0236 Date end = { 0, 0, 0, Date::FixedDate, { 0, 0, 0 } }; 0237 std::unique_ptr<MonthdayRange> next; 0238 }; 0239 0240 /** Year range. */ 0241 class YearRange 0242 { 0243 public: 0244 int requiredCapabilities() const; 0245 SelectorResult nextInterval(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; 0246 QByteArray toExpression() const; 0247 0248 int begin = 0; 0249 int end = 0; 0250 int interval = 1; 0251 std::unique_ptr<YearRange> next; 0252 }; 0253 } 0254 0255 #endif // KOPENINGHOURS_SELECTORS_P_H