--
-- (C) 2013-24 - ntop.org
--

local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path

require "lua_utils"

local template = require "template_utils"
local json = require "dkjson"
local page_utils = require("page_utils")

local is_nedge = ntop.isnEdge()
local is_appliance = ntop.isAppliance()
local is_iot_bridge = ntop.isIoTBridge()

if not (is_nedge or is_appliance) then
   return
end

local subpages = {
   { name = "mode",               nedge = true,  appliance = true,                       url = "mode.lua",           label = i18n("nedge.setup_mode")                  },
   { name = "wifi",               nedge = false, appliance = true,                       url = "wifi.lua",           label = i18n("prefs.wifi")                        },
   { name = "network_interfaces", nedge = true,  appliance = true,                       url = "interfaces.lua",     label = i18n("prefs.network_interfaces")          },
   { name = "vlan",               nedge = true,  appliance = false,                       url = "vlan.lua",           label = i18n("nedge.vlan_configuration")          },
   { name = "network_setup",      nedge = true,  appliance = true,                       url = "network.lua",        label = i18n("nedge.interfaces_configuration")    },
   { name = "dhcp",               nedge = true,  appliance = false, routing_only = true, url = "dhcp.lua",           label = i18n("nedge.dhcp_server")                 },
   { name = "dns",                nedge = true,  appliance = false, vlan_trunk = false,  url = "dns.lua",            label = i18n("nedge.dns_configuration")           },
   { name = "captive_portal",     nedge = true,  appliance = false, vlan_trunk = false,  url = "captive_portal.lua", label = i18n("prefs.toggle_captive_portal_title") },
   { name = "shapers",            nedge = true,  appliance = false,                      url = "shapers.lua",        label = i18n("nedge.shapers")                     },
   { name = "gateways",           nedge = true,  appliance = false, routing_only = true, url = "gateways.lua",       label = i18n("nedge.gateways")                    },
   { name = "static_routes",      nedge = true,  appliance = false, routing_only = true, url = "static_routes.lua",  label = i18n("nedge.static_routes")               },
   { name = "routing",            nedge = true,  appliance = false, routing_only = true, url = "routing.lua",        label = i18n("nedge.routing_policies")            },
   { name = "date_time",          nedge = true,  appliance = true,                       url = "date_time.lua",      label = i18n("nedge.date_time")                   },
   { name = "security",           nedge = true,  appliance = false, vlan_trunk = false,  url = "security.lua",       label = i18n("nedge.security")                    },
   { name = "misc",               nedge = true,  appliance = true,                       url = "misc.lua",           label = i18n("prefs.misc")                        },
}

local system_setup_ui_utils = {}

function system_setup_ui_utils.process_apply_discard_config(sys_config)
   if table.len(_POST) > 0 and sys_config then
      if _POST["nedge_config_action"] == "discard" then
         sys_config:discard()
      elseif _POST["nedge_config_action"] == "make_permanent" then
         sys_config:applyChanges()
      end
   end
end

function system_setup_ui_utils.print_page_before()
   sendHTTPContentTypeHeader('text/html')

   if not isAdministratorOrPrintErr() then
      return false
   end

   page_utils.print_header_and_set_active_menu_entry(page_utils.menu_entries.system_setup)
   active_page = "admin"
   dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua")
   page_utils.print_page_title(i18n("nedge.system_setup"))
   return true
end

function system_setup_ui_utils.print_setup_page(print_page_body_callback, sys_config, warnings)
   warnings = warnings or {}

   if not system_setup_ui_utils.print_page_before() then
     return false
   end

   system_setup_ui_utils.print_page_after(print_page_body_callback, sys_config, warnings)
   return true
end

function system_setup_ui_utils.print_page_after(print_page_body_callback, sys_config, warnings)
   system_setup_ui_utils.printConfigChange(sys_config, warnings)
   system_setup_ui_utils.printPageBody(sys_config, print_page_body_callback)
end

