// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "AlarmOperations.hpp" #include #include namespace alarms { AlarmOperations::AlarmOperations(std::unique_ptr &&alarmEventsRepo, GetCurrentTime getCurrentTimeCallback) : alarmEventsRepo{std::move(alarmEventsRepo)}, getCurrentTimeCallback{getCurrentTimeCallback} {}; void AlarmOperations::updateEventsCache(TimePoint now) { OnGetNextSingleProcessed callback = [&](std::vector singleEvents) { nextSingleEvents = std::move(singleEvents); }; getNextSingleEvents(now, callback); } void AlarmOperations::getAlarm(const std::uint32_t alarmId, OnGetAlarmProcessed callback) { OnGetAlarmEventCallback repoCallback = [callback](AlarmEventRecord record) { callback(record); }; alarmEventsRepo->getAlarmEvent(alarmId, repoCallback); } void AlarmOperations::addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback) { OnAddAlarmEventCallback repoCallback = [&, callback, record](bool success) mutable { checkAndUpdateCache(record); callback(success); }; alarmEventsRepo->addAlarmEvent(record, repoCallback); } void AlarmOperations::updateAlarm(AlarmEventRecord record, OnUpdateAlarmProcessed callback) { OnUpdateAlarmEventCallback repoCallback = [&, callback, record](bool success) mutable { auto found = std::find_if(nextSingleEvents.begin(), nextSingleEvents.end(), [recordId = record.ID](const SingleEventRecord &e) { return e.parent->ID == recordId; }); if (found != std::end(nextSingleEvents)) { updateEventsCache(getCurrentTime()); } else { checkAndUpdateCache(record); } callback(success); }; alarmEventsRepo->updateAlarmEvent(record, repoCallback); } void AlarmOperations::removeAlarm(const std::uint32_t alarmId, OnRemoveAlarmProcessed callback) { OnRemoveAlarmEventCallback repoCallback = [&, callback, alarmId](bool success) { auto found = std::find_if(nextSingleEvents.begin(), nextSingleEvents.end(), [alarmId](const SingleEventRecord &e) { return e.parent->ID == alarmId; }); if (found != std::end(nextSingleEvents) && nextSingleEvents.size() == 1) { updateEventsCache(getCurrentTime()); } callback(success); }; alarmEventsRepo->removeAlarmEvent(alarmId, repoCallback); } void AlarmOperations::getAlarmsInRange( TimePoint start, TimePoint end, std::uint32_t offset, std::uint32_t limit, OnGetAlarmsInRangeProcessed callback) { OnGetAlarmEventsInRangeCallback repoCallback = [callback](std::vector records) { callback(records); }; alarmEventsRepo->getAlarmEventsInRange(start, end, offset, limit, repoCallback); } void AlarmOperations::getNextSingleEvents(TimePoint start, OnGetNextSingleProcessed callback) { auto nextEvents = std::make_shared>(); OnGetAlarmEventsRecurringInRange repoGetRecurringCallback = [&, callback, nextEvents, start](std::vector records) { onRepoGetRecurringInRangeResponse(callback, nextEvents, start, records); }; OnGetNextCallback repoGetNextCallback = [&, callback, nextEvents, start, repoGetRecurringCallback](std::vector records) { onRepoGetNextResponse(callback, nextEvents, start, repoGetRecurringCallback, records); }; alarmEventsRepo->getNext(start, getNextSingleEventsOffset, getNextSingleEventsLimit, repoGetNextCallback); } void AlarmOperations::onRepoGetNextResponse(OnGetNextSingleProcessed handledCallback, std::shared_ptr> nextEvents, TimePoint start, OnGetAlarmEventsRecurringInRange recurringCallback, std::vector records) { if (records.empty()) { handledCallback({}); } else { *nextEvents = std::move(records); auto firstEventTimePoint = (*nextEvents)[0].startDate; nextEvents->erase(std::remove_if(nextEvents->begin(), nextEvents->end(), [](AlarmEventRecord rec) { return !rec.rruleText.empty(); }), nextEvents->end()); alarmEventsRepo->getAlarmEventsRecurringInRange( start, firstEventTimePoint, getNextSingleEventsOffset, getNextSingleEventsLimit, recurringCallback); } } void AlarmOperations::onRepoGetRecurringInRangeResponse(OnGetNextSingleProcessed handledCallback, std::shared_ptr> nextEvents, TimePoint start, std::vector records) { std::vector outEvents; if (!records.empty()) { (*nextEvents) .insert(nextEvents->end(), std::make_move_iterator(records.begin()), std::make_move_iterator(records.end())); } TimePoint nearestTimePoint = TIME_POINT_MAX; for (auto &event : (*nextEvents)) { auto newSingle = event.getNextSingleEvent(start); if (newSingle.startDate == nearestTimePoint) { outEvents.push_back(newSingle); } else if (newSingle.startDate < nearestTimePoint) { nearestTimePoint = newSingle.startDate; outEvents.clear(); outEvents.push_back(newSingle); } } handledCallback(outEvents); } void AlarmOperations::checkAndUpdateCache(AlarmEventRecord record) { auto nearestNewSingleEvent = record.getNextSingleEvent(getCurrentTime()); if (nearestNewSingleEvent.EventInfo::isValid() && nearestNewSingleEvent.startDate > getCurrentTime()) { auto alarmEvent = std::dynamic_pointer_cast(nearestNewSingleEvent.parent); if (record.enabled && (nextSingleEvents.empty() || nearestNewSingleEvent.startDate <= nextSingleEvents.front().startDate)) { updateEventsCache(getCurrentTime()); } } } auto AlarmOperations::minuteUpdated(TimePoint now) -> void { if (nextSingleEvents.empty() || nextSingleEvents.front().startDate > now) { return; } executeAlarm(nextSingleEvents.front()); } void AlarmOperations::addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr handler) { alarmHandlerFactory.addHandler(type, handler); } void AlarmOperations::executeAlarm(const SingleEventRecord &singleAlarmEvent) { alarms::AlarmType alarmType = alarms::AlarmType::None; if (typeid(*(singleAlarmEvent.parent)) == typeid(AlarmEventRecord)) { alarmType = alarms::AlarmType::Clock; } auto alarmEventPtr = std::dynamic_pointer_cast(singleAlarmEvent.parent); if (alarmEventPtr) { auto handler = alarmHandlerFactory.getHandler(alarmType); if (handler) { handler->handle(*alarmEventPtr); } } else { LOG_WARN("Parent type is not AlarmEventRecord!"); } } TimePoint AlarmOperations::getCurrentTime() { if (!getCurrentTimeCallback) { return TIME_POINT_INVALID; } return getCurrentTimeCallback(); } } // namespace alarms