-- 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 skynet = require 'skynet'
local singleton = require 'mc.singleton'
local log = require 'mc.logging'
local context = require 'mc.context'
local enums = require 'macros.power_mgmt_enums'
local class = require 'mc.class'

local lock_chip = class()

function lock_chip:lock(chip, timeout)
    if not chip then
        error('Chip obj is nil')
    end
    if not chip.SetLockStatus then
        return 0
    end
    if chip.LockStatus ~= enums.LOCK_TYPE.UNLOCK then
        log:notice('Chip does not need to be lock')
        return 0
    end
    local result = chip:SetLockStatus(context.new(), enums.LOCK_TYPE.LOCK, timeout)
    if result == enums.LOCK_RESULT_CODE.SUCCESS then
        log:notice('Lock chip Successfully')
    end
    return result
end

-- 加锁：count表示重复加锁的次数，默认为60次，timeout表示加锁的超时时间，默认为300s
function lock_chip:retry_lock_chip(chip, count, timeout)
    count = not count and enums.LOCK_PROPERTY.RETRY_COUNT or count
    timeout = not timeout and enums.LOCK_PROPERTY.LOCK_TIME or timeout
    local ok, res
    while count > 0 do
        ok, res = pcall(function ()
            return self:lock(chip, timeout)
        end)
        if not ok then
            goto continue
        end
        if res == enums.LOCK_RESULT_CODE.SUCCESS then
            return
        end
        ::continue::
        count = count - 1
        skynet.sleep(100)
    end
    error(string.format("Lock chip failed, error code: %s", res))
end

function lock_chip:unlock(chip)
    if not chip then
        error('Chip obj is nil')
    end
    if not chip.SetLockStatus then
        return 0
    end
    if chip.LockStatus ~= enums.LOCK_TYPE.LOCK then
        log:notice('Chip does not need to be unlocked')
        return 0
    end
    local result = chip:SetLockStatus(context.new(), enums.LOCK_TYPE.UNLOCK, 0)
    if result == enums.LOCK_RESULT_CODE.SUCCESS then
        log:notice('Unlock chip Successfully')
    end
    return result
end

function lock_chip:retry_unlock_chip(chip, count)
    count = not count and enums.LOCK_PROPERTY.RETRY_COUNT or count
    local ok, res
    while count > 0 do
        ok, res = pcall(function()
            return self:unlock(chip)
        end)
        if not ok then
            goto continue
        end
        if res == enums.LOCK_RESULT_CODE.SUCCESS then
            return
        end
        ::continue::
        count = count - 1
        skynet.sleep(100)
    end
    error(string.format('Unlock chip failed, error code: %s', res))
end

return singleton(lock_chip)