--[[
  @package eg4-crank-ui-2
  @file    can-ports.lua
  @brief   Handles the can port settings.
]]


local EDIT_SCREEN = "can_port_edit"

local can_protocols
local port_list_map = { count = 0 }
local cached_data = {}

---
--- @brief  Processes the currently avaialble can protocol list; populating the linked protocol screen.
--- @param  gre#context mapargs
---
function cb_update_available_can_protocols()
  can_protocols = sbsettings.read_available_can_protocols()
end

---
--- @brief  Get the protocols value from the settings as a string
--- @param  port_id - protocols list
--- @return string containing value.
---
function get_can_linked_protocol(port_id)
  local value = sbsettings.get_can_linked_protocol(port_id)
  return (value ~= "") and value or gre.get_value("can_port_edit_layer.menu.can_linked_protocol.none")
end

---
--- @brief  Initialise the can port list screen using the data received from the backend.
--- @param  gre#context mapargs
function cb_init_can_port_setting_list_item(mapargs)
  local settings = loadstring(mapargs.context_event_data.text)()
  cached_data[settings.port_id] = settings

  local control = get_list_control(mapargs.context_screen)

  -- Determine if item is already present.
  local item = port_list_map[settings.port_id]

  if not item then
    -- Add the new item to the menu list.
    port_list_map.count = port_list_map.count + 1
    item = string.format(control..".%%s.%d.1", port_list_map.count)
    port_list_map[settings.port_id] = item

    local format = gre.get_value(control..".format")
    gre.set_value(string.format(item, "text"), string.format(format, settings.port_id))
    gre.set_value(string.format(item, "port_id"), settings.port_id)
    gre.set_value(string.format(item, "alpha_pressed"), 0)

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

    cb_update_menu(mapargs)
  end

  gre.set_value(string.format(item, "value"), get_can_linked_protocol(settings.port_id))
end

---
--- @brief  Initialise, and transition to, the can port edit screen
--- @param  gre#context mapargs
function cb_can_port_selected(mapargs)
  local item = string.format(mapargs.context_control..".%%s.%d.1", mapargs.context_row)
  gre.set_value(EDIT_SCREEN..".heading", gre.get_value(string.format(item, "text")))
  gre.set_value(EDIT_SCREEN..".port_id", gre.get_value(string.format(item, "port_id")))
  screen_transition(EDIT_SCREEN)
end

---
--- @brief  Set the can port linked protocol
--- @param  state - 1 if checked
--- @param  item - item to set
--- @param  port_id - port to set
function set_can_linked_protocol(state, item, port_id)
  sbsettings.set_can_port_protocol(state, item, port_id)
end

---
--- @brief  Start the linked protocols selection screen
--- @param  gre#context mapargs
function cb_start_can_linked_protocol_selection(mapargs)
  -- Collate linked protocols as keys for quick reference
  local keys = { }
  local linked = get_can_linked_protocol(mapargs.port_id):split(",")
  for _,item in ipairs(linked) do
    keys[item] = true
  end

  -- Add text and checked status to list
  mapargs.list = { }
  for _,item in ipairs(can_protocols) do
    table.insert(mapargs.list, {
      text = item,
      checked = keys[item] and 1 or 0
    })
  end

  mapargs.parameter = mapargs.context_control:object_name()
  start_checkbox_list(mapargs)
end


---
--- @brief  Data source updates for can status
--- @param  group The group name
--- @return updated item data
local can_status = {}
function ds_can_status(group)
  local device_name = gre.get_value(group..".device_name")
  if device_name == nil then return {} end
  local path = "/sys/class/net/"..device_name
  local file = io.open(path.."/statistics/rx_bytes", "r")
  local rx_bytes = file and file:read("*n") or 0
  if file then file:close() end

  local file = io.open(path.."/statistics/tx_bytes", "r")
  local tx_bytes = file and file:read("*n") or 0
  if file then file:close() end

  local status = can_status[device_name]
  if status == nil then
    status = {
      rx_bytes = 0,
      tx_bytes = 0,
      active_count = 0,
    }
  end

  if rx_bytes == 0 then
    status.active_count = 0
  elseif rx_bytes == status.rx_bytes then
    if status.active_count > 0 then
      status.active_count = status.active_count - 1
    end
  else
    status.active_count = 5
  end

  local data = {
    ["value.text"] = status.active_count == 0 and gre.get_value(group..".disconnected") or gre.get_value(group..".connected"),
    ["traffic.tx_alpha"] = tx_bytes == status.tx_bytes and 64 or 255,
    ["traffic.rx_alpha"] = rx_bytes == status.rx_bytes and 64 or 255,
    ["extra.text"] = "",
  }

  status.tx_bytes = tx_bytes
  status.rx_bytes = rx_bytes

  can_status[device_name] = status

  return data
end


---
--- @brief  Initialise the can port status tiles
--- @param  gre#context mapargs
function cb_init_can_port_status_tiles(mapargs)
  local layer = "system_information_layer"
  local list = layer:get_children()
  for _,item in ipairs(list) do
    item = tostring(item)
    if item:object_name():starts_with("can_info_") then
      gre.set_value(item..".grd_hidden", 1)
    end
  end
  send_event("read_can_port_settings", "")
end

---
--- @brief  Initialise the can port status tile, processing the data received from the backend.
--- @param  gre#context mapargs
function cb_init_can_port_status_tile(mapargs)
  local info = loadstring(mapargs.context_event_data.text)()
  local group = mapargs.context_layer..".can_info_"..info.port_id
  local data = {
    [group..".grd_hidden"] = 0,
    [group..".heading.text"] = string.format(gre.get_value("can_ports_list_layer.menu.list.format"), info.port_id),
    [group..".port_id"] = info.port_id,
    [group..".device_name"] = info.device_name,
  }
  gre.set_data(data)
end
