--    ======================
--    Description
--    ======================
--
--    Logika aktualizująca plik alertów
--
--    ======================
--    Parameters
--    ======================
--
--    SubLogic supports following variables:
--
--    input.filename                          - nazwa pliku alertów
--
--    input.save                              - zapisuje zmiany do plik alertów
--
--    input.reload                            - ponownie wczytuje plik alertów (anuluje zmiany)
--
--    setting.uuid                            - UUID
--
--    setting.recipient.id                    - lista - ID odbiorcy
--
--    setting.recipient.firstname             - lista - Imię odbiorcy
--
--    setting.recipient.lastname              - lista - Nazwisko odbiorcy
--
--    setting.recipient.phone                 - lista - Telefon odbiorcy w formacie +48xxxxxxxxx
--
--    setting.recipient.email                 - lista - Email odbiorcy
--
--    ======================
--    mandatory variables
--    ======================
--
--    Logic expects following mandatory variables:
--
--    reload.trigger                          - causes reloading lua script
--
--    memcnt                                  - current amount of memory used by lua in bytes
--
--    Logic expects following kv settings:
--
--    LuaScriptPath                           - path to the lua script - must be absolute
--
--    ======================
--    ChangeLog
--    ======================
--
--    2018-10-28 ver 0.0.0
--
--    # First release
--
-- user can use some functions provided by ibmanager.

-- ibmanager provides following functions to use:
--
-- function returns value of required ibmanager variable
-- @param fullName - string - variable name - name of variable of which value must be returned, for example "rs.0.id.255.input.t.0.value"
-- @return         - string or integer - variable value or "nil" if variable not exist or is not readable
--
-- getValue(fullName)


-- function set value of given ibmanager variable
-- @param fullName - string - variable name - name of variable of which value we want to set, for example "rs.0.id.255.input.t.0.value"
-- @param value    - string, int or boolean - value to set
-- @return         - nothing
--
-- setValue(fullName, value)


-- function returns value of required ibmanager variable
-- @param key      - placed in xml logic configuration file:
--                   * as attribute: Name, in Var, RemoteVar and ImportVar elements in the case of stand alone variables
--                   * as concatenation of two attributes: ListName.Postfix in VarListItem, RemoteVarListItem and ImportVarListItem elements
--                     in the case of variables that are placed in lists
-- @return         - string or integer - variable value or "nil" if variable not exist or is not readable
--
-- getLogicValue(key)


-- function set value of given ibmanager variable
-- @param key      - placed in xml logic configuration file:
--                   * as attribute: Name, in Var, RemoteVar and ImportVar elements in the case of stand alone variables
--                   * as concatenation of two attributes: ListName.Postfix in VarListItem, RemoteVarListItem and ImportVarListItem elements
--                     in the case of variables that are placed in lists
-- @param value    - string, int or boolean - value to set
-- @return         - nothing
--
-- setLogicValue(key, value)

-- function returns two sections of kvsettings from xml configuration file
-- returned value is two element table, each of these elements is table too.
-- indices of returned table are strings and equal "instance" and "global"
-- values of returned tables are tables and contain KVsettings for applicable section.
-- nested tables have form key = value, where key is index in nested table and value is value.
-- example: {"instance" = {"ikey1" = "ivalue1", "ikey2" = "gvalue2"}, "global" = {"gkey1" = "gvalue1", "gkey2" = "gvalue2", "gkey3" = "gvalue3"}}
-- @return          - two dimensional array - kvsettings for global and instance sections
-- getKvSettings()


-- function schedules alert to send.
-- rules are defined in separated alert configuration files and are described in ibmanager instruction manual
-- @param id - alert identifier - must be defined in current logic configuration file in section: <Alert Id="any_identifier" ...
-- scheduleAlert(id)

-- function cancels alert sending, if was previously scheduled. if not then only wakes up alerts handling thread, so if there is no need to call this function, then do not call it.
-- rules are defined in separated alert configuration files and are described in ibmanager instruction manual
-- @param id - alert identifier - must be defined in current logic configuration file in section: <Alert Id="any_identifier" ...
-- cancelAlert(name)

-- function returns table, containing Variables that belongs to required list.
-- @param listName - Name attribute of VarList, RemoteVarList or ImportVarList elemetnst in configurationfile
-- @return array of key-value pairs. Key - variable postfix, Value - Variable value
-- getVarList(listName)

