-- 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 frudata_intf = require 'frudata_intf'
local common = require 'common'
local manage = require 'frudata_object.manage'
local queue = require 'skynet.queue'
local cs = queue()
local context = require 'mc.context'

local MAX_MULTI_LEN <const> = 1024

local frudata_object = {}

frudata_object.__index = frudata_object

function frudata_object:new(fruinfo_manage, obj)
    return setmetatable({
        fruinfo_manage = fruinfo_manage,
        obj = obj
    }, frudata_object)
end

function frudata_object:init()
    local fru_id = self.obj.FruId
    local fru_file, system_data, fru_offset, uid

    fru_file, system_data, fru_offset, uid = manage:frudev_read_from_eeprom(self.obj)
    if uid ~= '' then
        manage:update_fru_uid(fru_id, uid)
    end

    -- EepromV2类型电子标签eeprom_format为0，其他类型默认使用TianChi规范类型为1
    local eeprom_format = 0
    local is_sup_dft = 1
    local is_sys_area = fru_id == 0 and 1 or 0

    self.fruinfo_manage[fru_id] = {
        IsSupportDft = is_sup_dft,
        EepFormat = eeprom_format,
        FruOffset = fru_offset,
        SystemOffset = common.SYSTEM_OFFSET
    }

    frudata_intf.frudata_init(fru_id, fru_file, system_data, is_sup_dft, eeprom_format, is_sys_area)
    local elabel_info, elabel_multi, elabel_extend = self:elabel_read_from_eeprom()
    local ret = frudata_intf.elabel_init(fru_id, elabel_info, elabel_multi, elabel_extend)
    if ret == 2 then -- 需要同步到备份域
        log:notice('fru(%d) need sync fru info to elabel', fru_id)
        local elabel_info_tmp, elabel_extend_tmp = frudata_intf.get_elabel_info(fru_id)
        self:frudev_write_elabel_eeprom(elabel_info_tmp, elabel_extend_tmp)
    end
end

-- 从备份域中读取电子标签信息
function frudata_object:elabel_read_from_eeprom()
    local fru_id = self.obj.FruId
    local ctx = context.get_context_or_default()
    local len1, len2, _ = frudata_intf.get_elabel_eep_len()

    log:notice('read elabel eeprom data begin, obj.FruId = %d', fru_id)
    local elabel_info = self.obj.FruDev:Read(ctx, common.ELABEL_INFO_BLOCK_OFFSET, len1)
    local elabel_multi = self.obj.FruDev:Read(ctx, common.ELABEL_MULTI_AREA_OFFSET, MAX_MULTI_LEN)
    local elabel_extend = self.obj.FruDev:Read(ctx, common.ELABEL_EXTEND_INFO_BLOCK_OFFSET, len2)
    log:notice('read elabel eeprom data end, obj.FruId = %d', fru_id)

    return elabel_info, elabel_multi, elabel_extend
end

-- 同步电子标签信息到备份域
function frudata_object:frudev_write_elabel_eeprom(elabel_info, elabel_extend)
    local fru_id = self.obj.FruId
    local ctx = context.get_context_or_default()

    local ok, ret = pcall(function(...)
        log:notice('write fru area to eep start: fru_id = %d', fru_id)
        self.obj.EepromWp = common.EEPROM_WRITE_PROTECT.CLOSE
        self.obj.FruDev:Write(ctx, common.ELABEL_INFO_BLOCK_OFFSET, elabel_info)
        self.obj.FruDev:Write(ctx, common.ELABEL_EXTEND_INFO_BLOCK_OFFSET, elabel_extend)
        log:notice('write fru area to eep end: fru_id = %d', fru_id)
        self.obj.EepromWp = common.EEPROM_WRITE_PROTECT.OPEN
    end)

    if not ok then
        log:error('write fru(%d) elabel info eep failed, ret: %s', fru_id, ret)
    end
end

function frudata_object:write_system_area_to_eep(fru_id)
    manage:write_system_area_to_eep(fru_id, self.obj, self.fruinfo_manage)
end

function frudata_object:write_fru_area(fru_id, data)
    -- eepromv2数据进行重新读取，区别于MCU
    data = frudata_intf.get_fru_area(fru_id)
    self:write_elable_to_eep(fru_id)

    manage:write_fru_area_to_eep(fru_id, data, self.obj, self.fruinfo_manage)
end

function frudata_object:write_elable_to_eep(fru_id)
    local elabel_info, elabel_extend = frudata_intf.get_elabel_info(fru_id)
    cs(function()
        log:notice('write fru area to eep start: fru_id = %d', fru_id)
        self.obj.EepromWp = common.EEPROM_WRITE_PROTECT.CLOSE
        self.obj.FruDev:Write(context.new(), common.ELABEL_INFO_BLOCK_OFFSET, elabel_info)
        self.obj.FruDev:Write(context.new(), common.ELABEL_EXTEND_INFO_BLOCK_OFFSET, elabel_extend)
        log:notice('write fru area to eep end: fru_id = %d', fru_id)
        self.obj.EepromWp = common.EEPROM_WRITE_PROTECT.OPEN
    end)
end

function frudata_object:update_sys_data_to_dbus(fru_id)
    manage:update_sys_data_to_dbus(fru_id, self.obj)
end

function frudata_object:update_fru_data_to_dbus(fru_id)
    manage:update_fru_data_to_dbus(fru_id, self.obj)
end

return frudata_object
