-- 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 skynet = require 'skynet'

local sn_replace = {}
sn_replace.__index = sn_replace

function sn_replace.new(db, component_object, component_name)
    return setmetatable({
        db = db,
        component_object = component_object,
        component_name = component_name
    }, sn_replace)
end

function sn_replace:check_replace_event(value)
    local db_obj = self.db:select(self.db.ComponentMapping):where(self.db.ComponentMapping.ComponentName:eq(self
        .component_name)):first()

    -- 硬盘、内存等硬件在os下电等情况下会把SN修改为'N/A'或''，此时需要更新PreviousSN
    if value == 'N/A' or value == '' then
        if db_obj then
            self.component_object.PreviousSN = db_obj.PreviousSN
        end
        return
    end

    -- 没有对象数据，则认为是单板初次插入
    if not db_obj then
        self.component_object.PreviousSN = value
        local com_db = self.db.ComponentMapping({ ComponentName = self.component_name })

        -- 数据库持久化PreviousSN
        com_db.PreviousSN = value
        com_db:save()
        log:notice('first insert, component_name = %s, BoardSerialNumber = %s', self.component_name,
            com_db.PreviousSN)
    else
        log:info('board already exists, component_name = %s, BoardSerialNumber = %s', self.component_name,
            db_obj.PreviousSN)
        -- SN和上次不一样，则认为发生了替换
        if db_obj.PreviousSN ~= value then
            local com_db = self.db.ComponentMapping({ ComponentName = self.component_name })
            local pre_sn = com_db.PreviousSN
            com_db.PreviousSN = value
            com_db:save()

            self.component_object.PreviousSN = pre_sn
            -- BoardSerialNumber发生变化标志，用于上报事件
            self.component_object.ReplaceFlag = 0 -- 此处先置位避免多次拔插时无法上报，同时避免更换后标志显示为0
            skynet.sleep(0)
            self.component_object.ReplaceFlag = 1
            log:notice('BoardSerialNumber changed from %s to %s', pre_sn, value)
        else
            -- 没有发生替换
            self.component_object.PreviousSN = value
            log:info('Component object BoardSerialNumber is %s', value)
        end
    end
end

-- 判断SN是否变化
function sn_replace:update_component_serialnumber()
    self.component_object.property_changed:on(function(name, value, _)
        if name ~= 'SerialNumber' then
            return
        end

        self:check_replace_event(value)
    end)

    self:check_replace_event(self.component_object.SerialNumber)
end

return sn_replace