-- function returns monotonic system clock value, that elapsed since specific epoch
-- returned time is expressed in milliseconds.
-- getClock()

-- function logs message to file, if defined in configuration file log level is less than passed to this function
-- @param logLevel - one of:
--        LogLevel.TraceLo
--        LogLevel.Trace
--        LogLevel.TraceHi
--        LogLevel.DebugLo
--        LogLevel.Debug
--        LogLevel.DebugHi
--        LogLevel.Info
--        LogLevel.Notice
--        LogLevel.Warning
--        LogLevel.Error
--        LogLevel.Critical
-- @param logMessage - string to log
-- log(logLevel, logMessage)


-- ibmanager provides following global variables:

-- logic type, (in this case it will always be "Lua") - the same as in logic configuration file in section: <Logic Type="Lua" ...
-- LOGIC_TYPE

-- logic version, the same as in logic configuration file in section: <Logic ... Version="x.y.z" ...
-- LOGIC_VERSION

-- logic sub-type, the same as in logic configuration file in section: <Logic ... SubType="Hysteresis" ...
-- LOGIC_SUBTYPE

-- logic sub-version, the same as in logic configuration file in section: <Logic ... SubVersion="x.y.z" ...
-- LOGIC_SUBVERSION

-- logic instance name - the same as in logic configuration file, in section: <Instance Name="0">
-- LOGIC_INSTANCE_NAME

-- add script directory to package path
package.path = package.path .. ";./logic/scripts/utils/?.lua";

-- use script - without .lua extension - delta class

SUPPORTED_SUBLOGIC_TYPE = "UpdateAlertsXML";
SUPPORTED_SUBLOGIC_VERSION = "0.0.0";
g_versionChecked = false;

SLAXML = require 'slaxdom'
g_doc =nil;
g_recipientCount = 0;

g_tableRecipientPostfix = {};

g_settingRecipientId = {};
g_settingRecipientFirstname = {};
g_settingRecipientLastname = {};
g_settingRecipientPhone = {};
g_settingRecipientEmail = {};

