---
-- @package   eg4-crank-ui
-- @file      menu-update.lua
-- @brief     Functionality related to menus
--
-- @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.                                              
--
--

---
--- @brief  Find an object in one of the layers of a specific screen.
--- @param  screen - Where to search for object.
--- @param  label - object to find. A match is found if the object name starts with label.
--- @param  control - optionally check if the object has a specific child control
--  @return nil if not found or object name.
---
function findObject(screen, label, control)
  local layers = GetChildObjectList(screen)
  if layers == nil then return nil end
  for i = #layers,1,-1 do
    local layer = tostring(layers[i])
    if gre.get_value(layer..".grd_hidden") == 0 then
      local objs = GetChildObjectList(tostring(layer))
      for j = #objs,1,-1 do
        local obj = tostring(objs[j])
        if obj:sub(-#label) == label then
          if control then
            if gre.get_value(obj.."."..control..".grd_hidden") then
              return obj
            end
          else
            return obj
          end
        end
      end
    end
  end
  return nil
end

---
--- @brief  Repositions the groups/controls children of object depending on visibility and count the number of visible items..
--- @param  layer - layer to scan
--- @return count of visible groups.
---
local function findMenuItems(screen)
  return findObject(screen, ".menu_items")
end

----
--- @brief  Get text value for setting which may be radio, checkbox, formatted or unformatted number
--- @param  control - Control this is hosting the text value.
--- @param  setting - source of data.
--- @param  port_id - optional port id for setting
--- @return text value
---
function GetControlValueText(control, setting, port_id)
  local fn = _G["get_"..setting] or sbsettings["get_"..setting]
  if not fn then return end

  local items = setting.."_layer.group.items"
  local text = ""
  if gre.get_value(items..".checked.1.1") ~= nil then
    -- Populate text with checkbox list
    local value = fn(port_id)
    if type(value) == "table" then
      text = GetCheckboxTextValue(items, value) or ""
    else
      text = tostring(value)
    end
  elseif gre.get_value(items..".radio.1.1") then
    -- Populate text with radio item
    local value = fn(port_id)
    if type(value) == "string" or gre.get_value(items..".value_as_text") == 1 then
      text = tostring(value)
    else
      text = GetRadioCollectionText(items, MapRadioValue(items, value))
    end
  else
    -- set text to a value item
    local format = gre.get_value(control..".format")
    if format then
      text = string.format(format, fn(port_id))
    else
      local value = fn(port_id)
      if tonumber(value) and gre.get_value(control..".enum."..(tonumber(value) + 1)..".1") then
        text = tostring(gre.get_value(control..".enum."..(tonumber(value) + 1)..".1"))
      else
        text = value
      end
    end
  end
  return text
end

----
--- @brief  Populate menu items with setting values
--- @param  screen - current screen
--- @param  group - group to scan and populate
---
local function PopulateControlSettingValues(screen, group)
  local suppress = gre.get_value(screen..".suppress_update")
  if not suppress or suppress == 0 then
    -- scan objects for items that have get functions
    local list = GetChildObjectList(group)
    
    -- Get port id from group or screen
    local port_id = gre.get_value(group..".port_id") or gre.get_value(screen..".port_id")
    local last = ""
    for i = #list,1,-1 do
      local control = tostring(list[i])
      if gre.get_value(control..".grd_hidden") == 0 then
        if last:sub(1, #control) ~= control then
          local fn = control:split(".")
          fn = fn[#fn]
          if string.sub(control, -7) == "_toggle" then
            local fn = "get_"..fn:sub(1,-8)
            fn = _G[fn] or sbsettings[fn]
            if fn then
              SetToggleControlValue(control, fn(port_id))
            end
          elseif string.sub(control, -5) == "_spin" then
            local fn = "get_"..fn:sub(1,-6)
            fn = _G[fn] or sbsettings[fn]
            if fn then
              SetSpinControlValue(control, fn(port_id))
            end
          else
            local text = GetControlValueText(control, fn, port_id)
            gre.set_value(control..".value", text)
          end
        end
      end  
      last = control
    end
  end
end

----
--- @brief  Repositions all the menu items vertically taking into account 
---         hidden attribute.    
--- @param  gre#context mapargs
---
function CBMenuUpdate(mapargs)
  if not mapargs then mapargs = {} end
  local screen = mapargs.context_screen or mapargs.active_context or gre.env("active_screen")
  local group = screen and findMenuItems(screen)
  if not group then return end
  if not gre.get_value(group..".fixed_position") then
    RepositionObjectChildren(group)
  end
  PopulateControlSettingValues(screen, group)
end

----
--- @brief  Update the settings menu 
--- @param  gre#context mapargs
---
function CBSettingsMenuUpdate(mapargs)
  local value = sbsettings.get_sign_test_maintenance_lock()
  gre.set_value("settings_layer.menu_items.sign_self_test_button.grd_hidden", 1 - value,
                "settings_layer.menu_items.sign_self_test.grd_hidden", 1 - value)

  local htc_terminal_enabled = false
  local control_id = CBFetchFirstOBCControlID()
  if control_id then
    if not CheckVirtualOBC(control_id) or sbsettings.get_enable_virtual_htc_terminal() == 1 then
      htc_terminal_enabled = true
    end
  end

  gre.set_value("mo_settings.htc_terminal_control_id", control_id,
                "settings_layer.menu_items.htc_terminal.grd_hidden", htc_terminal_enabled and 0 or 1)

  local enabled = sbsettings.get_usb_power_state()
  gre.set_value("settings_layer.menu_items.usb_power.grd_hidden", enabled,
                "settings_layer.menu_items.usb_power_button.grd_hidden", enabled)

  CBMenuUpdate(mapargs)
end

----
--- @brief  Update the maintenance home menu 
--- @param  gre#context mapargs
---
function CBHomeMenuUpdate(mapargs)
  local value = sbsettings.get_sign_test_maintenance_lock()
  gre.set_value("home_layer.menu_items.sign_self_test_button.grd_hidden", value,
                "home_layer.menu_items.sign_self_test.grd_hidden", value)

  local htc_terminal_enabled = false
  local driver_enabled = sbsettings.get_driver_htc_terminal_permission() ~= 0
  local control_id = CBFetchFirstOBCControlID()
  if driver_enabled and control_id then
    if not CheckVirtualOBC(control_id) or sbsettings.get_enable_virtual_htc_terminal() == 1 then
      htc_terminal_enabled = true
    end
  end

  gre.set_value("home_layer.menu_items.htc_terminal.grd_hidden", htc_terminal_enabled and 0 or 1,
                "mo_home.htc_terminal_control_id", control_id)

  local value = sbsettings.get_allow_driver_reboot()
  gre.set_value("status_and_information_layer.menu_items.reboot_device.grd_hidden", 1 - value)

  CBMenuUpdate(mapargs)
end

-- EOF --
