-- module defines most common functions

-- function returns 1 if currentValue <= demandValue or returns 0 if currentValue >= currentValue. Including hysteresis.
function lowerThan(currentState, currentValue, demandValue, hysteresis)
  local result = currentState;

  if ((currentState == 0) and (currentValue <= (demandValue - hysteresis / 2))) then
    result = 1;
  end

  if ((currentState == 1) and (currentValue >= (demandValue + hysteresis / 2))) then
    result = 0;
  end

  return result;
end

-- function returns 1 if currentValue >= demandValue or returns 0 if currentValue <= currentValue. Including hysteresis.
function higherThan(currentState, currentValue, demandValue, hysteresis)
  local result = currentState;

  if ((currentState == 1) and (currentValue <= (demandValue - hysteresis / 2))) then
    result = 0;
  end

  if ((currentState == 0) and (currentValue >= (demandValue + hysteresis / 2))) then
    result = 1;
  end

  return result;
end

-- function returns 1 if sourceValue>=targetValue including dtOn and dtOff
function checkDelta(currentState, sourceValue, targetValue, dtOn, dtOff)
  local result = currentState;

  if ((currentState == 0) and (sourceValue - targetValue >= dtOn)) then
    result = 1;
  end

  if ((currentState == 1) and (sourceValue - targetValue <= dtOff)) then
    result = 0;
  end

  return result;
end

-- zwraca tabele key,value posortowaną w/g value
-- parametr dodatkowy f pozwala ustalić sposób sortowania
-- Przykład użycia:
--
--    for postfix, value in pairsByKeys(settingPointInput) do
--      print(postfix, value)
--    end

-- iterator that traverses a table following the order of its keys.
-- An optional parameter f allows the specification of an alternative order. 
-- It first sorts the keys into an array, and then iterates on the array. 
-- At each step, it returns the key and value from the original table
function pairsByKeys (t, f)
  local a = {}
  for n in pairs(t) do table.insert(a, n) end
  table.sort(a, f)
  local i = 0      -- iterator variable
  local iter = function ()   -- iterator function
    i = i + 1
    if a[i] == nil then return nil
    else return a[i], t[a[i]]
    end
  end
  return iter
end

-- zwraca tabele key,value posortowaną w/g value
-- parametr dodatkowy f pozwala ustalić sposób sortowania
--
-- Przykład użycia:
--
--    for postfix, value in pairsByValues(settingPointInput) do
--      print(postfix, value)
--    end

function pairsByValues(t, f)
  local a, b = {}, {} -- "a" keeps custom values or player number or handleId (keys), "b" keeps values
  for k, v in pairs(t) do
     table.insert(b, v)
      a[v]=k
  end
  table.sort(b, f)
  local i = 0                    -- iterator variable
  local iter = function ()   -- iterator function
     i = i + 1
      if b[i] == nil then return nil
         else return a[b[i]], b[i]
      end
  end
  return iter
end

-- zwraca pierwszy znaleziony klucz, którego wartość się zgadza z value
-- funkcja przydatna do zwrócenia indexu w tabeli zawierające prefixy z varList
--
-- Przykład użycia:
--
--    for postfix, value in pairsByValues(g_settingInput) do
--      i = tonumber(getKeyByValue(g_tablePointsPostfix, postfix))
--      print(i, g_tablePointsPostfix[i], g_settingInput[g_tablePointsPostfix[i]], g_settingOutput[g_tablePointsPostfix[i]] );
--    end

function getKeyByValue(a_table, a_value)
  local res = ''
  for k, v in pairs(a_table) do
    if (v == a_value) then
      res = '' .. k
      break
    end
  end
  
  return res
end

-- czy wartości w tablicy są unikalne

function uniqueValues(a_table)
  for i_postfix, i_value in pairs(a_table) do
    for j_postfix, j_value in pairs(a_table) do
      if (i_value == j_value) and (i_postfix ~= j_postfix) then
        --print('Found duplicated values in varList: ' .. i_value)
        return false
      end
    end
  end
  
  return true
end

-- kopiuje obiekty (tablice) - tworzy duplikat

function copyObj(obj, seen)
  if type(obj) ~= 'table' then return obj end
  if seen and seen[obj] then return seen[obj] end
  local s = seen or {}
  local res = setmetatable({}, getmetatable(obj))
  s[obj] = res
  for k, v in pairs(obj) do res[copyObj(k, s)] = copyObj(v, s) end
  return res
end

-- porównuje dwa obiekty (zawartość) czy wartości w nich zawarte są sobie równe

function equals(o1, o2, ignore_mt)
    if o1 == o2 then return true end
    local o1Type = type(o1)
    local o2Type = type(o2)
    if o1Type ~= o2Type then return false end
    if o1Type ~= 'table' then return false end

    if not ignore_mt then
        local mt1 = getmetatable(o1)
        if mt1 and mt1.__eq then
            --compare using built in method
            return o1 == o2
        end
    end

    local keySet = {}

    for key1, value1 in pairs(o1) do
        local value2 = o2[key1]
        if value2 == nil or equals(value1, value2, ignore_mt) == false then
            return false
        end
        keySet[key1] = true
    end

    for key2, _ in pairs(o2) do
        if not keySet[key2] then return false end
    end
    return true
end