-- 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 file_utils = require 'utils.file'
local frudata_intf = require 'frudata_intf'
local common = require 'common'
local manage = require 'frudata_object.manage'
local utils = require 'mc.utils'
local vos = require 'utils.vos'

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

    fru_file, system_data = self:frudev_read_from_file()
    fru_offset = common.FRU_OFFSET

    -- EepromV2类型电子标签eeprom_format为0，其他类型默认使用TianChi规范类型为1
    local eeprom_format = 1
    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)
end

function frudata_object:frudev_read_from_file()
    local fruid = self.obj.FruId
    log:notice('read file data begin, obj.FruId = %d', fruid)
    local file_name = self.obj.StorageLoc
    if not file_name or #file_name == 0 or file_utils.check_shell_special_character_s(file_name) ~= 0 then
        log:error('filename is error, fruid = %d', fruid)
        return
    end

    -- 目录不存在则创建目录
    local index = string.find(string.reverse(file_name), '/')
    local dir = string.sub(file_name, 1, #file_name - index)
    local file_name_str = string.sub(file_name, #dir + 2, #file_name)
    if file_utils.check_real_path_s(dir) ~= 0 then
        log:notice('mkdir fruId(%d) data dir', fruid)
        os.execute_s('mkdir -p ' .. dir)
        utils.chmod(dir, utils.S_IRWXU) -- 目录权限设置为0700
    end
    if not vos.get_file_accessible(file_name) then
        -- 文件不存在则创建文件
        log:notice('touch %s, obj.FruId = %d', file_name_str, fruid)
        local fru_file = common.copy_str('\x00', common.FRU_FILE_LEN + common.FRU_OFFSET)
        local file = file_utils.open_s(file_name, 'w')
        if not file then
            log:error('write file(%s) failed, fruid = %d', file_name_str, fruid)
            return
        end
        file:write(fru_file)
        file:close()
        utils.chmod(file_name, utils.S_IRUSR | utils.S_IWUSR) -- 目录权限设置为0600
    end

    local file = file_utils.open_s(file_name, 'r')
    if not file then
        log:error('open file(%s) failed, fruid = %d', file_name_str, fruid)
        return
    end
    file:seek("set", common.FRU_OFFSET)
    local fru_file = file:read(common.FRU_FILE_LEN)
    if not fru_file then
        file:close()
        log:error('read file(%s) failed, fruid = %d', file_name_str, fruid)
        return '', ''
    end
    log:notice('read frudata(%d), file length = %d', fruid, #fru_file)
    file:close()
    -- system域为空
    return fru_file, ''
end

function frudata_object:write_system_area_to_eep(fru_id)
    log:error('StorageType is File, not have system area')
end

function frudata_object:write_fru_area_to_file(fru_id, data)
    log:notice('write_fru_area_to_file: fru_id = %d data_len = %d.', fru_id, #data)
    local file_name = self.obj.StorageLoc
    if file_name == nil or #file_name == 0 then
        local buf = string.format('filename is NULL, fruid = %d', fru_id)
        error(buf)
    end

    local file = file_utils.open_s(file_name, 'w+')
    if not file then
        local buf = string.format('open file(%s) failed, fruid = %d', file_name, fru_id)
        error(buf)
    end
    local file_header = file:read(common.FRU_OFFSET)
    local buf = file_header .. data
    file:write(buf)
    file:close()
end

function frudata_object:write_fru_area(fru_id, _)
    -- file数据进行重新读取，区别于MCU
    local data = frudata_intf.get_fru_area(fru_id)
    self:write_fru_area_to_file(fru_id, data)
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
