Simple mode can handle oh rules with off modifier.

This commit is contained in:
Sergey Magidovich 2016-03-31 14:14:35 +03:00
parent a277fd0921
commit 1755f619c9
4 changed files with 255 additions and 13 deletions

View file

@ -793,6 +793,11 @@ BOOST_AUTO_TEST_CASE(OpeningHoursWeekdays_TestParseUnparse)
auto const parsedUnparsed = ParseAndUnparse<osmoh::Weekdays>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
auto const rule = "Sa";
auto const parsedUnparsed = ParseAndUnparse<osmoh::Weekdays>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
}
BOOST_AUTO_TEST_CASE(OpeningHoursMonthdayRanges_TestParseUnparse)
@ -1063,6 +1068,12 @@ BOOST_AUTO_TEST_CASE(OpeningHoursRuleSequence_TestParseUnparse)
{
auto const rule = "Mo-Fr closed \"always closed\"";
auto const parsedUnparsed = ParseAndUnparse<osmoh::TRuleSequences>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
auto const rule = "Sa; Su";
auto const parsedUnparsed = ParseAndUnparse<osmoh::TRuleSequences>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}

View file

@ -16,7 +16,7 @@ string ToString(OpeningHours const & oh)
}
} // namespace
UNIT_TEST(OpeningHours2TimeTableSt)
UNIT_TEST(OpeningHours2TimeTableSet)
{
{
OpeningHours oh("08:00-22:00");
@ -192,14 +192,120 @@ UNIT_TEST(OpeningHours2TimeTableSt)
TEST_EQUAL(tt.GetOpeningDays().size(), 1, ());
}
}
}
UNIT_TEST(OpeningHours2TimeTableSet_off)
{
{
// We don't handle offs for for now.
OpeningHours oh("Mo-Fr 08:00-13:00,14:00-20:00; Sa 09:00-13:00,14:00-18:00; Su off");
OpeningHours oh("Mo-Fr 08:00-13:00,14:00-20:00; Su off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(!MakeTimeTableSet(oh, tts), ());
TEST(MakeTimeTableSet(oh, tts), ());
}
{
OpeningHours oh("Mo-Su 08:00-13:00,14:00-20:00; Sa off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(MakeTimeTableSet(oh, tts), ());
TEST_EQUAL(tts.GetUnhandledDays(), TOpeningDays({osmoh::Weekday::Saturday}), ());
}
{
OpeningHours oh("Sa; Su; Sa off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(MakeTimeTableSet(oh, tts), ());
TEST_EQUAL(tts.GetUnhandledDays(),
TOpeningDays({osmoh::Weekday::Monday,
osmoh::Weekday::Tuesday,
osmoh::Weekday::Wednesday,
osmoh::Weekday::Thursday,
osmoh::Weekday::Friday,
osmoh::Weekday::Saturday}), ());
}
{
OpeningHours oh("Mo-Su 08:00-13:00,14:00-20:00; Sa 10:00-11:00 off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(MakeTimeTableSet(oh, tts), ());
TEST_EQUAL(tts.Size(), 2, ());
auto const tt = tts.Get(1);
TEST_EQUAL(tt.GetOpeningDays(), TOpeningDays({osmoh::Weekday::Saturday}), ());
TEST_EQUAL(tt.GetOpeningTime().GetStart().GetHourMinutes().GetHoursCount(), 8, ());
TEST_EQUAL(tt.GetOpeningTime().GetEnd().GetHourMinutes().GetHoursCount(), 20, ());
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(), 13, ());
TEST_EQUAL(tt.GetExcludeTime()[1].GetEnd().GetHourMinutes().GetHoursCount(), 14, ());
}
{
OpeningHours oh("Mo-Su; Sa 10:00-11:00 off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(MakeTimeTableSet(oh, tts), ());
TEST_EQUAL(tts.Size(), 2, ());
auto const tt = tts.Get(1);
TEST_EQUAL(tt.GetOpeningTime().GetStart().GetHourMinutes().GetHoursCount(), 0, ());
TEST_EQUAL(tt.GetOpeningTime().GetEnd().GetHourMinutes().GetHoursCount(), 24, ());
TEST_EQUAL(tt.GetOpeningDays(), TOpeningDays({osmoh::Weekday::Saturday}), ());
TEST_EQUAL(tt.GetExcludeTime()[0].GetStart().GetHourMinutes().GetHoursCount(), 10, ());
TEST_EQUAL(tt.GetExcludeTime()[0].GetEnd().GetHourMinutes().GetHoursCount(), 11, ());
}
{
OpeningHours oh("Mo-Fr 11:00-17:00; Sa-Su 12:00-16:00; Tu off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(MakeTimeTableSet(oh, tts), ());
TEST_EQUAL(tts.Size(), 2, ());
TEST_EQUAL(tts.GetUnhandledDays(), TOpeningDays({osmoh::Weekday::Tuesday}), ());
}
{
OpeningHours oh("Mo-Fr 11:00-17:00; Sa-Su 12:00-16:00; Mo-Fr off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(MakeTimeTableSet(oh, tts), ());
TEST_EQUAL(tts.Size(), 1, ());
TEST_EQUAL(tts.GetUnhandledDays(),
TOpeningDays({osmoh::Weekday::Monday,
osmoh::Weekday::Tuesday,
osmoh::Weekday::Wednesday,
osmoh::Weekday::Thursday,
osmoh::Weekday::Friday}), ());
}
{
OpeningHours oh("Mo-Fr 11:00-17:00; Sa-Su 12:00-16:00; Mo-Fr 11:00-13:00 off");
TEST(oh.IsValid(), ());
TimeTableSet tts;
TEST(MakeTimeTableSet(oh, tts), ());
TEST_EQUAL(tts.Size(), 2, ());
auto const tt = tts.Get(0);
TEST_EQUAL(tts.GetUnhandledDays(), TOpeningDays(), ());
TEST_EQUAL(tt.GetOpeningTime().GetStart().GetHourMinutes().GetHoursCount(), 11, ());
TEST_EQUAL(tt.GetOpeningTime().GetEnd().GetHourMinutes().GetHoursCount(), 17, ());
TEST_EQUAL(tt.GetExcludeTime()[0].GetStart().GetHourMinutes().GetHoursCount(), 11, ());
TEST_EQUAL(tt.GetExcludeTime()[0].GetEnd().GetHourMinutes().GetHoursCount(), 13, ());
}
}

View file

@ -338,7 +338,7 @@ bool TimeTableSet::Append(TimeTable const & tt)
bool TimeTableSet::Remove(size_t const index)
{
if (index == 0 || index >= Size())
if (Size() == 1 || index >= Size())
return false;
m_table.erase(m_table.begin() + index);

View file

@ -10,7 +10,7 @@
namespace
{
void SetUpWeekdays(osmoh::Weekdays const & wds, editor::ui::TimeTable & tt)
editor::ui::TOpeningDays MakeOpeningDays(osmoh::Weekdays const & wds)
{
set<osmoh::Weekday> openingDays;
for (auto const & wd : wds.GetWeekdayRanges())
@ -30,7 +30,12 @@ void SetUpWeekdays(osmoh::Weekdays const & wds, editor::ui::TimeTable & tt)
if (wd.HasSaturday())
openingDays.insert(osmoh::Weekday::Saturday);
}
tt.SetOpeningDays(openingDays);
return openingDays;
}
void SetUpWeekdays(osmoh::Weekdays const & wds, editor::ui::TimeTable & tt)
{
tt.SetOpeningDays(MakeOpeningDays(wds));
}
void SetUpTimeTable(osmoh::TTimespans spans, editor::ui::TimeTable & tt)
@ -164,6 +169,117 @@ editor::ui::TOpeningDays const kWholeWeek = {
osmoh::Weekday::Saturday,
osmoh::Weekday::Sunday
};
editor::ui::TOpeningDays GetCommonDays(editor::ui::TOpeningDays const & a,
editor::ui::TOpeningDays const & b)
{
editor::ui::TOpeningDays result;
set_intersection(begin(a), end(a), begin(b), end(b), inserter(result, begin(result)));
return result;
}
osmoh::HourMinutes::TMinutes::rep GetDuration(osmoh::Time const & time)
{
return time.GetHourMinutes().GetDurationCount();
}
bool Includes(osmoh::Timespan const & a, osmoh::Timespan const & b)
{
return GetDuration(a.GetStart()) <= GetDuration(b.GetStart()) &&
GetDuration(b.GetEnd()) <= GetDuration(a.GetEnd());
}
bool ExcludeRulePart(osmoh::RuleSequence const & rulePart, editor::ui::TimeTableSet & tts)
{
auto const ttsInitialSize = tts.Size();
for (size_t i = 0; i < ttsInitialSize; ++i)
{
auto tt = tts.Get(i);
auto const ttOpeningDays = tt.GetOpeningDays();
auto const commonDays = GetCommonDays(ttOpeningDays,
MakeOpeningDays(rulePart.GetWeekdays()));
auto const removeCommonDays = [&commonDays](editor::ui::TTimeTableProxy & tt)
{
for (auto const day : commonDays)
VERIFY(tt.RemoveWorkingDay(day), ("Can't remove working day"));
VERIFY(tt.Commit(), ("Can't commit changes"));
};
auto const twentyFourHoursGuard = [](editor::ui::TimeTable & tt)
{
using osmoh::operator ""_h;
if (tt.IsTwentyFourHours())
{
tt.SetTwentyFourHours(false);
// TODO(mgsergio): Consider TimeTable refactoring:
// get rid of separation of TwentyFourHours and OpeningTime.
tt.SetOpeningTime({0_h, 24_h});
}
};
auto const & excludeTime = rulePart.GetTimes();
// The whole rule matches to the tt.
if (commonDays.size() == ttOpeningDays.size())
{
// rulePart applies to commonDays in a whole.
if (excludeTime.empty())
return tts.Remove(i);
twentyFourHoursGuard(tt);
for (auto const & time : excludeTime)
{
// Whatever it is, it's already closed at a time out of opening time.
if (!Includes(tt.GetOpeningTime(), time))
continue;
// The whole opening time interval should be switched off
if (!tt.AddExcludeTime(time))
return tts.Remove(i);
}
VERIFY(tt.Commit(), ("Can't update time table"));
return true;
}
// A rule is applied to a subset of a time table. We should
// subtract common parts from tt and add a new time table if needed.
if (commonDays.size() != 0)
{
// rulePart applies to commonDays in a whole.
if (excludeTime.empty())
{
removeCommonDays(tt);
continue;
}
twentyFourHoursGuard(tt);
editor::ui::TimeTable copy = tt;
VERIFY(copy.SetOpeningDays(commonDays), ("Can't set opening days"));
auto doAppendRest = true;
for (auto const & time : excludeTime)
{
// Whatever it is, it's already closed at a time out of opening time.
if (!Includes(copy.GetOpeningTime(), time))
continue;
// The whole opening time interval should be switched off
if (!copy.AddExcludeTime(time))
{
doAppendRest = false;
break;
}
}
removeCommonDays(tt);
if (doAppendRest)
VERIFY(tts.Append(copy), ("Can't add new time table"));
}
}
return true;
}
} // namespace
namespace editor
@ -209,14 +325,22 @@ bool MakeTimeTableSet(osmoh::OpeningHours const & oh, ui::TimeTableSet & tts)
ui::TimeTable tt = ui::TimeTable::GetUninitializedTimeTable();
tt.SetOpeningTime(tt.GetPredefinedOpeningTime());
// TODO(mgsergio): We don't handle cases with speciffic time off.
// I.e. Mo-Fr 08-20; Fr 18:00-17:00 off.
// Can be implemented later.
if (rulePart.GetModifier() == osmoh::RuleSequence::Modifier::Closed ||
rulePart.GetModifier() == osmoh::RuleSequence::Modifier::Unknown ||
// Comments and unknown rules belong to advanced mode.
if (rulePart.GetModifier() == osmoh::RuleSequence::Modifier::Unknown ||
rulePart.GetModifier() == osmoh::RuleSequence::Modifier::Comment)
return false;
if (rulePart.GetModifier() == osmoh::RuleSequence::Modifier::Closed)
{
// off modifier in the first part in oh is useless.
if (first == true)
return false;
if (!ExcludeRulePart(rulePart, tts))
return false;
continue;
}
if (rulePart.HasWeekdays())
SetUpWeekdays(rulePart.GetWeekdays(), tt);
else
@ -232,7 +356,8 @@ bool MakeTimeTableSet(osmoh::OpeningHours const & oh, ui::TimeTableSet & tts)
tt.SetTwentyFourHours(true);
}
bool const appended = first ? tts.Replace(tt, 0) : tts.Append(tt);
// Check size as well since ExcludeRulePart can add new time tables.
bool const appended = first && tts.Size() == 1 ? tts.Replace(tt, 0) : tts.Append(tt);
first = false;
if (!appended)
return false;