---
--- @package   eg4-crank-ui
--- @file      notifications.lua
--- @brief     Functionality for handling system notifications.
---
--- @copyright Copyright 2019 Hanover Displays Limited.
--- @license   This program is the confidential and proprietary product of
---            Hanover Displays Limited. Any unauthorised use, reproduction or
---            transfer of this program is strictly prohibited. (Subject to
---            limited distribution and restricted disclosure only.) All
---            rights reserved.
---
---


--- This ensures that each new event is uniquely named.
local unique_id = 1
local rebooting

---
--- @brief  Returns the current rebooting state
--- @return true or nil
function SystemRebooting()
  return rebooting
end 

---
--- @brief  Add the notifications layer to all screens
---
function CBAddNotificationsLayer()
  gre.screen_attach_layer("notification_layer")
  gre.screen_attach_layer("screen_shot_layer")
  gre.screen_attach_layer("display_off_touch_filter_layer")
  gre.set_layer_attrs_global("screen_shot_layer", { hidden = 1 })
end

---
--- @brief  Removes duplicate notifications from the screen
--- @oaram  notification - item(s) to remove
---
local function RemoveDuplicateNotifications(notification)
  local matched = false
  local list = GetChildObjectList("notification_layer")
  for i = 1,#list do
    local object = tostring(list[i])
    -- Split the control name
    local x = string.split(object, ".")
    -- Get the notification name
    local x = string.split(x[#x], "_", 1)
    if #x == 2 then
      if x[#x] == notification then
        gre.delete_object(object)
        matched = true
      end
    end
  end
  return matched
end

---
--- @brief  Callback to close notifications marked as close on USB removal
---
function CBCloseNotificationsOnUSBRemoval()
  local list = GetChildObjectList("notification_layer")
  for i = 1,#list do
    local object = tostring(list[i])
    if gre.get_value(object .. ".close_on_usb_removal") == 1 then
      CBCloseNotification({context_group = object, context_layer = "notification_layer"})
    end
  end
  playStop()
end

---
--- @brief  Callback to create a new notification on the user interface
--- @note   The event name is used to identify the notification group to clone
--- @param  gre#context mapargs
---
function CBNotify(mapargs)

  -- Do not accept any more notifications if the system is rebooting.
  if not mapargs.rebooting and rebooting then return end
  rebooting = mapargs.rebooting

  local matched = false
  if mapargs.allow_duplicates == nil then
    matched = RemoveDuplicateNotifications(mapargs.context_event)
  end

  local group = tostring(unique_id) .. "_" .. mapargs.context_event
  unique_id = unique_id + 1

  mapargs.context_layer = "notification_layer"
  mapargs.context_group = "notification_layer." .. group
  mapargs.context_control = nil

  if not gre.get_value("notification_template_layer."..mapargs.context_event..".grd_hidden") then
    return
  end
  gre.set_value(mapargs.context_layer .. ".background_group.grd_hidden", 0,
                mapargs.context_layer .. ".background_group.background.grd_hidden", 0)

  gre.clone_object("notification_template_layer."..mapargs.context_event, group, mapargs.context_layer, { hidden = 0 })

  -- Check to see if this is an additional handler for the event. This can be used to populate the control with extra information.
  local callback = _G[mapargs.callback]
  if type(callback) == "function" then
    callback(mapargs)
  end

  -- Do not play tone if dialog is a duplicate and was already present.
  if not matched then
    local play_tone = _G[gre.get_value(mapargs.context_group .. ".play_tone")]
    if type(play_tone) == "function" then
      play_tone(mapargs)
    end
  end

  local activate_display = gre.get_value(mapargs.context_group .. ".activate_display")
  if activate_display == 1 then 
    CBRestartNoActivityTimer()
  end
end

---
--- @brief  Callback to close the currently viewed notification and redraw the screem
--- @param  gre#context mapargs
---
function CBCloseNotification(mapargs)
  gre.delete_object(mapargs.context_group)
  gre.redraw()
  if #GetChildObjectList(mapargs.context_layer) == 1 then
    gre.set_group_attrs(mapargs.context_layer .. ".background_group", { hidden = 1 })
  end
end

-- Parameters required for the hold to start action functionality
local hold_timer_id = nil
local hold_control = nil
local hold_max = nil
local hold_count = nil
local HOLD_DURATION = 3   -- Seconds
local HOLD_TPS= 20        -- Ticks per second
local HOLD_PROGRESS_COLOUR = 0x334BE4
local HOLD_COMPLETE_COLOUR = 0xC81914

---
--- @brief Callback to progress the hold timer action.
---
local function updateHoldTimer()
  hold_count = hold_count + 1
  if hold_count == HOLD_DURATION * HOLD_TPS then
    gre.timer_clear_interval(hold_timer_id)
    hold_timer_id = nil
    gre.set_value(hold_control .. ".color", HOLD_COMPLETE_COLOUR)
    CBClickOnScreenPress()
  end
  local width = math.floor((hold_count * hold_max) / (HOLD_DURATION * HOLD_TPS) + 0.5)
  gre.set_value(hold_control .. ".delayed_width", width)
end

---
--- @brief Callback to start the hold timer action.
--- @param gre#context mapargs
function CBStartHoldToConfirmAction(mapargs)
  hold_control = mapargs.context_control
  hold_count = 0
  hold_max = gre.get_value(hold_control..".grd_width")
  hold_timer_id = gre.timer_set_interval(updateHoldTimer, 1000 / HOLD_TPS)
end

---
--- @brief Callback to stop the hold timer action.
--- @param gre#context mapargs
function CBStopHoldToConfirmAction(mapargs)
  if hold_timer_id ~= nil then
    gre.timer_clear_interval(hold_timer_id)
    hold_timer_id = nil
  end
  gre.set_value(hold_control .. ".delayed_width", 0)
  gre.set_value(hold_control .. ".color", HOLD_PROGRESS_COLOUR)
end

---
--- @brief Callback to the release of the control for the hold timer action.
--- @param gre#context mapargs
function CBReleaseHoldToConfirmAction(mapargs)
  if hold_timer_id == nil then
    local action = _G[mapargs.action]
    if type(action) == "function" then
      action(mapargs)
    end
    gre.set_value(hold_control .. ".delayed_width", 0)
    gre.set_value(hold_control .. ".color", HOLD_PROGRESS_COLOUR)
  else
    CBStopHoldToConfirmAction(mapargs)
  end
end

-- EOF --
