-- 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: IPMI Entity instance process.
local log = require 'mc.logging'
local utils = require 'sensor_utils'

local entity_instance = {}
entity_instance.__index = entity_instance

function entity_instance.new(mdb_obj, key, sensor_sigs, host_id)
    return setmetatable({
        mdb_obj = mdb_obj,
        key = key,
        sensor_sigs = sensor_sigs,
        normal_sensor_num = 0,
        minor_sensor_num = 0,
        major_sensor_num = 0,
        critical_sensor_num = 0,
        host_id = host_id
    }, entity_instance)
end

function entity_instance:update_health_count(last_health, cur_health)
    -- 第一步：根据上一次健康状态调整对应的传感器数量值（核减1次）
    if last_health == utils.HEALTH_NORMAL and self.normal_sensor_num > 0 then
        self.normal_sensor_num = self.normal_sensor_num - 1
    elseif last_health == utils.HEALTH_MINOR and self.minor_sensor_num > 0 then
        self.minor_sensor_num = self.minor_sensor_num - 1
    elseif last_health == utils.HEALTH_MAJOR and self.major_sensor_num > 0 then
        self.major_sensor_num = self.major_sensor_num - 1
    elseif last_health == utils.HEALTH_CRITICAL and self.critical_sensor_num > 0 then
        self.critical_sensor_num = self.critical_sensor_num - 1
    end

    -- 第二步：根据本次的健康状态调整对应的传感器数量值（核增1次）
    if cur_health == utils.HEALTH_NORMAL then
        self.normal_sensor_num = self.normal_sensor_num + 1
    elseif cur_health == utils.HEALTH_MINOR then
        self.minor_sensor_num = self.minor_sensor_num + 1
    elseif cur_health == utils.HEALTH_MAJOR then
        self.major_sensor_num = self.major_sensor_num + 1
    elseif cur_health == utils.HEALTH_CRITICAL then
        self.critical_sensor_num = self.critical_sensor_num + 1
    end
end

function entity_instance:update_health(last_health, cur_health)
    -- 第一步：更新当前的导致健康状态变化的个数
    self:update_health_count(last_health, cur_health)

    -- 第二步：更替上一次的健康状态，并且更新当前健康状态值
    local health = utils.HEALTH_NORMAL
    if self.critical_sensor_num > 0 then
        health = utils.HEALTH_CRITICAL
    elseif self.major_sensor_num > 0 then
        health = utils.HEALTH_MAJOR
    elseif self.minor_sensor_num > 0 then
        health = utils.HEALTH_MINOR
    end
    log:info('entity [0x%06X] health has been changed from %d to %d', self.key, self.mdb_obj['Health'], health)
    self.mdb_obj['Health'] = health
end

function entity_instance:initialize()
    -- 接入时根据当前的在位和上下电状态先检查一下Entity状态
    if self.mdb_obj['PowerState'] == 0 or self.mdb_obj['Presence'] == 0 then
        self:update_sensor_status(utils.SCAN_DISABLED)
    else
        self:update_sensor_status(utils.SCAN_ENABLED)
    end
end

function entity_instance:listen()
    -- 监听 Entity 类的在位和上下电状态变化
    self.mdb_obj.property_changed:on(function(name, value, sender)
        if name ~= 'PowerState' and name ~= 'Presence' then
            return
        end

        log:info('entity [0x%06X] %s is changed to %d', self.key, name, value)
        local status = value == 0 and utils.SCAN_DISABLED or utils.SCAN_ENABLED
        self:update_sensor_status(status)
    end)
end

function entity_instance:update_sensor_status(status)
    -- 将当前的状态发送给sensor进行处理
    self.sensor_sigs.update:emit(self.mdb_obj.Id, self.mdb_obj.Instance, self.host_id, status)
end

function entity_instance:power_ctrl(state)
    self.mdb_obj['PowerState'] = state == 1 and 1 or 0
end

function entity_instance:is_disabled()
    return (self.mdb_obj['PowerState'] == 0 or self.mdb_obj['Presence'] == 0)
end

return entity_instance