-- zwraca 1 jeżeli listy są OK
function checkLists()
    local fail = false
    
    if (g_recipientCount == 0) then
      error("VarList setting.recipient.id not initialized in instance section of configuration.");
      fail = true
    else
      for i = 0, g_recipientCount-1, 1 do
        
        -- Check for fail
        
        if g_settingRecipientFirstname[g_tableRecipientPostfix[i]] then
        else
          error("VarList element setting.recipient.firstname." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
          fail = true
        end
        
        if g_settingRecipientLastname[g_tableRecipientPostfix[i]] then
        else
          error("VarList element setting.recipient.lastname." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
          fail = true
        end

        if g_settingRecipientPhone[g_tableRecipientPostfix[i]] then
        else
          error("VarList element setting.recipient.phone." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
          fail = true
        end

        if g_settingRecipientEmail[g_tableRecipientPostfix[i]] then
        else
          error("VarList element setting.recipient.email." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
          fail = true
        end
      end
    end
    
    if fail then
      return 0
    else
      return 1
    end
    
end

function readAll(file)
    local f = assert(io.open(file, "rb"))
    local content = f:read("*all")
    f:close()
    return content
end

-- entry point to the logic
function onLogicCall(firstCall)

  if not g_versionChecked then
    -- checking sublogic type and sublogic version
    if LOGIC_SUBTYPE ~= SUPPORTED_SUBLOGIC_TYPE then
      error("Wrong logic sub-type. expected " .. SUPPORTED_SUBLOGIC_TYPE .. " but used " .. LOGIC_SUBTYPE);
    end
    local versionWithoutBuild = string.match(LOGIC_SUBVERSION, "[0-9]+%.[0-9]+%.[0-9]+");
    if versionWithoutBuild ~= SUPPORTED_SUBLOGIC_VERSION then
      error("Wrong logic sub-version. expected " .. SUPPORTED_SUBLOGIC_VERSION .. " but used " .. LOGIC_SUBVERSION);
    end
    g_versionChecked = true;
  end

  local inputFilename                    = getLogicValue("input.filename");
  local inputReload                      = getLogicValue("input.reload");
  local inputSave                        = getLogicValue("input.save");
  local settingUuid                      = getLogicValue("setting.uuid");
  local settingRecipientIdList           = getVarList("setting.recipient.id");
  local settingRecipientFirstnameList    = getVarList("setting.recipient.firstname");
  local settingRecipientLastnameList     = getVarList("setting.recipient.lastname");
  local settingRecipientPhoneList        = getVarList("setting.recipient.phone");
  local settingRecipientEmailList        = getVarList("setting.recipient.email");

  local i = 0;
  g_recipientCount = 0;

  -- tablica wartości id odbiorców
  if settingRecipientIdList ~= nil then
    for key, value in pairs(settingRecipientIdList) do
      g_settingRecipientId['' .. key] = value;
 
      g_tableRecipientPostfix[g_recipientCount] = key
      g_recipientCount = g_recipientCount + 1;
    end
  end

  -- tablica imion odbiorców
  if settingRecipientFirstnameList ~= nil then
    for postfix, value in pairs(settingRecipientFirstnameList) do
      g_settingRecipientFirstname['' .. postfix] = value;
    end
  end

  -- tablica nazwisk odbiorców
  if settingRecipientLastnameList ~= nil then
    for postfix, value in pairs(settingRecipientLastnameList) do
      g_settingRecipientLastname['' .. postfix] = value;
    end
  end

  -- tablica telefonów odbiorców
  if settingRecipientPhoneList ~= nil then
    for postfix, value in pairs(settingRecipientPhoneList) do
      g_settingRecipientPhone['' .. postfix] = value;
    end
  end

  -- tablica emaili odbiorców
  if settingRecipientEmailList ~= nil then
    for postfix, value in pairs(settingRecipientEmailList) do
      g_settingRecipientEmail['' .. postfix] = value;
    end
  end

  if (firstCall) or (inputReload == 1) then

    print('=================');

    if (g_recipientCount == 0) then
      error("VarList setting.recipient.id not initialized in instance section of configuration.");
    else
      for i = 0, g_recipientCount-1, 1 do
        g_settingRecipientId[g_tableRecipientPostfix[i]] = -1;
        setLogicValue("setting.recipient.id." .. g_tableRecipientPostfix[i], g_settingRecipientId[g_tableRecipientPostfix[i]]);

        if g_settingRecipientFirstname[g_tableRecipientPostfix[i]] then
          g_settingRecipientFirstname[g_tableRecipientPostfix[i]] = "";
          setLogicValue("setting.recipient.firstname." .. g_tableRecipientPostfix[i], g_settingRecipientFirstname[g_tableRecipientPostfix[i]]);
        else
          error("VarList element setting.recipient.firstname." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
        end

        if g_settingRecipientLastname[g_tableRecipientPostfix[i]] then
          g_settingRecipientLastname[g_tableRecipientPostfix[i]] = "";
          setLogicValue("setting.recipient.lastname." .. g_tableRecipientPostfix[i], g_settingRecipientLastname[g_tableRecipientPostfix[i]]);
        else
          error("VarList element setting.recipient.lastname." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
        end

        if g_settingRecipientPhone[g_tableRecipientPostfix[i]] then
          g_settingRecipientPhone[g_tableRecipientPostfix[i]] = "";
          setLogicValue("setting.recipient.phone." .. g_tableRecipientPostfix[i], g_settingRecipientPhone[g_tableRecipientPostfix[i]]);
        else
          error("VarList element setting.recipient.phone." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
        end

        if g_settingRecipientEmail[g_tableRecipientPostfix[i]] then
          g_settingRecipientEmail[g_tableRecipientPostfix[i]] = "";
          setLogicValue("setting.recipient.email." .. g_tableRecipientPostfix[i], g_settingRecipientEmail[g_tableRecipientPostfix[i]]);
        else
          error("VarList element setting.recipient.email." .. g_tableRecipientPostfix[i] .. " not initialized in instance section of configuration.");
        end

      end
    end;

    g_doc = SLAXML:dom(readAll(inputFilename), {stripWhitespace=true})

    for _,n1 in ipairs(g_doc.kids) do
      if n1.name == 'Config' then

        for _,n2 in ipairs(n1.kids) do

          -- print('n2', n2.name);

          if n2.name == 'User' then
            for _,attr in ipairs(n2.attr) do
              if attr.name == 'UUID' then
                settingUuid = attr.value
              end
            end
          end

          if n2.name == 'Recipients' then
            i = 0;
            
            for _,n3 in ipairs(n2.kids) do
              -- print('n3', i, n3.name);

              for _,attr in ipairs(n3.attr) do
                
                -- print('attr', i, tableRecipientPostfix[i], attr.name, attr.value);

                if attr.name == 'Id' then
                  g_settingRecipientId[g_tableRecipientPostfix[i]] = attr.value
                  setLogicValue("setting.recipient.id." .. g_tableRecipientPostfix[i], attr.value);
                end

                if attr.name == 'FirstName' then
                  g_settingRecipientFirstname[g_tableRecipientPostfix[i]] = attr.value
                  setLogicValue("setting.recipient.firstname." .. g_tableRecipientPostfix[i], attr.value);
                end

                if attr.name == 'LastName' then
                  g_settingRecipientLastname[g_tableRecipientPostfix[i]] = attr.value
                  setLogicValue("setting.recipient.lastname." .. g_tableRecipientPostfix[i], attr.value);
                end

                if attr.name == 'Phone' then
                  g_settingRecipientPhone[g_tableRecipientPostfix[i]] = attr.value
                  setLogicValue("setting.recipient.phone." .. g_tableRecipientPostfix[i], attr.value);
                end

                if attr.name == 'Email' then
                  g_settingRecipientEmail[g_tableRecipientPostfix[i]] = attr.value
                  setLogicValue("setting.recipient.email." .. g_tableRecipientPostfix[i], attr.value);
                end

              end

              i = i + 1;

            end
          end

        end
      end
    end

    setLogicValue("input.reload", 0);
    setLogicValue("setting.uuid", settingUuid);
  end
  

  if inputSave == 1 then

    print('=================');
    
    -- local inspect = require('inspect')
    -- print(inspect(n2.kids));

    for _,n1 in ipairs(g_doc.kids) do
      if n1.name == 'Config' then
        
        for _,n2 in ipairs(n1.kids) do
          
          if n2.name == 'User' then
            for _,attr in ipairs(n2.attr) do
              if attr.name == 'UUID' then
                attr.value = settingUuid
              end
            end
          end

          if n2.name == 'Recipients' then
            i = 0;
            n2.kids = nil         
          end
        end       
      end
    end

    local xml = SLAXML:xml(g_doc, {indent=2})
    
    local recipientsGenerated = ""
    
    if checkLists() == 1 then
      recipientsGenerated = "<Recipients>"
    
      for i = 0, g_recipientCount-1, 1 do
        
        if (g_settingRecipientId[g_tableRecipientPostfix[i]] ~= -1) and
           (g_settingRecipientFirstname[g_tableRecipientPostfix[i]] ~= "") and
           (g_settingRecipientLastname[g_tableRecipientPostfix[i]] ~= "") and
           (g_settingRecipientPhone[g_tableRecipientPostfix[i]] ~= "") and
           (g_settingRecipientEmail[g_tableRecipientPostfix[i]] ~= "") then

          recipientsGenerated = recipientsGenerated .. '<Recipient Id="' .. g_settingRecipientId[g_tableRecipientPostfix[i]] .. '" '       
          recipientsGenerated = recipientsGenerated .. 'FirstName="' .. g_settingRecipientFirstname[g_tableRecipientPostfix[i]] .. '" '
          recipientsGenerated = recipientsGenerated .. 'LastName="' .. g_settingRecipientLastname[g_tableRecipientPostfix[i]] .. '" '
          recipientsGenerated = recipientsGenerated .. 'Phone="' .. g_settingRecipientPhone[g_tableRecipientPostfix[i]] .. '" '
          recipientsGenerated = recipientsGenerated .. 'Email="' .. g_settingRecipientEmail[g_tableRecipientPostfix[i]] .. '" />'
        end
      end

      recipientsGenerated = recipientsGenerated .. "</Recipients>"

    else
      recipientsGenerated = "<Recipients/>"
    end

    print (recipientsGenerated);

    xml = xml:gsub("<Recipients/>", recipientsGenerated)
    
    g_doc = SLAXML:dom(xml, {stripWhitespace=true})

    xml = SLAXML:xml(g_doc, {indent=2})

    local file = io.open(inputFilename, "w")
    file:write(xml)
    file:close()
   

    setLogicValue("input.save", 0);
  end

end
