aboutsummaryrefslogtreecommitdiff
path: root/src/alarm-queue-simple.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/alarm-queue-simple.cpp')
-rw-r--r--src/alarm-queue-simple.cpp215
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();
}
/***