-- 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 c_object = require 'mc.orm.object'
local log = require 'mc.logging'
local valve_enums = require 'valve_enums'

local valve_obj_manager = c_object('Valve')

function valve_obj_manager:get_opening_degree()
    return self.OpeningDegree
end

function valve_obj_manager:get_id()
    return self.Id
end

function valve_obj_manager:get_slot()
    return self.Slot
end

function valve_obj_manager:get_standard_opening_degree()
    return self.StandardOpeningDegree
end

function valve_obj_manager:get_mode()
    return self.Mode
end

function valve_obj_manager:is_present()
    return self.Presence == 1
end

function valve_obj_manager:set_opening_degree(degree)
    -- 开度范围0~1000
    if degree > valve_enums.OPENING_DEGREE_MAX then
        log:error('[thermal_mgmt] set_opening_degree failed. StandardOpeningDegree = %d, degree = %d', self.StandardOpeningDegree, degree)
        return false
    end

    self.OpeningDegree = degree
    return true
end

function valve_obj_manager:set_opening_degree_state(state)
    self.OpeningDegreeState = state
end

function valve_obj_manager:set_patrol_result(result)
    self.PatrolResult = result
end

-- 校验current_degree开度值是否在target_degree允许的误差范围
function valve_obj_manager:check_opening_degree(current_degree, target_degree, error_range)
    if current_degree > valve_enums.OPENING_DEGREE_MAX then
        return false
    end

    if current_degree >= target_degree - error_range and current_degree <= target_degree + error_range then
        return true
    end

    return false
end

function valve_obj_manager:do_patrol()
    log:notice('[thermal_mgmt] valve patrol:id-%d, slot-%s', self.Id, self.Slot)

    local standard_opening_degree = self:get_standard_opening_degree()

    -- 标定开度未进行出厂配置或超出范围，巡检异常告警
    if standard_opening_degree > valve_enums.OPENING_DEGREE_MAX then
        log:error('[thermal_mgmt] invalid standard opening degree(%s)', standard_opening_degree)
        -- 根据巡检异常结果记录运行日志
        log:running(log.RLOG_INFO, 'Failed to inspect the valve(slot-%s)', self.Slot)
        return valve_enums.Patrol_Result.Failed
    end

    -- 巡检流程
    local current_opening_degree
    local opening_degree_state
    local cnt = 0
    local RETRY_COUNT = 2

    while cnt < RETRY_COUNT do
        -- 设置目标开度
        self:set_opening_degree(standard_opening_degree + 130)

        self:sleep_ms(5 * 1000)

        -- 读取当前开度值
        current_opening_degree = self:get_opening_degree()

        -- 巡检标准：巡检值为标定值+13%开度，排除3%开度误差，判断标准为10%开度（最小调节单位）
        if self:check_opening_degree(current_opening_degree, standard_opening_degree + 130, 30) then
            opening_degree_state = valve_enums.Opening_Degree_State.Normal
            break
        else
            opening_degree_state = valve_enums.Opening_Degree_State.Abnormal
            cnt = cnt + 1
        end
    end

    -- 更新开度状态
    self:set_opening_degree_state(opening_degree_state)
    -- 恢复标称值
    self:set_opening_degree(standard_opening_degree)

    -- 根据开度状态巡检结果记录运行日志
    if opening_degree_state == valve_enums.Opening_Degree_State.Normal then
        log:running(log.RLOG_INFO, 'Successfully inspect the valve(slot-%s)', self.Slot)
    else
        log:running(log.RLOG_INFO, 'Failed to inspect the valve(slot-%s)', self.Slot)
    end

    return valve_enums.Patrol_Result.Success
end

function valve_obj_manager:init()
    self:connect_signal(self.on_add_object, function()
    end)
    self:connect_signal(self.on_add_object_complete, function()
        log:notice('[thermal_mgmt] valve on_add_object_complete id: %d, slot: %s',
            self.Id, self.Slot)
    end)
    valve_obj_manager.super.init(self)
end

return valve_obj_manager
