diff --git a/3party/opening_hours/opening_hours.cpp b/3party/opening_hours/opening_hours.cpp index 342a339153..e847d45615 100644 --- a/3party/opening_hours/opening_hours.cpp +++ b/3party/opening_hours/opening_hours.cpp @@ -26,7 +26,9 @@ #include "rules_evaluation.hpp" #include "parse_opening_hours.hpp" +#include #include +#include #include #include #include @@ -748,4 +750,28 @@ bool OpeningHours::IsValid() const { return m_valid; } +bool OpeningHours::IsTwentyFourHours() const +{ + return m_rule.size() == 1 && m_rule[0].IsTwentyFourHours(); +} + +bool OpeningHours::HasWeekdaySelector() const +{ + return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasWeekdays)); +} + +bool OpeningHours::HasMonthSelector() const +{ + return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasMonths)); +} + +bool OpeningHours::HasWeekSelector() const +{ + return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasWeeks)); +} + +bool OpeningHours::HasYearSelector() const +{ + return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasYears)); +} } // namespace osmoh diff --git a/3party/opening_hours/opening_hours.hpp b/3party/opening_hours/opening_hours.hpp index 31594695f4..d9f229f80b 100644 --- a/3party/opening_hours/opening_hours.hpp +++ b/3party/opening_hours/opening_hours.hpp @@ -69,6 +69,16 @@ private: HourMinutes operator-(HourMinutes const & hm); std::ostream & operator<<(std::ostream & ost, HourMinutes const & hm); +inline bool operator<(HourMinutes const & a, HourMinutes const & b) +{ + return a.GetDuration() < b.GetDuration(); +} + +inline bool operator==(HourMinutes const & a, HourMinutes const & b) +{ + return a.GetDuration() == b.GetDuration(); +} + class Time; class TimeEvent @@ -661,6 +671,13 @@ public: bool IsValid() const; + bool IsTwentyFourHours() const; + bool HasWeekdaySelector() const; + bool HasMonthSelector() const; + bool HasWeekSelector() const; + bool HasYearSelector() const; + + TRuleSequences const & GetRule() const { return m_rule; } private: TRuleSequences m_rule; bool const m_valid; diff --git a/3party/opening_hours/rules_evaluation.cpp b/3party/opening_hours/rules_evaluation.cpp index 8f951195e4..1ea5490e73 100644 --- a/3party/opening_hours/rules_evaluation.cpp +++ b/3party/opening_hours/rules_evaluation.cpp @@ -196,6 +196,8 @@ std::tm MakeTimetuple(time_t const timestamp) namespace osmoh { +using ::operator==; + bool IsActive(Timespan const & span, std::tm const & time) { // Timespan with e.h. should be split into parts with no e.h. diff --git a/editor/editor_tests/editor_tests.pro b/editor/editor_tests/editor_tests.pro index 5d176882f1..aac55b6519 100644 --- a/editor/editor_tests/editor_tests.pro +++ b/editor/editor_tests/editor_tests.pro @@ -16,3 +16,4 @@ SOURCES += \ $$ROOT_DIR/testing/testingmain.cpp \ opening_hours_ui_test.cpp \ xml_feature_test.cpp \ + ui2oh_test.cpp \ diff --git a/editor/editor_tests/ui2oh_test.cpp b/editor/editor_tests/ui2oh_test.cpp new file mode 100644 index 0000000000..2bed9f8432 --- /dev/null +++ b/editor/editor_tests/ui2oh_test.cpp @@ -0,0 +1,113 @@ +#include "testing/testing.hpp" + +#include "editor/ui2oh.hpp" + +using namespace osmoh; +using namespace editor; +using namespace editor::ui; + +UNIT_TEST(ConvertOpeningHours) +{ + { + OpeningHours oh("Mo-Fr 08:00-22:00"); + TEST(oh.IsValid(), ()); + + TimeTableSet tts; + + TEST(ConvertOpeningHours(oh, tts), ()); + TEST_EQUAL(tts.Size(), 1, ()); + + auto const tt = tts.Front(); + TEST(!tt.IsTwentyFourHours(), ()); + TEST_EQUAL(tt.GetWorkingDays().size(), 5, ()); + TEST_EQUAL(tt.GetOpeningTime().GetStart().GetHourMinutes().GetHoursCount(), 8, ()); + TEST_EQUAL(tt.GetOpeningTime().GetEnd().GetHourMinutes().GetHoursCount(), 22, ()); + } + { + OpeningHours oh("Mo-Fr 08:00-12:00, 13:00-22:00"); + TEST(oh.IsValid(), ()); + + TimeTableSet tts; + + TEST(ConvertOpeningHours(oh, tts), ()); + TEST_EQUAL(tts.Size(), 1, ()); + + auto const tt = tts.Front(); + TEST(!tt.IsTwentyFourHours(), ()); + TEST_EQUAL(tt.GetWorkingDays().size(), 5, ()); + TEST_EQUAL(tt.GetOpeningTime().GetStart().GetHourMinutes().GetHoursCount(), 8, ()); + TEST_EQUAL(tt.GetOpeningTime().GetEnd().GetHourMinutes().GetHoursCount(), 22, ()); + + TEST_EQUAL(tt.GetExcludeTime().size(), 1, ()); + TEST_EQUAL(tt.GetExcludeTime()[0].GetStart().GetHourMinutes().GetHoursCount(), 12, ()); + TEST_EQUAL(tt.GetExcludeTime()[0].GetEnd().GetHourMinutes().GetHoursCount(), 13, ()); + } + { + OpeningHours oh("Mo-Fr 08:00-10:00, 11:00-12:30, 13:00-22:00"); + TEST(oh.IsValid(), ()); + + TimeTableSet tts; + + TEST(ConvertOpeningHours(oh, tts), ()); + TEST_EQUAL(tts.Size(), 1, ()); + + auto const tt = tts.Front(); + TEST(!tt.IsTwentyFourHours(), ()); + TEST_EQUAL(tt.GetWorkingDays().size(), 5, ()); + TEST_EQUAL(tt.GetOpeningTime().GetStart().GetHourMinutes().GetHoursCount(), 8, ()); + TEST_EQUAL(tt.GetOpeningTime().GetEnd().GetHourMinutes().GetHoursCount(), 22, ()); + + TEST_EQUAL(tt.GetExcludeTime().size(), 2, ()); + TEST_EQUAL(tt.GetExcludeTime()[0].GetStart().GetHourMinutes().GetHoursCount(), 10, ()); + TEST_EQUAL(tt.GetExcludeTime()[0].GetEnd().GetHourMinutes().GetHoursCount(), 11, ()); + TEST_EQUAL(tt.GetExcludeTime()[1].GetStart().GetHourMinutes().GetHoursCount(), 12, ()); + TEST_EQUAL(tt.GetExcludeTime()[1].GetEnd().GetHourMinutes().GetHoursCount(), 13, ()); + TEST_EQUAL(tt.GetExcludeTime()[1].GetStart().GetHourMinutes().GetMinutesCount(), 30, ()); + TEST_EQUAL(tt.GetExcludeTime()[1].GetEnd().GetHourMinutes().GetMinutesCount(), 0, ()); + } + { + OpeningHours oh("Mo-Fr 08:00-10:00; Su, Sa 13:00-22:00"); + TEST(oh.IsValid(), ()); + + TimeTableSet tts; + + TEST(ConvertOpeningHours(oh, tts), ()); + TEST_EQUAL(tts.Size(), 2, ()); + + { + auto const tt = tts.Get(0); + TEST(!tt.IsTwentyFourHours(), ()); + TEST_EQUAL(tt.GetWorkingDays().size(), 5, ()); + } + + { + auto const tt = tts.Get(1); + TEST(!tt.IsTwentyFourHours(), ()); + TEST_EQUAL(tt.GetWorkingDays().size(), 2, ()); + } + } + { + OpeningHours oh("Jan Mo-Fr 08:00-10:00"); + TEST(oh.IsValid(), ()); + + TimeTableSet tts; + + TEST(!ConvertOpeningHours(oh, tts), ()); + } + { + OpeningHours oh("2016 Mo-Fr 08:00-10:00"); + TEST(oh.IsValid(), ()); + + TimeTableSet tts; + + TEST(!ConvertOpeningHours(oh, tts), ()); + } + { + OpeningHours oh("week 30 Mo-Fr 08:00-10:00"); + TEST(oh.IsValid(), ()); + + TimeTableSet tts; + + TEST(!ConvertOpeningHours(oh, tts), ()); + } +} diff --git a/editor/opening_hours_ui.cpp b/editor/opening_hours_ui.cpp index ba6a6ead46..0d85f57d77 100644 --- a/editor/opening_hours_ui.cpp +++ b/editor/opening_hours_ui.cpp @@ -48,18 +48,17 @@ bool FixTimeSpans(osmoh::Timespan openingTime, osmoh::TTimespans & spans) span.GetEnd().GetHourMinutes().AddDuration(24_h); } - sort(begin(spans), end(spans), - [](osmoh::Timespan const & s1, osmoh::Timespan const s2) - { - auto const start1 = s1.GetStart().GetHourMinutes().GetDuration(); - auto const start2 = s2.GetStart().GetHourMinutes().GetDuration(); + sort(begin(spans), end(spans), [](osmoh::Timespan const & s1, osmoh::Timespan const s2) + { + auto const start1 = s1.GetStart().GetHourMinutes(); + auto const start2 = s2.GetStart().GetHourMinutes(); - // If two spans start at the same point the longest span should be leftmost. - if (start1 == start2) - return SpanLength(s1) > SpanLength(s2); + // If two spans start at the same point the longest span should be leftmost. + if (start1 == start2) + return SpanLength(s1) > SpanLength(s2); - return start1 < start2; - }); + return start1 < start2; + }); osmoh::TTimespans result{spans.front()}; for (auto i = 1, j = 0; i < spans.size(); ++i) diff --git a/editor/ui2oh.cpp b/editor/ui2oh.cpp index 6ba3b24723..0b348e60d6 100644 --- a/editor/ui2oh.cpp +++ b/editor/ui2oh.cpp @@ -1,19 +1,95 @@ #include "editor/ui2oh.hpp" +#include "base/enumerate.hpp" + +#include "std/algorithm.hpp" #include "std/array.hpp" #include "std/string.hpp" #include "3party/opening_hours/opening_hours.hpp" +namespace +{ +void SetUpWeekdays(osmoh::Weekdays const & wds, editor::ui::TimeTable & tt) +{ + set workingDays; + for (auto const & wd : wds.GetWeekdayRanges()) + { + if (wd.HasSunday()) + workingDays.insert(osmoh::Weekday::Sunday); + if (wd.HasMonday()) + workingDays.insert(osmoh::Weekday::Monday); + if (wd.HasTuesday()) + workingDays.insert(osmoh::Weekday::Tuesday); + if (wd.HasWednesday()) + workingDays.insert(osmoh::Weekday::Wednesday); + if (wd.HasThursday()) + workingDays.insert(osmoh::Weekday::Thursday); + if (wd.HasFriday()) + workingDays.insert(osmoh::Weekday::Friday); + if (wd.HasSaturday()) + workingDays.insert(osmoh::Weekday::Saturday); + } + tt.SetWorkingDays(workingDays); +} + +void SetUpTimeTable(osmoh::TTimespans spans, editor::ui::TimeTable & tt) +{ + using namespace osmoh; + + sort(begin(spans), end(spans), [](Timespan const & a, Timespan const & b) + { + auto const start1 = a.GetStart().GetHourMinutes().GetDuration(); + auto const start2 = b.GetStart().GetHourMinutes().GetDuration(); + + return start1 < start2; + }); + + // Take first start and last end as opening time span. + tt.SetOpeningTime({spans.front().GetStart(), spans.back().GetEnd()}); + + // Add an end of a span of index i and start of following span + // as exclude time. + for (auto i = 0; i + 1 < spans.size(); ++i) + tt.AddExcludeTime({spans[i].GetEnd(), spans[i + 1].GetStart()}); +} +} // namespace + namespace editor { osmoh::OpeningHours ConvertOpeningHours(ui::TimeTableSet const & tt) { - return string(); // TODO(mgsergio): // Just a dummy. + return string(); // TODO(mgsergio): Implement me. } -ui::TimeTableSet ConvertOpeningHours(osmoh::OpeningHours const & oh) +bool ConvertOpeningHours(osmoh::OpeningHours const & oh, ui::TimeTableSet & tts) { - return {}; + if (oh.HasYearSelector() || oh.HasWeekSelector() || oh.HasMonthSelector()) + return false; + + tts = ui::TimeTableSet(); + if (oh.IsTwentyFourHours()) + return true; + + for (auto const & p : my::enumerate(oh.GetRule())) + { + auto const & rulePart = p.item; + ui::TimeTable tt; + + if (rulePart.HasWeekdays()) + SetUpWeekdays(rulePart.GetWeekdays(), tt); + + if (rulePart.HasTimes()) + { + tt.SetTwentyFourHours(false); + SetUpTimeTable(rulePart.GetTimes(), tt); + } + + bool const appended = p.index == 0 ? tts.Replace(tt, 0) : tts.Append(tt); + if (!appended) + return false; + } + + return true; } } // namespace editor diff --git a/editor/ui2oh.hpp b/editor/ui2oh.hpp index 636fdb917e..3cf31a7e43 100644 --- a/editor/ui2oh.hpp +++ b/editor/ui2oh.hpp @@ -9,6 +9,6 @@ class OpeningHours; namespace editor { -osmoh::OpeningHours ConvertOpeningHours(ui::TimeTableSet const & tt); -ui::TimeTableSet ConvertOpeningHours(osmoh::OpeningHours const & oh); +osmoh::OpeningHours ConvertOpeningHours(ui::TimeTableSet const & tts); +bool ConvertOpeningHours(osmoh::OpeningHours const & oh, ui::TimeTableSet & tts); } // namespace editor