---
-- @package   eg4-crank-ui
-- @file      password-validation.lua
-- @brief     Functionality related to password settings, entry and validation
--
-- @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.
--
--


local active = false 

-- Stores the current value type. Either nil (index), string, or number.
local value_type

---
--- @brief  Updates the radio collection display ensuring the only required 
---         item indicates active
--- @param  control - table of radio items
--- @param  index - item to set
---
local function RadioCollectionSetItem(control, index)
  local rows = gre.get_table_attrs(control, "rows").rows
  local data = {}
  data[control .. ".index"] = index
  for row = 1, rows do
    if row == index then
      data[control .. ".radio." .. row .. ".1"] = 255
    else
      data[control .. ".radio." .. row .. ".1"] = 0
    end
  end
  -- Ensure fade cell variables are set
  for row = rows,1,-1 do
    if gre.get_value(control..".fade."..row..".1") then
      break
    end
    data[control..".fade."..row..".1"] = 0
  end
  gre.set_data(data)
end

---
--- @brief  Gets a radio collection value text for a specific index.
--- @param  control - table of radio items
--- @param  index - item to get
--- @return value text
---
function GetRadioCollectionText(control, index)
    return gre.get_value(control..".text."..index..".1")
end

---
--- @brief  Sets a radio collection to a specific index.
--- @param  control - table of radio items
--- @param  index - item to set
---
function SetRadioCollectionByIndex(control, index)
  if index ~= nil then
    RadioCollectionSetItem(control, index)
  else
    RadioCollectionSetItem(control, -1)
  end
end

---
--- @brief  If value mapping present, maps value to context row 
--- @param  control - table of radio items
--- @param  value - value to map.
--  @return mapped value.
---
function MapRadioValue(control, value)
  local i = 0
  
  -- iter to return next value or nil
  local iter = function()
    return function() 
      i = i + 1
      return gre.get_value(control..".value."..i..".1")
    end 
  end

  -- Scan values for a match
  local check = value
  for item in iter() do
    if check == tonumber(item) then
      return i
    end
    -- Clear value as it should be mapped.
    value = nil
  end

  return value and value + 1
end

----
--- @brief  Populate radio item for the current context setting.
--- @param  gre#context mapargs
---
function CBUpdateRadioItem(mapargs)
  local screen = mapargs.context_screen or mapargs.active_context
  local layers = screen and GetChildObjectList(screen)
  if layers == nil then return nil end

  -- find the layer with the radio list item
  for i = #layers,1,-1 do
    local layer = tostring(layers[i])
    layer = layer:split(".")
    layer = layer[#layer]
    local group = layer..".group"
    local control = group..".items"
    if gre.get_value(control..".radio.1.1") ~= nil then
      -- Located radio layer, populate with settings 
      local fn = layer:split(".")
      fn = "get_"..fn[#fn]:sub(1,-7)
      fn =  _G[fn] or sbsettings[fn]
      if fn then
        local port_id = gre.get_value(group..".port_id") or gre.get_value(screen..".port_id")
        local value = fn(port_id)
        value_type = nil
        if type(value) == "string" or gre.get_value(control..".value_as_text") == 1 then
          SetRadioCollectionByValue(control, tostring(value))
          value_type = type(value)
        else
          -- If present, use lookup table to determine value
          SetRadioCollectionByIndex(control, MapRadioValue(control, value))
        end
      end
      return
    end
  end
end

---
--- @brief  Call back to send a radio collected to a specific index.
--- @param  gre#context mapargs
---
function CBSetRadioCollectionByIndex(mapargs)
  RadioCollectionSetItem(mapargs.control, mapargs.value)
end

---
--- @brief  Searches for a value in a list and sets the radio group to the determined index.
--- @param  control - table of radio items
--- @param  list - table of radio items
--- @param  value - value to match against table
---
function UpdateRadioCollectionItemByListValue(control, list, value) 
  if value ~= nil then
    for index = 1, #list do
      if tostring(list[index]) == tostring(value) then
        RadioCollectionSetItem(control, index)
        return
      end
    end
  end
  RadioCollectionSetItem(control, -1)
end

---
--- @brief  Sets a radio collected to a specific value matched to the current list.
--- @param  control - table of radio items
--- @param  value - value to match against table
---
function SetRadioCollectionByValue(control, value)
  if value ~= nil then
    local rows = gre.get_table_attrs(control, "rows")
    local control_text = control .. ".text."
    for row = 1, rows["rows"] do
      local item = control_text .. row .. ".1"
      local data = gre.get_data(item)
      if tostring(data[item]) == tostring(value) then
        RadioCollectionSetItem(control, row)
        return
      end
    end
  end  
  RadioCollectionSetItem(control, -1)
end

---
--- @brief  Callback to set a radio collection item from a touch.
--- @param  gre#context mapargs
---
function CBRadioCollectionSelect(mapargs) 
  if not ScrollActive() then

    -- Call more function if touch is on the right side of the control.
    local fn = _G[mapargs.more or gre.get_value(mapargs.context_control..".more")]
    if fn and mapargs.context_event_data.x > gre.get_value(mapargs.context_control..".grd_width") / 2 then
      fn(mapargs)
    end

    RadioCollectionSetItem(mapargs.context_control, mapargs.context_row)    

    if value_type then
      mapargs.value = gre.get_value(mapargs.context_control..".text."..mapargs.context_row..".1")
      if value_type == "number" then
        mapargs.value = tonumber(mapargs.value)
      end
    else
      -- Load value with mapped value or derived from context row.
      local value = gre.get_value(mapargs.context_control..".value."..mapargs.context_row..".1")
      mapargs.value = tonumber(value) or value or (mapargs.context_row - 1)
    end
    
    -- Get port id from parameter, group, or screen
    mapargs.port_id = mapargs.port_id or gre.get_value(mapargs.context_group..".port_id") or gre.get_value(mapargs.context_screen..".port_id")

    -- Check if a set function exists for this component.
    local fn = "set_"..mapargs.context_layer:sub(1,-7)
    fn = _G[fn] or sbsettings[fn]
    if fn then
      fn(mapargs.value, mapargs.port_id)
    end

    -- If specified, run callback
    local callback = _G[mapargs.callback] or _G[gre.get_value(mapargs.context_control..".callback")]
    if type(callback) == "function" then
      callback(mapargs)
    end

    -- If specified, send event to backend
    local event = mapargs.event or gre.get_value(mapargs.context_control..".event")
    if event then
      SendEvent(event)
    end
  end
end

---
--- @brief  Test function for touch of a radio collection.
--- @param  gre#context mapargs
---
function CBRadioCollectionSelectTest(mapargs) 
  if not ScrollActive() then
    print(mapargs.context_row .. ", " .. mapargs.context_col)
  end
end

-- EOF --
