---
-- @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 maintenance_passwords_present = false
local driver_logged_in = false
local maintenance_operator_logged_in = false
local usb_update_confirmed = false
local driver_password_present = false
local maintenance_operator_logout_timer = nil
local maintenance_timeout

---
--- @brief  Processes the maintenance passwords available event
--- @param  gre#context mapargs
---
function MaintenanceOperatorLoggedIn()
  return maintenance_operator_logged_in
end

---
--- @brief  Send the maintenance password to the backend for validation. 
--- @param  gre#context mapargs
---
function CBValidateMaintenanceOperatorPassword(mapargs)
  if sbsettings.validate_maintenance_operator_password(mapargs.value) then
    local fn = _G[gre.get_value(mapargs.context_screen..".function_on_valid")]
    if fn then fn(mapargs) end
    ScreenTransition(gre.get_value(mapargs.context_screen..".screen_on_valid"))
  else
    gre.set_value("numeric_entry_layer.text_entry_group.text_entry_info_control.grd_hidden", 0)
    playError()
  end
end

---
--- @brief  Send the USB update password to the backend for validation. 
--- @param  gre#context mapargs
---
function CBValidateUSBUpdatePassword(mapargs)
  if sbsettings.validate_usb_update_password(mapargs.value) then
    local fn = _G[gre.get_value(mapargs.context_screen..".function_on_valid")]
    if fn then fn(mapargs) end
    ScreenTransition(gre.get_value(mapargs.context_screen..".screen_on_valid"))
  else
    gre.set_value("numeric_entry_layer.text_entry_group.text_entry_info_control.grd_hidden", 0)
    playError()
  end
end

---
--- @brief  Send the driver password to the backend for validation. 
--- @param  gre#context mapargs
---
function CBValidateDriverPassword(mapargs)
  if sbsettings.validate_bus_driver_password(mapargs.value) then
    local fn = _G[gre.get_value(mapargs.context_screen..".function_on_valid")]
    if fn then fn(mapargs) end
    ScreenTransition(gre.get_value(mapargs.context_screen..".screen_on_valid"))
  else
    gre.set_value("numeric_entry_layer.text_entry_group.text_entry_info_control.grd_hidden", 0)
    playError()
  end
end

---
--- @brief  Send password to backend for validation against any password
--- @param  gre#context mapargs
---
function CBValidateAnyPassword(mapargs)
  if sbsettings.validate_bus_driver_password(mapargs.value) or
    sbsettings.validate_maintenance_operator_password(mapargs.value) then
    CBDriverPasswordLoginComplete(mapargs)
  else
    gre.set_value("numeric_entry_layer.text_entry_group.text_entry_info_control.grd_hidden", 0)
    playError()
  end
end

---
--- @brief  Send driver ID to backend for validation.
--- @param  gre#context mapargs
---
function CBValidateDriverID(mapargs)
  if sbsettings.validate_driver_id(mapargs.value) then
    StartBusDriverOnlyPasswordLogin("bd_driver_id")
  else
    gre.set_value("numeric_entry_layer.text_entry_group.text_entry_info_control.grd_hidden", 0)
    CBPlayError()
  end
end

---
--- @brief  Send service ID to the backend for validation
--- @param  gre#context mapargs
---
function CBValidateServiceID(mapargs)
  SendText("validate_service_id", mapargs.value)
end

---
--- @brief  Call back to perform no action.
--- @param  gre#context mapargs
---
function CBNoAction(mapargs)
end

---
--- @brief  Determine maintenance entry point depending on the maintenance
---         passwords
--- @param  gre#context mapargs
---
function CBMaintenanceSettingsStart(mapargs)
  if ScrollActive() then return end
  if not maintenance_passwords_present or maintenance_operator_logged_in then
    ScreenTransition(mapargs.screen or mapargs.context_screen)
    local callback = mapargs.function_on_valid
    if type(callback) == "function" then
      callback(mapargs)
    end
    CBMaintenanceOperatorLoggedIn()
  else
    gre.set_data(
      { ["mo_login.back_screen"] = mapargs.context_screen,
        ["mo_login.screen_on_valid"] = mapargs.screen or mapargs.context_screen,
        ["mo_login.function_on_valid"] = mapargs.function_on_valid or "CBNoAction" })
    ScreenTransition("mo_login")
  end
end

---
--- @brief  Stop the maintenance operator logout timer.
---
function CBStopMaintenanceOperatorLogoutTimer()
  if maintenance_operator_logout_timer ~= nil then
    gre.timer_clear_timeout(maintenance_operator_logout_timer)
    maintenance_operator_logout_timer = nil
  end
end

---
--- @brief  Set flags to indicate that the driver, but not the  maintenance 
---
function CBMaintenanceOperatorLogout()
  CBStopMaintenanceOperatorLogoutTimer()
  maintenance_operator_logged_in = false
end

---
--- @brief  Set flags to indicate that the driver and maintenance operator is 
---         not logged in.
--- @param  gre#context mapargs
---
function CBDriverLoggedOut(mapargs)
  if IconMenuOpening() then return end
  driver_logged_in = false
  CBMaintenanceOperatorLogout()
  CBStartDriverLogin()
end


