-- 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: upgrade.cfg解析
local log = require 'mc.logging'
local ini_parse = require 'mc.v2_persistence'
local defs = require 'unit_manager.class.logic_fw.comm_defs'

-- 保证此数是UPGRADE_GROUP_MEM_CNT的整数倍，否则数组操作会越界--BTD
local UPGRADE_MAX_COMPNENT_NUM = 32
local COMPONET_ID_INVALID <const> = 0xff
local COMPONET_IDEX_INVALID <const> = 0xffffffff

local cfg = {}
cfg.__index = cfg

function cfg.new(obj, group_name)
    local cold_list = {}
    local idx
    local chip_num = tonumber(obj.CPLDChipNummbers) or 1
    for w in string.gmatch(obj.ColdValidList or "", "%d+") do
        idx = tonumber(w)
        if idx > 0 and idx <= chip_num then
            table.insert(cold_list, idx)
        end
    end
    local hot_list = {}
    for w in string.gmatch(obj.HotValidList or "", "%d+") do
        idx = tonumber(w)
        if idx > 0 and idx <= chip_num then
            table.insert(hot_list, idx)
        end
    end

    return setmetatable({
        name = group_name,
        -- 标识固件对应的组件类型，天池场景EXU为主板（0X05），其他组件均认为是背板(0X24)
        component_id = obj.ComponentID and tonumber(obj.ComponentID) or COMPONET_ID_INVALID,
        idex = obj.ComponentIDEx and tonumber(obj.ComponentIDEx) or COMPONET_IDEX_INVALID, -- 标识天池组件类型，非标字段可能为空
        board_id = tonumber(obj.BoardID),
        uid = obj.Uid, -- 该固件包支持的天池UId列表，最多10个
        -- CPLD芯片多厂商模式还是单厂商模式，非标字段可能为空
        supplier_mode = tonumber(obj.MultipleSuppliersMode) or defs.CPLD_SUPPLIER_MODE.SINGLE,
        chip_num = chip_num, -- CPLD的的芯片数目，非标字段可能为空
        cold_valid_list = cold_list, -- 冷升级CPLD芯片列表
        hot_valid_list = hot_list, -- 无感升级CPLD芯片列表
        update_link = obj.UpdateLink,
        file_type = obj.UpdateFileType or 'vme' -- 默认vme格式
    }, cfg)
end

function cfg:check_fw_uid_exist(fw)
    -- 用逗号隔开该升级包中支持的所有组件uid，用%w识别所有字母和数字
    for uid in string.gmatch(self.uid, "%w+") do
        -- 匹配组件uid
        if fw.uid ~= uid then
            goto continue
        end

        -- 未配置ComponentID和ComponentIDEx时直接返回ture，否则与配置中的信息匹配
        if (fw.component_id == COMPONET_ID_INVALID and fw.component_id_ex == COMPONET_IDEX_INVALID) or
            (fw.component_id == self.component_id and fw.component_id_ex == self.idex) then
            log:notice("check fw uid(%s) id(%s) id_ex(%s) exist success",
                fw.uid, fw.component_id, fw.component_id_ex)
            return true
        end
        ::continue::
    end
    return false
end

-- prepare阶段框架会下发解包的update.cfg路径，解析文件内容，获取每个Firmware的配置
function cfg:get_cfg_list(path)
    if not path then
        log:error("get nil cfg path")
        return {}
    end
    log:info("get cfg path[%s]", path)
    local data = ini_parse.load_file(path)
    if (not data.Basic) or (not data.Basic.Version) then
        log:error('Get Basic Version failed')
        return {}
    end
    local update_file_num = tonumber(data.Firmware.FileNum)
    if update_file_num == 0 or update_file_num > UPGRADE_MAX_COMPNENT_NUM then
        log:error('Update file num is invalid')
        return {}
    end
    local cfg_list = {}
    local group_name = nil
    for i = 2, update_file_num do -- 第1个Firmware指的就是配置文件，所以从2开始
        group_name = string.format("Firmware%d", (i - 1))
        log:info("get %s", group_name)
        table.insert(cfg_list, cfg.new(data[group_name], group_name))
    end
    return cfg_list
end

return cfg
