--[[
  @package    eg4-crank-ui-2
  @file       network-settings.lua
  @brief      Handles the network settings screen and functionality
]]

local apply_network_settings

---
--- @brief  Check whether to show the network settings option
local network_options_enabled = true
function show_network_settings()
  return network_options_enabled
end

---
--- @brief  Check whether to show the network interface DHCP lease start option
function show_ethernet_port_dhcp_lease_start()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_mode(port_id) == 3
end

---
--- @brief  Check whether to show the network interface DHCP lease end option
function show_ethernet_port_dhcp_lease_end()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_mode(port_id) == 3
end

---
--- @brief  Check whether to show the network port IP address
function show_ethernet_port_address()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_mode(port_id) ~= 0
end

---
--- @brief  Check whether to show the network port subnet mask
function show_ethernet_port_netmask()
  local port_id = gre.get_value("network_interface_settings.port_id")
  if sbsettings.get_ethernet_port_address(port_id) == "" then return end
  return sbsettings.get_ethernet_port_mode(port_id) ~= 0
end

---
--- @brief  Check whether to show the network port gateway
function show_ethernet_port_gateway()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_mode(port_id) ~= 0
end

---
--- @brief  Check whether to show the WiFi port IP address
function show_wifi_port_address()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_mode(port_id) ~= 0
end

---
--- @brief  Check whether to show the WiFi subnet mask
function show_wifi_port_netmask()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_mode(port_id) ~= 0
end

---
--- @brief  Check whether to show the WiFi gateway
function show_wifi_port_gateway()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_mode(port_id) ~= 0
end

---
--- @brief  Disables network settings if no networking is available
function cb_disable_network_options()
  network_options_enabled = false
end

---
--- @brief  Enables network settings if networking is available
function cb_enable_network_options()
  network_options_enabled = true
end

---
--- @brief  Apply network settings
function cb_apply_network_settings()
  if not apply_network_settings then return end
  apply_network_settings = nil
  send_event("settings_updated")
end

---
--- @brief  Set flag to indicate that network settings have changed
function cb_set_apply_network_settings()
  apply_network_settings = true
end

---
--- @brief  Fetch long description of network interface.
function get_network_item_description(port_id)
  local prefix = port_id:sub(1,2)
  if prefix == "et" or prefix == "en" then
    port_id = gre.get_value("network_interfaces.ethernet_port").." ("..port_id..")"
  elseif prefix == "wl" then
    port_id = gre.get_value("network_interfaces.wifi_port").." ("..port_id..")"
  end
  return port_id
end

---
--- @brief  Initialises the network interfaces list layer.
--- @param  gre#context mapargs
local network_interfaces = { count = 0 }
function cb_init_network_interfaces_list(mapargs)
  local list = loadstring(mapargs.context_event_data.text)()
  local control = get_list_control(mapargs.context_screen)
  local data = {}
  for _,port_id in pairs(list) do
    -- Determine if item is already present.
    if network_interfaces[port_id] == nil then
      network_interfaces.count = network_interfaces.count + 1
      network_interfaces[port_id] = {}

      -- Add the new item to the menu list.
      data[string.format(control..".port_id.%d.1", network_interfaces.count)] = port_id
      data[string.format(control..".text.%d.1", network_interfaces.count)] = get_network_item_description(port_id)
      data[string.format(control..".alpha_pressed.%d.1", network_interfaces.count)] = 0
    end
  end
  gre.set_data(data)
  local height = gre.get_table_cell_attrs(control, 1, 1, "height").height
  gre.set_table_attrs(control, { height = network_interfaces.count * height, rows = network_interfaces.count })
  cb_update_menu(mapargs)
end

---
--- @brief  Initialises the network interface settings layer.
function cb_init_network_interface_settings(mapargs)
  local port_id = gre.get_value("network_interface_settings.port_id")
  local prefix = port_id:sub(1, 2)
  gre.set_layer_attrs_global("ethernet_settings_menu_layer", { hidden = (prefix == "et" or prefix == "en") and 0 or 1 })
  gre.set_layer_attrs_global("wifi_settings_menu_layer", { hidden = (prefix == "wl") and 0 or 1 })
  cb_update_menu(mapargs)
end

---
--- @brief  Get auto up which is combined with enabled
--- @param  gre#context mapargs
function get_ethernet_port_enabled(port_id)
  return (sbsettings.get_ethernet_port_auto_up(port_id) == 0 or
          sbsettings.get_ethernet_port_enabled(port_id) == 0) and 0 or 1
end

---
--- @brief  Set auto up and also enable network.
--- @param  gre#context mapargs
function set_ethernet_port_enabled(value, port_id)
  if value ~= 0 then
    sbsettings.set_ethernet_port_enabled(1, port_id)
  end
  sbsettings.set_ethernet_port_auto_up(value, port_id)
end

---
--- @brief  Get the IP address of the network interface
function get_ethernet_port_address()
  local port_id = gre.get_value("network_interface_settings.port_id")
  return sbsettings.get_ethernet_port_address(port_id)
end


---
--- @brief  set the IP address of the network interface
function cb_set_ethernet_ip_address(value, port_id)
  if value ~= "" and not cb_validate_ip_address_value(value) then return end
  sbsettings.set_ethernet_port_address(value, port_id)
  cb_set_apply_network_settings()
  cb_back_screen()
  return true