function system_setup_ui_utils.printConfigChange(sys_config, warnings)
   local first_start = sys_config.isFirstStart()
   local config_changed = sys_config.configChanged()

   if config_changed or first_start then

      if is_nedge then
        local lan_networks = sys_config:getLanNetworks()
        local dhcp_config = sys_config:getDhcpServerConfig()

          if dhcp_config.enabled then
            local warn_dhcp_range = false
            for _, lan_config in pairs(lan_networks) do
              local lan_name = lan_config.iface
              if (not lan_name) or (not dhcp_config["subnet"][lan_name]) then
                goto continue
              end

              if not sys_config:hasValidDhcpRange(dhcp_config["subnet"][lan_name]["first_ip"], dhcp_config["subnet"][lan_name]["last_ip"]) and not warn_dhcp_range then
                warnings[#warnings + 1] = i18n("nedge.invalid_dhcp_range")
                warn_dhcp_range = true -- warn once in case of multiple interfaces
              end
              ::continue::
            end
          end
      end

      print(
        template.gen("modal_confirm_dialog.html", {
          dialog={
            id      = "config_apply_dialog_reboot",
            action  = "$('#applyNedgeConfig').submit()",
            title   = i18n("nedge.apply_configuration"),
            message = i18n("nedge.apply_configuration_and_reboot"),
	    custom_alert_class = "alert alert-danger",
            confirm = i18n("nedge.apply_and_reboot"),
            confirm_button = "btn-primary",
          }
        })
      )

      print(
        template.gen("modal_confirm_dialog.html", {
          dialog={
            id      = "config_apply_dialog_restart_self",
            action  = "$('#applyNedgeConfig').submit()",
            title   = i18n("nedge.apply_configuration"),
            message = i18n("nedge.apply_configuration_and_restart_self", {product = ntop.getInfo()["product"]}),
	    custom_alert_class = "alert alert-danger",
            confirm = i18n("nedge.apply_and_restart_self"),
            confirm_button = "btn-primary",
          }
        })
      )

      print[[<div class="alert alert-warning" role="alert"><i class="fas fa-exclamation-triangle fa-sm"></i> ]]
      print[[<strong>]] print(i18n("nedge.setup_config_edited_title")) print[[</strong> ]]
      print(ternary(not sys_config.configChanged(), i18n("nedge.apply_the_initial_device_configuration"), i18n("nedge.setup_config_edited_descr")))
      print[[<button style="visibility:hidden;">&nbsp;</button>]]
      print[[<div style="display: inline-block; float: right;">]]

      if config_changed then
        print[[<form name="modifyNedgeConfig" class="form-inline" style="display:inline;" method="POST">
    <input name="csrf" type="hidden" value="]] print(ntop.getRandomCSRFValue()) print [["/>
    <input type="hidden" name="nedge_config_action" value="discard">
    <button type="submit" class="btn btn-secondary">]] print(i18n("nedge.setup_discard")) print[[</button>
  </form>]]
      end

      print[[
<form id="applyNedgeConfig" name="modifyNedgeConfig" class="form-inline" style="display:inline;" method="POST">
  <input name="csrf" type="hidden" value="]] print(ntop.getRandomCSRFValue()) print [["/>
  <input type="hidden" name="nedge_config_action" value="make_permanent">
]]

      if sys_config:needsReboot() then
         print[[<button type="button" data-bs-toggle="modal" data-bs-target="#config_apply_dialog_reboot" class="btn btn-primary">]] print(i18n("nedge.setup_apply")) print[[</button>]]
      elseif sys_config:needsSelfRestart() then
         print[[<button type="button" data-bs-toggle="modal" data-bs-target="#config_apply_dialog_restart_self" class="btn btn-primary">]] print(i18n("nedge.setup_apply")) print[[</button>]]
      else
         print[[<button type="submit" class="btn btn-primary">]] print(i18n("nedge.setup_apply")) print[[</button>]]
      end
      print[[
</form>
</div>
</div>
]]
   end

   for _, warning in ipairs(warnings) do
      if not isEmptyString(warning) then
         printWarningAlert(warning)
      end
   end
end

function system_setup_ui_utils.printPageBody(sys_config, print_page_body_callback)
   print[[
<table class="table">
  <col width="20%">
  <col width="80%">
  <tr>
    <td>
      <div class="list-group">
]]

   local mode = sys_config:getOperatingMode()

   for _, subpage in ipairs(subpages) do
      if is_appliance and not subpage.appliance then
         goto continue
      elseif (not is_iot_bridge or mode == "passive") and subpage.name == "wifi" then
         goto continue
      elseif (is_iot_bridge and mode == "bridging") and subpage.name == "network_interfaces" then
         goto continue
      elseif is_nedge and not subpage.nedge then
         goto continue
      elseif is_nedge then
         if (subpage.routing_only == true) and (not sys_config:isMultipathRoutingEnabled()) then
            goto continue
         elseif (subpage.vlan_trunk == false) and (sys_config:isBridgeOverVLANTrunkEnabled()) then
            goto continue
         end
      end

      print("<a href=\""..ntop.getHttpPrefix().."/lua/")
      if is_nedge and not subpage.appliance then
         print("pro/nedge/")
      end
      print("system_setup_ui/")
      print(subpage.url)
      print[[" class="list-group-item list-group-item-action]]

      if((_SERVER["URI"] or ''):ends(subpage.url)) then
	 print(" active")
      end

      print[[">]] print(subpage.label) print[[</a>]]

      ::continue::
   end

   print[[
      </div>
    </td>
    <td colspan=2>
      <form method="POST">
         <table class="table">
]]

   if print_page_body_callback then
      print_page_body_callback()
   end

   print[[
         </table>

         <input id="csrf" name="csrf" type="hidden" value="]] print(ntop.getRandomCSRFValue()) print [[">
      </form>
    </td>
  </tr>
</table>

<script>
   aysHandleForm("form[name!='modifyNedgeConfig']", {
      disable_on_dirty: '.disable-on-dirty',
   });

   /* Use the validator to override default chrome bubble, which is displayed out of window */
   $("form[id!='search-host-form']").validator({disable:true});
</script>]]

   dofile(dirs.installdir .. "/scripts/lua/inc/footer.lua")
end


function system_setup_ui_utils.printPrivateAddressSelector(label, comment, ip_key, netmask_key, value, netmask_value, showEnabled, extra)
  local field_id = ip_key .. "__id"
  local networks_presets = {
    {prefix="192.168", netmask="255.255.0.0"},
    {prefix="172.16", netmask="255.255.0.0"},
    {prefix="10.0", netmask="255.255.0.0"},
  }
  extra = extra or {}
  local initial_preset = ""

  if isEmptyString(netmask_value) then
    netmask_value = "255.255.255.0"
  end
  local netmask_parts = string.split(netmask_value, "%.")

  local value_parts = { "", "", "", ""}
  if not isEmptyString(value) then
    value_parts = string.split(value, "%.")

    local prefix = table.concat({value_parts[1], value_parts[2]}, ".")

    for _, preset in pairs(networks_presets) do
      if preset.prefix == prefix then
        initial_preset = preset.prefix
        netmask_value = preset.netmask
        netmask_parts = string.split(netmask_value, "%.")
        break
      end
    end

    if isEmptyString(initial_preset) then
      local masked_parts = {}
      for _, xxx in ipairs(netmask_parts) do
        if xxx == '255' then
          masked_parts[_] = value_parts[_]
        end
      end
      initial_preset = table.concat(masked_parts, ".")
    end
  end

  if ((showEnabled == nil) or (showEnabled == true)) then
    showEnabled = "table-row"
  else
    showEnabled = "none"
  end

   print('<tr id="'..field_id..'" style="display: '..showEnabled..';"><td width=50%><strong>'..label..'</strong><p><small>'..comment..'</small></td>')
   print [[
    <td align=right>
      <table class="form-group mb-3" style="margin-bottom: 0; min-width:22em;">
        <tr class='border-0'>
          <td class="local-ip-selector border-0 text-end" style="vertical-align:top; padding-left: 2em;">]]

   if extra.net_select ~= false then
      print[[<select name="]] print(field_id) print[[_net" class="form-select d-inline-block" style="width: 9.6rem">]]
      for _, preset in pairs(networks_presets) do
         print[[<option value="]] print(preset.prefix) print[["]]
         if preset.prefix == initial_preset then
            print(" selected")
         end
         print[[>]]
         print(preset.prefix)
         print[[</option>]]
      end
      print[[</select> .]]
   else
      print[[<input type="hidden" name="]] print(field_id) print[[_net" value="]] print(initial_preset) print[[">]]

      for _, xxx in ipairs(netmask_parts) do
        if xxx == '255' then
          print[[<input class="form-control d-inline-block" style="width: 4.8rem" type="number" min="0" max="255" name="]] print(field_id) print[[_quad_]] print(tostring(_)) print[[" value="]] print(value_parts[_]) print[[" disabled /> . ]]
           
        end
      end
   end

   for _, xxx in ipairs(netmask_parts) do
      if xxx ~= '255' then
         print[[<input class="form-control d-inline-block" style="width: 4.8rem" type="number" min="0" max="255" name="]] print(field_id) print[[_quad_]] print(tostring(_)) print[[" value="]] print(value_parts[_]) print[[" />]]
         if _ ~= 4 then
           print[[ . ]]
         end
      end
   end

   print[[<input type="hidden" name="]] print(ip_key) print[[">]]

   if netmask_key ~= nil then
      print[[<input type="hidden" name="]] print(netmask_key) print[[" value="]] print(netmask_value) print[[">]]
   end

   print[[</div>
          </td>
        </tr>
        <tr>
          <td colspan="3" style="padding:0;">
            <div class="help-block with-errors text-end" style="height:1em;"></div>
          </td>
        </tr>
      </table>
  </td></tr>

  <script>
      var network_prefixes = ]] print(json.encode(networks_presets)) print[[;
      var form = $("#]] print(field_id) print[[").closest("form");

      if (! form.attr("data-privaddr-]] print(field_id) print[[")) {
        form.attr("data-privaddr-]] print(field_id) print[[", 1);
        form.submit(function(event) {
          var form = $(this);

          if (event.isDefaultPrevented() || (form.find(".has-error").length > 0))
            return false;

          var f_net = form.find('[name="]] print(field_id) print[[_net"]');
          var f_quad1 = form.find('[name="]] print(field_id) print[[_quad_1"]');
          var f_quad2 = form.find('[name="]] print(field_id) print[[_quad_2"]');
          var f_quad3 = form.find('[name="]] print(field_id) print[[_quad_3"]');
          var f_quad4 = form.find('[name="]] print(field_id) print[[_quad_4"]');
          var f_ip = form.find('[name="]] print(ip_key) print[["]');
]]
   if extra.net_select ~= false then
      print[[
          f_ip.val([f_net.val(), f_quad3.val(), f_quad4.val()].join("."));
      ]]
   else   
      print[[
          f_ip.val([f_quad1.val(), f_quad2.val(), f_quad3.val(), f_quad4.val()].join("."));
      ]]
   end

   if netmask_key ~= nil then
      print[[
          var f_netmask = form.find('[name="]] print(netmask_key) print[["]');
          var netmask_to_apply = null;

          for(var i=0; i<network_prefixes.length; i++) {
            if(network_prefixes[i].prefix == f_net.val()) {
               netmask_to_apply = network_prefixes[i].netmask;
               break;
            }
         }
          if(netmask_to_apply) f_netmask.val(netmask_to_apply);
         ]]
   end

   print[[
          // Clear the support fields
          f_net.removeAttr("name");
          f_quad1.removeAttr("name");
          f_quad2.removeAttr("name");
          f_quad3.removeAttr("name");
          f_quad4.removeAttr("name");

          // Reset form for ays
          aysResetForm(form);
          return true;
        });
      }
  </script>]]
end

function system_setup_ui_utils.prefsDateTimeFieldPrefs(label, comment, key, default_value, showEnabled, extra)
  extra = extra or {}

  if ((showEnabled == nil) or (showEnabled == true)) then
    showEnabled = "table-row"
  else
    showEnabled = "none"
  end

  local attributes = {}

  if extra.disabled == true then attributes["disabled"] = "disabled" end
  if extra.required == true then attributes["required"] = "" end

  local input_type = "text"
  print('<tr id="'..key..'" style="display: '..showEnabled..';"><td width=50%><strong>'..label..'</strong><p><small>'..comment..'</small></td>')

  local style = {}
  style["text-align"] = "right"
  style["margin-bottom"] = "0.5em"

  print [[
    <td align=right>
      <table class="form-group mb-3" style="margin-bottom: 0; min-width:22em;">
        <tr>
          <td width="100%;"></td>]]

      if extra.width == nil then
	 style["width"] = "20em"
	 style["margin-left"] = "auto"
      else
        style["width"] = "15em"
      end
      style["margin-left"] = "auto"

      style = table.merge(style, extra.style)
      attributes = table.merge(attributes, extra.attributes)

      local orig_name = key.."_orig"
      local picker_name = key.."_picker"

      print[[
          <td style="vertical-align:top; padding-left: 2em;">
            <input type="hidden" id="]] print(orig_name) print[[" name="]] print(orig_name) print[[" value="" />
            <div class='input-group' id=']] print(picker_name) print[[' style="width: 20em;" data-target-input="nearest">
               <span class="input-group-text"><i class="fas fa-calendar-alt"></i></span>

               <input id="]] print(key) print[[" name="]] print(key) print[[" type="text" class="form-control datetimepicker-input" data-target="#]] print(picker_name) print[[" data-toggle="datetimepicker"/>
            </div>

        <script type="text/javascript">
            var date_format = 'DD/MM/YYYY HH:mm:ss';
            var language = window.navigator.userLanguage || window.navigator.language;
            var bdate = new Date(]] print(default_value.."") print[[000);

            $(function () {
                $('#]] print(picker_name) print[[').datetimepicker({defaultDate: bdate, format: date_format});
                  $('#]] print(picker_name) print[[')
                  .on("change.datetimepicker", function(e) {
                     var input = $('#]] print(key) print[[').find('[name="' + "]] print(key) print[[" + '"]');
                     aysRecheckForm(input.closest("form"));
                  });
            $('#]] print(orig_name) print[[').val($('#]] print(picker_name) print[[').find("input").val());
            });

        </script>


          </td>
        </tr>
        <tr>
          <td colspan="3" style="padding:0;">
            <div class="help-block with-errors text-end" style="height:1em;"></div>
          </td>
        </tr>
      </table>
  </td></tr>

]]

end

return system_setup_ui_utils