---
--- @brief  Set flags to indicate that the driver, but not the  maintenance 
---         operator is logged in.
--- @param  gre#context mapargs
---
function CBDriverLoggedIn(mapargs)
  driver_logged_in = true
  if maintenance_operator_logged_in and maintenance_operator_logout_timer == nil then
    if maintenance_timeout == 0 then
      CBMaintenanceOperatorLogout()
    else
      maintenance_operator_logout_timer = gre.timer_set_timeout(CBMaintenanceOperatorLogout, maintenance_timeout * 1000)
    end
  end
end

---
--- @brief  Set flags to indicate that the the  maintenance operator is 
---         logged in.
---
function CBMaintenanceOperatorLoggedIn()
  CBStopMaintenanceOperatorLogoutTimer()
  maintenance_operator_logged_in = true
end

---
--- @brief  Indicate to the backend confirmation to proceed with the USB update.
--- @param  gre#context mapargs
---
function CBStartUSBUpdate(mapargs)
  usb_update_confirmed = true
  SendEvent("usb_update_request_confirmed")
  local screen = gre.get_value("bd_login_for_usb_update.back_screen")
  ScreenTransition(screen)
end

---
--- @brief  Indicate to the backend the permission to proceed with the USB update has been rejected.
--- @param  gre#context mapargs
---
function CBRejectUSBUpdate(mapargs)
  -- Don't send the message if previously confirmed
  if not usb_update_confirmed then
    SendEvent("usb_update_request_rejected")
  end
end

---
--- @brief  Check if maintenance password entry is required before proceeding with USB update.
--- @param  gre#context mapargs
---
function CBUSBUpdateConfirmationRequested(mapargs)
  usb_update_confirmed = false
  if sbsettings.get_usb_update_requires_password() == 0 then
    CBStartUSBUpdate(mapargs)
  else
    ScreenTransition("bd_login_for_usb_update")
  end
end

---
--- @brief  Go to the correct screen following exit from USB update password entry.
--- @param  gre#context mapargs
---
function CBSetReturnScreenForUSBUpdateLogin(mapargs)
  if driver_logged_in then
    gre.set_value("bd_login_for_usb_update.back_screen", "bd_home")
  else
    gre.set_value("bd_login_for_usb_update.back_screen", "bd_startup")
  end
end

---
--- @brief  Start the bus driver password login.
--- @param  password_required - true or 1 indicates that password is required.
--- @param  screen_on_valid - which screen to go to when password entered.
--- @param  back_screen - which screen to go to when password entry is cancelled.
---
function StartBusDriverPasswordLogin(password_required, screen_on_valid, back_screen)
  gre.set_value(
    "bd_login.screen_on_valid", screen_on_valid,
    "bd_login.back_screen", back_screen)
  if password_required == true or password_required == 1 then
    if driver_password_present then
      ScreenTransition("bd_login")
      return
    elseif maintenance_passwords_present then
      gre.set_value(
        "mo_login.screen_on_valid", screen_on_valid,
        "mo_login.back_screen", back_screen)
      ScreenTransition("mo_login")
      return
    end
  end
  CBDriverPasswordLoginComplete()
end

---
--- @brief  Start the bus driver password login, only only if driver password is present.
--- @param  back_screen - which screen to go to when password entry is cancelled.
---
function StartBusDriverOnlyPasswordLogin(back_screen)
  StartBusDriverPasswordLogin(driver_password_present and sbsettings.get_driver_passcode_required() == 1, "bd_home", back_screen)
end

---
--- @brief  Handle the password login complete event
---
function CBDriverPasswordLoginComplete()
  ScreenTransition(gre.get_value("bd_login.screen_on_valid"))
end

---
--- @brief Option selected.   
--- @param gre#context mapargs
function CBFactoryDefaultSettingsSelected(mapargs)
  if ScrollActive() then return end
  CBStartFactoryDefaultSettingsNotification(mapargs)
end

---
--- @brief  Send maintenance timeout value to backend
---
function CBUpdateMaintenanceTimeout(mapargs)
  maintenance_timeout = mapargs.value or sbsettings.get_maintenance_timeout()
end

---
--- @brief  Stop the factory default timer
---
local factory_default_timer = nil
function CBStopFactoryDefaultTimer()
  if factory_default_timer == nil then return end
  gre.timer_clear_timeout(factory_default_timer)
  factory_default_timer = nil
end

---
--- @brief  Start the factory default timer and notify the when it expires
---
function CBStartFactoryDefaultTimer(mapargs)
CBStopFactoryDefaultTimer()  
  factory_default_timer = gre.timer_set_timeout(function ()
      if IconMenuOpening() then return end
      CBNotify({ context_event = "confirm_factory_default" })
    end, 10000)
end

---
-- @brief  Starts the settings screen
--
function CBStartSettings()
  if IconMenuOpening() then return end
  CBStopMaintenanceOperatorLogoutTimer()
  ScreenTransition("mo_home")
end

---
-- @brief  Starts the settings screen
--
function CBUpdatePasswordStatus()
  local counts = sbsettings.get_password_counts()
  if counts.driver == 0 then
    driver_password_present  = false
    UpdateDriverPasswordEdit(false)
  else
    driver_password_present = true
    UpdateDriverPasswordEdit(true)
  end

  if counts.maintenance == 0 then
    maintenance_passwords_present = false
    UpdateMaintenancePasswordEdit(0)
  else
    maintenance_passwords_present = true
    UpdateMaintenancePasswordEdit(counts.maintenance or 1)
  end
end

-- EOF --