end

---
--- @brief  Set the gateway of the network interface
function cb_set_ethernet_gateway(value, port_id)
  if value ~= "" and not cb_validate_ip_address_value(value) then return end
  sbsettings.set_ethernet_port_gateway(value, port_id)
  cb_set_apply_network_settings()
  cb_back_screen()
  return true
end

---
--- @brief  Set the subnet mask of the network interface
function cb_set_ethernet_netmask(value, port_id)
  if value ~= "" and not cb_validate_netmask_value(value) then return end
  sbsettings.set_ethernet_port_netmask(value, port_id)
  cb_set_apply_network_settings()
  cb_back_screen()
  return true
end

---
--- @brief  Set the gateway of the network interface lease start
function cb_set_ethernet_lease_start(value, port_id)
  if value ~= "" and not cb_validate_ip_address_value(value) then return end
  sbsettings.set_ethernet_port_dhcp_lease_start(value, port_id)
  cb_set_apply_network_settings()
  cb_back_screen()
  return true
end

---
--- @brief  Set the gateway of the network interface lease end
function cb_set_ethernet_lease_end(value, port_id)
  if value ~= "" and not cb_validate_ip_address_value(value) then return end
  sbsettings.set_ethernet_port_dhcp_lease_end(value, port_id)
  cb_set_apply_network_settings()
  cb_back_screen()
  return true
end

---
--- @brief  Initialises the network interface DNS servers layer.
--- @param  gre#context mapargs
function cb_init_network_interfaces_dns_servers(mapargs)
  local context_screen = mapargs and mapargs.context_screen or gre.env("active_screen")
  local control = get_list_control(mapargs.context_screen)
  local port_id = gre.get_value(context_screen..".port_id")
  local dns_servers = sbsettings.get_ethernet_port_dns_servers_table(port_id)
  local index = 0
  local data = {}
  for _,dns in ipairs(dns_servers) do
    index = index + 1
    data[string.format(control..".text.%d.1", index)] = dns
    data[string.format(control..".alpha_pressed.%d.1", index)] = 0
  end
  gre.set_data(data)
  local height = gre.get_table_cell_attrs(control, 1, 1, "height").height
  gre.set_table_attrs(control, { height = #dns_servers * height, rows = #dns_servers })
  cb_update_menu(mapargs)
end

---
--- @brief  Add a DNS server to the network interface
--- @param  value  The DNS server to add
--- @param  port_id  The network interface port ID
function cb_add_network_interface_dns_server(value, port_id)
  if not cb_validate_ip_address_value(value) then return end
  sbsettings.add_ethernet_port_dns_server(value, port_id)
  cb_set_apply_network_settings()
  cb_back_screen()
  return true
end

---
--- @brief  Delete a DNS server from the network interface
--- @param  mapargs  The context mapargs
function cb_del_network_interface_dns_server(mapargs)
  local value = gre.get_value(string.format(mapargs.context_control..".text.%d.1", mapargs.context_row))
  local port_id = gre.get_value(mapargs.context_screen..".port_id")
  sbsettings.del_ethernet_port_dns_server(value, port_id)
  cb_set_apply_network_settings()
  cb_init_network_interfaces_dns_servers()
  return true
end

---
--- @brief  Initialises the WiFi access points list layer.
--- @param  gre#context mapargs
function cb_init_wifi_access_points(mapargs)
  local ap_list = sbsettings.read_wifi_access_point_nodes()
  local control = get_list_control(mapargs.context_screen)
  local index = 0
  local data = {}
  for _,ap in pairs(ap_list) do
    index = index + 1
    data[string.format(control..".text.%d.1", index)] = ap
    data[string.format(control..".alpha_pressed.%d.1", index)] = 0
  end
  gre.set_data(data)
  local height = gre.get_table_cell_attrs(control, 1, 1, "height").height
  gre.set_table_attrs(control, { height = index * height, rows = index })
  cb_update_menu(mapargs)
end

---
--- @brief  Start a new WiFi access point entry
--- @param  value  The new access point name
function cb_start_new_wifi_access_point_entry(value)
  if #value < 2 then return end

  -- Make a change to assert that the SSID exists.
  sbsettings.set_wifi_priority(sbsettings.get_wifi_priority(value), value)
  cb_set_apply_network_settings()

  local screen = "wifi_access_point_edit"
  gre.set_value(screen..".heading", value,
                screen..".port_id", value)
  screen_transition(screen)
  return true
end

---
--- @brief  Set the WiFi access point PSK
--- @param  value  The PSK
function cb_set_wifi_psk(value)
  sbsettings.set_wifi_psk(value, gre.get_value(gre.env("active_screen")..".port_id"))
  cb_set_apply_network_settings()
  cb_back_screen()
  return true
end

---
--- @brief  Remove the WiFi access point
--- @param  mapargs  The context mapargs
function cb_wifi_forget_ssid(mapargs)
  local ssid = gre.get_value(mapargs.context_screen..".port_id")
  sbsettings.del_wifi_access_point_node(ssid)
  cb_set_apply_network_settings()
  cb_back_screen()
end
