-- 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.

-- Description: fructl的相关工具
local log = require 'mc.logging'
local context = require 'mc.context'
local class = require 'mc.class'
local skynet = require 'skynet'
local client = require 'bios.client'
local bs_util = require 'util.base_util'

local fructl = class()

function fructl.find_obj_by_system_id(objects, system_id)
    if not objects then
        return
    end
    if not system_id then
        system_id = 1
    end
    for _, obj in pairs(objects) do
        if bs_util.get_obj_id(obj.path) == system_id then
            return obj
        end
    end
    return
end

function fructl.get_power_lock_obj(system_id)
    return fructl.find_obj_by_system_id(client:GetPowerOnLockObjects(), system_id)
end

function fructl.get_memory_obj()
    local objects = client:GetMemoryObjects()
    return objects
end

function fructl.get_fructl_obj(system_id)
    local ok, obj = pcall(client.GetFruCtrlFruCtrlObject, client, {SystemId = system_id, Id = ':Id'})
    if not ok then
        return
    end
    return obj
end

-- 获取上下电状态
function fructl.get_power_status(system_id)
    system_id = system_id or 1
    local obj = fructl.get_fructl_obj(system_id)
    if not obj then
        log:error('[bios]get_power_status: get power object failed')
        return nil
    end
    return obj.PowerState
end

function fructl.get_power_restart_cause(system_id)
    system_id = system_id or 1
    local obj = fructl.get_fructl_obj(system_id)
    if not obj then
        log:error("[bios]get_power_restart_cause: get power obj failed")
        return nil
    end
    return obj.CurrentRestartCause
end

-- 获取上电策略
function fructl.get_power_strategy(system_id)
    system_id = system_id or 1
    local obj = fructl.get_fructl_obj(system_id)
    if not obj then
        log:error('[bios]get_power_status: get power object failed')
        return nil
    end
    return obj.PowerOnStrategy
end

-- 加上电锁、释放上电锁
function fructl.set_power_on_lock(state, timeout, reason, app_name, system_id)
    system_id = system_id or 1
    local obj = fructl.get_power_lock_obj(system_id)
    if not obj then
        log:error('[bios]set_power_on_lock: get power object failed')
        return nil
    end
    return obj.pcall:SetPowerOnLock(context.new(), state, timeout, app_name, reason)
end

function fructl.get_context()
    local ctx
    local ok = pcall(function()
        ctx = context.new()
        ctx.Requestor = 'bmc.kepler.bios'
    end)
    if not ok then
        return context.new()
    else
        return ctx
    end
end

-- 上下电
function fructl.set_power_state(state, reason, system_id)
    system_id = system_id or 1
    local obj = fructl.get_fructl_obj(system_id)
    if not obj then
        log:error('[bios]set_power_state: get power object failed')
        return nil
    end
    return obj.pcall:PowerCtrl(fructl.get_context(), state, reason)
end

function fructl.try_set_power_state(times, state, reason, system_id)
    system_id = system_id or 1
    local res
    while times > 0  do
        times = times - 1
        res = fructl.set_power_state(state, reason, system_id)
        if res then
            return
        end
        skynet.sleep(100)
    end
    error(string.format('[bios]try set power state(%s) fail', state))
end

function fructl.wait_until_power_off(times, system_id)
    system_id = system_id or 1
    local power_status
    while times > 0  do
        times = times - 1
        power_status = fructl.get_power_status(system_id)
        if power_status == 'OFF' then
            return
        end
        skynet.sleep(60)
    end
    error(string.format('[bios]wait power off timeout'))
end

return fructl