-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
--
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local log = require 'mc.logging'
local context = require 'mc.context'

local m = {}

--@function 查询用户期望电源主备供电
--          Setted active power supply. per bit represents a PS, bit0 is PS1, and so on,
--          the bit value of 1 indicates the PS is active.can not set all PS are active or backup.
function m.get_setted_active_power(device_spec, active_standby_supported, power_worke_mode, expected_active_psu)
    local ps_max_num -- 产品电源最大个数
    local iPowerMode = 0
    for _, device_obj in ipairs(device_spec) do
        if device_obj[1] == 'Psu' then -- 设备名
            ps_max_num = device_obj[2] -- 设备数量
            break
        end
    end
    if not ps_max_num then -- 获取最大电源个数失败
        log:error("Object(bmc.kepler.Chassis) property Psu not found") -- 设备中未找到Psu
        error(base_messages.Success())
    end
    local entireValue = tonumber(2 ^ ps_max_num - 1)
    if power_worke_mode == "LoadBalancing" then
        return entireValue
    end
    if not active_standby_supported then -- 不支持主备
        return 0x7FFFFFFF
    end
    for _, psu_id in ipairs(expected_active_psu) do
        iPowerMode = iPowerMode | (2 ^ (psu_id - 1)) -- bit位为1表示电源期望为主用
    end
    iPowerMode = iPowerMode & entireValue
    return iPowerMode
end

-- 用户输入的主用电源ModeMask转换为数组
function m.get_setted_active_psu_table(device_spec, active_standby_supported, setted_active_power)
    local expected_active_psu = {}
    if not active_standby_supported then -- 不支持主备
        error(base_messages.ResourceMissingAtURI()) -- SnmpStatusCode=2
    end

    local ps_max_num -- 产品电源最大个数
    for _, device_obj in ipairs(device_spec) do
        if device_obj[1] == 'Psu' then -- 设备名
            ps_max_num = device_obj[2] -- 设备数量
            break
        end
    end
    if not ps_max_num then -- 获取最大电源个数失败
        log:error("Object(bmc.kepler.Chassis) property Psu not found") -- DeviceMaxCount数组中未找到Psu
        error(base_messages.Success())
    end
    local entireValue = tonumber(2 ^ ps_max_num - 1)

    -- 设置电源超过当前个数或全为主用电源
    if setted_active_power >= entireValue then
        log:error('Can not set all PS are active or backup')
        error(custom_messages.SimpleCommunityName()) -- SnmpStatusCode=3
    end

    for i = 0, ps_max_num - 1 do
        if (2 ^ i) & setted_active_power == 2 ^ i then
            table.insert(expected_active_psu, i + 1)
        end
    end
    table.sort(expected_active_psu)
    return expected_active_psu
end

function m.set_power_limit_fail_action(fail_action)
    local MDB_SERVICE = 'bmc.kepler.power_strategy'
    local MDB_PATH = '/bmc/kepler/Systems/1/PowerStrategy'
    local MDB_INTERFACE = 'bmc.kepler.Systems.PowerStrategy'
    local err, _ = bus:pcall(MDB_SERVICE, MDB_PATH, MDB_INTERFACE, 'SetPowerLimitException', 'a{ss}s',
    context.get_context() or context.new(), fail_action)
    if err and err.name == "org.freedesktop.DBus.Error.UnknownMethod" then
        if fail_action == "NoAction" then
            error(base_messages.PropertyValueNotInList("LogEventOnly", "PowerLimitException"))
        end
        return false
    end
    if err then
        error(err)
    end
    return true
end

function m.get_power_limit_fail_action()
    local MDB_SERVICE = 'bmc.kepler.power_strategy'
    local MDB_PATH = '/bmc/kepler/Systems/1/PowerStrategy'
    local MDB_INTERFACE = 'bmc.kepler.Systems.PowerStrategy'
    local err, fail_action = bus:pcall(MDB_SERVICE, MDB_PATH, MDB_INTERFACE, 'GetPowerLimitException', 'a{ss}',
    context.get_context() or context.new())
    if err and err.name == "org.freedesktop.DBus.Error.UnknownMethod" then
        return nil
    end
    if err then
        error(err)
    end
    return fail_action
end

return m
