diff options
Diffstat (limited to 'src/alarm-queue-simple.cpp')
-rw-r--r-- | src/alarm-queue-simple.cpp | 215 |
1 files changed, 123 insertions, 92 deletions
diff --git a/src/alarm-queue-simple.cpp b/src/alarm-queue-simple.cpp index f45e61a..921e8d2 100644 --- a/src/alarm-queue-simple.cpp +++ b/src/alarm-queue-simple.cpp @@ -20,134 +20,165 @@ #include <datetime/alarm-queue-simple.h> #include <cmath> +#include <set> namespace unity { namespace indicator { namespace datetime { /*** -**** Public API +**** ***/ -SimpleAlarmQueue::SimpleAlarmQueue(const std::shared_ptr<Clock>& clock, - const std::shared_ptr<Planner>& planner, - const std::shared_ptr<WakeupTimer>& timer): - m_clock(clock), - m_planner(planner), - m_timer(timer), - m_datetime(clock->localtime()) +class SimpleAlarmQueue::Impl { - m_planner->appointments().changed().connect([this](const std::vector<Appointment>&){ - g_debug("AlarmQueue %p calling requeue() due to appointments changed", this); - requeue(); - }); - - m_clock->minute_changed.connect([=]{ - const auto now = m_clock->localtime(); - constexpr auto skew_threshold_usec = int64_t{90} * G_USEC_PER_SEC; - const bool clock_jumped = std::abs(now - m_datetime) > skew_threshold_usec; - m_datetime = now; - if (clock_jumped) { - g_debug("AlarmQueue %p calling requeue() due to clock skew", this); +public: + + Impl(const std::shared_ptr<Clock>& clock, + const std::shared_ptr<Planner>& planner, + const std::shared_ptr<WakeupTimer>& timer): + m_clock{clock}, + m_planner{planner}, + m_timer{timer}, + m_datetime{clock->localtime()} + { + m_planner->appointments().changed().connect([this](const std::vector<Appointment>&){ + g_debug("AlarmQueue %p calling requeue() due to appointments changed", this); requeue(); - } - }); + }); + + m_clock->minute_changed.connect([this]{ + const auto now = m_clock->localtime(); + constexpr auto skew_threshold_usec = int64_t{90} * G_USEC_PER_SEC; + const bool clock_jumped = std::abs(now - m_datetime) > skew_threshold_usec; + m_datetime = now; + if (clock_jumped) { + g_debug("AlarmQueue %p calling requeue() due to clock skew", this); + requeue(); + } + }); + + m_timer->timeout().connect([this](){ + g_debug("AlarmQueue %p calling requeue() due to timeout", this); + requeue(); + }); - m_timer->timeout().connect([this](){ - g_debug("AlarmQueue %p calling requeue() due to timeout", this); requeue(); - }); + } - requeue(); -} + ~Impl() + { + } -SimpleAlarmQueue::~SimpleAlarmQueue() -{ -} + core::Signal<const Appointment&, const Alarm&>& alarm_reached() + { + return m_alarm_reached; + } -core::Signal<const Appointment&>& SimpleAlarmQueue::alarm_reached() -{ - return m_alarm_reached; -} +private: -/*** -**** -***/ + void requeue() + { + const auto appointments = m_planner->appointments().get(); + const Alarm* alarm; + + // kick any current alarms + for (const auto& appointment : appointments) + { + if ((alarm = appointment_get_current_alarm(appointment))) + { + m_triggered.insert(std::make_pair(appointment.uid, alarm->time)); + m_alarm_reached(appointment, *alarm); + } + } -void SimpleAlarmQueue::requeue() -{ - // kick any current alarms - for (auto current : find_current_alarms()) + // idle until the next alarm + if ((alarm = find_next_alarm(appointments))) + { + g_debug ("setting timer to wake up for next appointment '%s' at %s", + alarm->text.c_str(), + alarm->time.format("%F %T").c_str()); + + m_timer->set_wakeup_time(alarm->time); + } + } + + bool already_triggered (const Appointment& appt, const Alarm& alarm) const { - const std::pair<std::string,DateTime> trig {current.uid, current.begin}; - m_triggered.insert(trig); - m_alarm_reached(current); + const std::pair<const std::string&,const DateTime&> key{appt.uid, alarm.time}; + return m_triggered.count(key) != 0; } - // idle until the next alarm - Appointment next; - if (find_next_alarm(next)) + // return the next Alarm (if any) that will kick now or in the future + const Alarm* find_next_alarm(const std::vector<Appointment>& appointments) const { - g_debug ("setting timer to wake up for next appointment '%s' at %s", - next.summary.c_str(), - next.begin.format("%F %T").c_str()); + const Alarm* best {}; + const auto now = m_clock->localtime(); + const auto beginning_of_minute = now.start_of_minute(); - m_timer->set_wakeup_time(next.begin); - } -} + g_debug ("planner has %zu appointments in it", (size_t)appointments.size()); -// find the next alarm that will kick now or in the future -bool SimpleAlarmQueue::find_next_alarm(Appointment& setme) const -{ - bool found = false; - Appointment tmp; - const auto now = m_clock->localtime(); - const auto beginning_of_minute = now.start_of_minute(); + for(const auto& appointment : appointments) + { + for(const auto& alarm : appointment.alarms) + { + if (already_triggered(appointment, alarm)) + continue; - const auto appointments = m_planner->appointments().get(); - g_debug ("planner has %zu appointments in it", (size_t)appointments.size()); + if (alarm.time < beginning_of_minute) // has this one already passed? + continue; - for(const auto& walk : appointments) - { - const std::pair<std::string,DateTime> trig {walk.uid, walk.begin}; - if (m_triggered.count(trig)) - continue; + if (best && (best->time < alarm.time)) // do we already have a better match? + continue; - if (walk.begin < beginning_of_minute) // has this one already passed? - continue; + best = &alarm; + } + } - if (found && (tmp.begin < walk.begin)) // do we already have a better match? - continue; + return best; + } + + // return the Appointment's current Alarm (if any) + const Alarm* appointment_get_current_alarm(const Appointment& appointment) const + { + const auto now = m_clock->localtime(); - tmp = walk; - found = true; + for (const auto& alarm : appointment.alarms) + if (!already_triggered(appointment, alarm) && DateTime::is_same_minute(now, alarm.time)) + return &alarm; + + return nullptr; } - if (found) - setme = tmp; - return found; -} + std::set<std::pair<std::string,DateTime>> m_triggered; + const std::shared_ptr<Clock> m_clock; + const std::shared_ptr<Planner> m_planner; + const std::shared_ptr<WakeupTimer> m_timer; + core::Signal<const Appointment&, const Alarm&> m_alarm_reached; + DateTime m_datetime; +}; -// find the alarm(s) that should kick right now -std::vector<Appointment> SimpleAlarmQueue::find_current_alarms() const -{ - std::vector<Appointment> appointments; +/*** +**** Public API +***/ - const auto now = m_clock->localtime(); - for(const auto& walk : m_planner->appointments().get()) - { - const std::pair<std::string,DateTime> trig {walk.uid, walk.begin}; - if (m_triggered.count(trig)) // did we already use this one? - continue; - if (!DateTime::is_same_minute(now, walk.begin)) - continue; +SimpleAlarmQueue::SimpleAlarmQueue(const std::shared_ptr<Clock>& clock, + const std::shared_ptr<Planner>& planner, + const std::shared_ptr<WakeupTimer>& timer): + impl{new Impl{clock, planner, timer}} +{ +} - appointments.push_back(walk); - } +SimpleAlarmQueue::~SimpleAlarmQueue() +{ +} - return appointments; +core::Signal<const Appointment&, const Alarm&>& +SimpleAlarmQueue::alarm_reached() +{ + return impl->alarm_reached(); } /*** |