--[[
  @package    eg4-crank-ui-2
  @file       passcode-validation.lua
  @brief      Handles driver and maintenance passcode settings and functionality
]]


local info = { }

---
--- @brief  Set flags to indicate that the driver, but not the  maintenance
---
local function maintenance_operator_logout()
  CBStopMaintenanceOperatorLogoutTimer()
  info.maintenance_operator_logged_in = false
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.
---
function start_driver_login(password_required, screen_on_valid)
  info.screen_on_valid = screen_on_valid
  if password_required == true or password_required == 1 then
    local counts = sbsettings.get_password_counts()
    if counts.driver > 0 then
      screen_transition("driver_login")
      return
    elseif counts.maintenance > 0 then
      screen_transition("maintenance_login")
      return
    end
  end
  cb_driver_login_complete()
end

---
--- @brief  Bus driver login at startup
---
local function start_up_driver_login()
  start_driver_login(sbsettings.get_driver_passcode_required() == 1 and sbsettings.get_password_counts().driver > 0, "home")
end

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

---
--- @brief  Set flags to indicate that the maintenance operator has logged out
---
function maintenance_operator_logout()
  stop_maintenance_operator_logout_timer()
  info.maintenance_operator_logged_in = false
end

---
--- @brief  Set flags to indicate that the driver, but not the  maintenance
---         operator is logged in.
--- @param  gre#context mapargs
---
function cb_driver_logged_in(mapargs)
  info.driver_logged_in = true
  if not info.maintenance_operator_logged_in then return end
  if info.maintenance_operator_logout_timer ~= nil then return end
  local maintenance_timeout = sbsettings.get_maintenance_timeout()
  if maintenance_timeout == 0 then
    maintenance_operator_logout()
  else
    info.maintenance_operator_logout_timer = gre.timer_set_timeout(maintenance_operator_logout, maintenance_timeout * 1000)
  end
end

---
--- @brief  Handle the password login complete event
---
function cb_driver_login_complete()
  screen_transition(info.screen_on_valid)
end

---
--- @brief  Set flags to indicate that the driver and maintenance operator is
---         not logged in.
---
function cb_driver_logged_out()
  clear_last_screen()
  info.driver_logged_in = false
  maintenance_operator_logout()
  cb_start_driver_login()
end

---
--- @brief  Handles starting the driver login
---
function cb_start_driver_login()
  if sbsettings.get_driver_id_entry() == 1 then
    set_idle_screen("driver_id_entry")
    screen_transition("driver_id_entry")
  else
    set_idle_screen("driver_login")
    start_up_driver_login()
  end
end

---
--- @brief  Validate password for driver login
--- @param  gre#context mapargs
---
local function validate_any_password(value)
  return sbsettings.validate_bus_driver_password(value) or
         sbsettings.validate_maintenance_operator_password(value)
end

---
--- @brief  Call back to validate the driver passcode and complete the login.
--- @param  gre#context mapargs
---
function cb_submit_driver_passcode(value)
  if not validate_any_password(value) then return false end
  cb_driver_login_complete()
  return true
end

---
--- @brief  Send driver ID to backend for validation.
--- @param  gre#context mapargs
---
function cb_submit_driver_id(value)
  if not sbsettings.validate_driver_id(value) then return false end
  start_up_driver_login()
  return true
end


---
--- @brief  Determines if the logout icon is shown
--- @return true if the logout control should be shown
function show_logout()
  if sbsettings.get_driver_id_entry() == 1 then return true end
  return sbsettings.get_driver_passcode_required() == 1 and sbsettings.get_password_counts().driver > 0
end

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

---
--- @brief  Set flags to indicate that the the  maintenance operator is
---         logged in.
---
function cb_maintenance_operator_logged_in()
  cb_set_mode_maintenance()
  stop_maintenance_operator_logout_timer()
  info.maintenance_operator_logged_in = true
end

---
--- @brief  Transition to the required screen and execute the required function on maintenance login.
local function do_maintenance_login()
  cb_maintenance_operator_logged_in()
  if info.screen_on_valid and info.screen_on_valid ~= "" then
    screen_transition(info.screen_on_valid)
  end
  local fn = info.function_on_valid
  if type(fn) == "string" then fn = _G[fn] end
  if type(fn) == "function" then fn() end
end

---
--- @brief  Determine maintenance entry point depending on the maintenance
---         passwords
--- @param  gre#context mapargs
function cb_maintenance_settings_start(mapargs)
  info.screen_on_valid = mapargs.screen or mapargs.context_control:object_name()
  info.function_on_valid = mapargs.function_on_valid
  if sbsettings.get_password_counts().maintenance == 0 or info.maintenance_operator_logged_in then
    do_maintenance_login()
  else
    screen_transition("maintenance_login")
  end
end

---
--- @brief  Check the maintenance password and login if correct.
--- @param  value - passcode to check
--- @return true if the passcode is correct
function cb_submit_maintenance_passcode(value)
  if not sbsettings.validate_maintenance_operator_password(value) then return end
  do_maintenance_login()
  return true
end

---
--- @brief  Check if passcode entry is required before proceeding with USB update.
function cb_usb_update_confirmation_requested()
  if sbsettings.get_usb_update_requires_password() == 0 then
    send_event("usb_update_request_confirmed")
    return
  end
  info.usb_updated_passcode_validated = nil
  screen_transition("usb_update_login")
end

---
--- @brief  Check the passcode for USB update and send confirmation to backend.
--- @param  value - passcode to check
function cb_submit_usb_update_passcode(value)
  if not sbsettings.validate_usb_update_password(value) then return end
  info.usb_updated_passcode_validated = true
  screen_transition_idle()
  send_event("usb_update_request_confirmed")
  return true
end

---
--- @brief  If not confirmed on screen exit, the send the reject event
function cb_usb_update_confirmation_rejected()
  if not info.usb_updated_passcode_validated then return end
  send_event("usb_update_request_rejected")
end

---
--- @brief  Indicate whether to show the service run number entry icon.
--- @return true to show
function show_service_run_number_entry()
  return get_service_id_required() == 1
end

---
--- @brief  Submit the servive number number to the backend for validation.
--- @param  value - service number to check
function cb_service_run_number_submit(value)
  send_event("validate_service_id", value)
  return true
end
