
--[[
  @package    eg4-crank-ui-2
  @file       sign-update-progress.lua
  @brief      Handles sign update event for the user interface
]]

local info = {}

--- Note: Command test message
--- running_detected_extracting
--- $ ./iogen g4_frontend - sign_update_progress 1s0:text "return { signAddress = 1, finalStatus = 'RUNNING', stage = 'DETECTED', subStage = 'EXTRACTING', percentage = 0 }"
---

---
--- @brief  Update the sign update progress list.
local function update_sign_progress()
  if not info.group then return end

  local control = info.group..".list"

  if info.pb_x == nil then
    info.pb_x = gre.get_value(control..".pb_x")
    info.pb_width = gre.get_value(control..".pb_width")
  end

  local data = {}
  local rows = 0
  for sign_address, status in sorted_pairs(info.data) do
    rows = rows + 1
    data[control..".sign_address."..rows..".1"] = "#"..sign_address

    local state = status.finalStatus:lower()
    local stage = status.stage:lower()
    local sub_stage = status.subStage:lower()
    -- Hierarchy of status text lookup:
    --
    --   state_stage_sub_stage
    --   state_stage
    --   state
    --   stage_sub_stage
    --   stage
    local text = gre.get_value(info.group..".status_"..state.."_"..stage.."_"..sub_stage) or
                 gre.get_value(info.group..".status_"..state.."_"..stage) or
                 gre.get_value(info.group..".status_"..state) or
                 gre.get_value(info.group..".status_"..stage.."_"..sub_stage) or
                 gre.get_value(info.group..".status_"..stage) or
                 state.." "..stage.." "..sub_stage
    local version = (status.installingVersion and status.installingVersion ~= "") and " v"..status.installingVersion or ""
    data[control..".status."..rows..".1"] = text:gsub("\\n", "\n"):format(version)

    local width = status.percentage * info.pb_width / 100
    data[control..".width."..rows..".1"] = width
    data[control..".x."..rows..".1"] = width - info.pb_width + info.pb_x
    data[control..".percentage."..rows..".1"] = status.percentage == 0 and "" or status.percentage.."%"
  end
  gre.set_data(data)

  local height = gre.get_table_cell_attrs(control, 1, 1, "height").height
  gre.set_table_attrs(control, { rows = rows })
end


---
--- @brief  Update the common sign update progress on the status tile.
local function update_common_progress()

  local lowest_percentage = 100
  for sign_address, status in sorted_pairs(info.data) do
    if status.percentage >= 0 and status.percentage < lowest_percentage then
      lowest_percentage = status.percentage
    end
  end

  update_progress_tile("sign_update", "("..lowest_percentage .. "%)")

  local group = get_update_progress_notification_group()
  if group then
    local control = group..".status"
    gre.set_value(control..".heading", gre.get_value(control..".sign_update_in_progress"))
    gre.set_value(control..".text", "")
    stop_indeterminate_progress(group..".progress_bar")
    local width = gre.get_value(group..".progress_bar.grd_width")
    set_update_in_progress_bar(lowest_percentage / 100)
  end
end

---
--- @brief  Process the sign update progress message.
function cb_process_sign_update_progress(mapargs)

  local status = loadstring(mapargs.context_event_data.text)()

  if info.cleanup then info = {} end
  if not info.data then info.data = {} end
  info.data[status.signAddress] = status

  if not info.group then
    info.notification = mapargs.context_event
    info.group = notify(mapargs.context_event)

    -- Setup navigation info
    info.page = 1
    local control = info.group..".list"
    local row_height = gre.get_table_cell_attrs(control, 1, 1, "height").height
    info.height = gre.get_value(control..".grd_height")
    info.rows_per_page = math.floor(info.height / row_height)

    -- Stop the notification to be closed while update is in progress
    gre.set_value(info.group..".hide.grd_hidden", 0)
  end

  info.suppress_sign_update_notification = nil
  if info.show_sign_update_notification then 
    show_notifications(info.notification)
    info.show_sign_update_notification = nil
  end

  update_sign_progress()
  update_common_progress()
  update_in_progress_controls()
end

---
--- @brief  Navigate the sign update list.
--- @param mapargs - gre#context mapargs
function cb_sign_update_list_navigate(mapargs)
  info.page = info.page + mapargs.dir
  if info.page < 1 then info.page = 1 end
    local control = info.group..".list"
  local rows = gre.get_table_attrs(control, "rows" ).rows or 0
  local pages = math.floor((rows - 1) / info.rows_per_page) + 1
  if info.page > pages then info.page = pages end
  animate_scroll(control, -(info.page - 1) * info.height)
end

---
--- @brief  If not suppressed, show the sign update progress notification.
function cb_show_sign_update_progress()
  if info.suppress_sign_update_notification then return end
  show_notifications(info.notification)
end

---
--- @brief  Indicate that cleanup is required next time progress is updated.
function show_sign_update_progress_and_cleanup()
  -- Allow the notification to be closed.
  if info.group == nil then return end
  gre.set_value(info.group..".hide.grd_hidden", 0)
  show_notifications(info.notification)
  info.cleanup = true
end

--- @brief  Suppress showing the sign update progress notification, but indicate that
--          it should be shown when the next update progress message is received.
function suppress_show_sign_update_notification()
  if info.group == nil then return end
  hide_notifications(info.notification)
  info.suppress_sign_update_notification = true
  info.show_sign_update_notification = true
end
