-- 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 skynet = require 'skynet'
local log = require 'mc.logging'
local file_sec = require 'utils.file'
local utils = require 'mc.utils'
local class_mgnt = require 'mc.class_mgnt'

local DUMP_SLEEP_TIME = 30

local dump = {}

local function custominfo_split(input)
    return string.gsub(input, ";", "\n                         ")
end

local function print_fru_chassis_info(frudata_obj)
    local print_buf = ''
    if frudata_obj['ChassisType'] ~= '' then
        print_buf = string.format("%s Chassis Type          : %s\n", print_buf, frudata_obj['ChassisType'])
    end
    if frudata_obj['ChassisPartNumber'] ~= '' then
        print_buf = string.format("%s Chassis Part Number   : %s\n", print_buf, frudata_obj['ChassisPartNumber'])
    end
    if frudata_obj['ChassisSerialNumber'] ~= '' then
        print_buf = string.format("%s Chassis Serial Number : %s\n", print_buf, frudata_obj['ChassisSerialNumber'])
    end
    if frudata_obj['ChassisCustomInfo'] ~= '' then
        local print_str = custominfo_split(frudata_obj['ChassisCustomInfo'])
        print_buf = string.format("%s Chassis Extend label  : %s\n", print_buf, print_str)
    end
    return print_buf
end

local function print_fru_board_info(frudata_obj)
    local print_buf = ''
    if frudata_obj['MfgDate'] ~= '' then
        print_buf = string.format("%s Board Mfg. Date       : %s\n", print_buf, frudata_obj['MfgDate'])
    end
    if frudata_obj['BoardManufacturer'] ~= '' then
        print_buf = string.format("%s Board Manufacturer    : %s\n", print_buf, frudata_obj['BoardManufacturer'])
    end
    if frudata_obj['BoardProductName'] ~= '' then
        print_buf = string.format("%s Board Product Name    : %s\n", print_buf, frudata_obj['BoardProductName'])
    end
    if frudata_obj['BoardSerialNumber'] ~= '' then
        print_buf = string.format("%s Board Serial Number   : %s\n", print_buf, frudata_obj['BoardSerialNumber'])
    end
    if frudata_obj['BoardPartNumber'] ~= '' then
        print_buf = string.format("%s Board Part Number     : %s\n", print_buf, frudata_obj['BoardPartNumber'])
    end
    if frudata_obj['BoardFRUFileID'] ~= '' then
        print_buf = string.format("%s Board FRU File ID     : %s\n", print_buf, frudata_obj['BoardFRUFileID'])
    end
    if frudata_obj['BoardCustomInfo'] ~= '' then
        local print_str = custominfo_split(frudata_obj['BoardCustomInfo'])
        print_buf = string.format("%s Extend label          : %s\n", print_buf, print_str)
    end
    return print_buf
end

local function print_fru_product_info(frudata_obj)
    local print_buf = ''
    if frudata_obj['ManufacturerName'] ~= '' then
        print_buf = string.format("%s Product Manufacturer  : %s\n", print_buf, frudata_obj['ManufacturerName'])
    end
    if frudata_obj['ProductName'] ~= '' then
        print_buf = string.format("%s Product Name          : %s\n", print_buf, frudata_obj['ProductName'])
    end
    if frudata_obj['ProductPartNumber'] ~= '' then
        print_buf = string.format("%s Product Part Number   : %s\n", print_buf, frudata_obj['ProductPartNumber'])
    end
    if frudata_obj['ProductVersion'] ~= '' then
        print_buf = string.format("%s Product Version       : %s\n", print_buf, frudata_obj['ProductVersion'])
    end
    if frudata_obj['ProductSerialNumber'] ~= '' then
        print_buf = string.format("%s Product Serial Number : %s\n", print_buf, frudata_obj['ProductSerialNumber'])
    end
    if frudata_obj['AssetTag'] ~= '' then
        print_buf = string.format("%s Product Asset Tag     : %s\n", print_buf, frudata_obj['AssetTag'])
    end
    if frudata_obj['ProductFRUFileID'] ~= '' then
        print_buf = string.format("%s Product FRU File ID   : %s\n", print_buf, frudata_obj['ProductFRUFileID'])
    end
    if frudata_obj['ProductCustomInfo'] ~= '' then
        local print_str = custominfo_split(frudata_obj['ProductCustomInfo'])
        print_buf = string.format("%s Product Extend label  : %s\n", print_buf, print_str)
    end
    return print_buf
end

local function print_fru_system_info(frudata_obj)
    local print_buf = ''
    if frudata_obj['SystemManufacturer'] ~= '' then
        print_buf = string.format("%s System Manufacturer   : %s\n", print_buf, frudata_obj['SystemManufacturer'])
    end
    if frudata_obj['SystemProductName'] ~= '' then
        print_buf = string.format("%s System Product Name   : %s\n", print_buf, frudata_obj['SystemProductName'])
    end
    if frudata_obj['SystemSerialNumber'] ~= '' then
        print_buf = string.format("%s System Serial Number  : %s\n", print_buf, frudata_obj['SystemSerialNumber'])
    end
    if frudata_obj['SystemVersion'] ~= '' then
        print_buf = string.format("%s System Version        : %s\n", print_buf, frudata_obj['SystemVersion'])
    end
    return print_buf
end

local function print_fru_info(obj)
    local fru_name = obj['FruName']
    local fru_id = obj['FruId']
    local frudata_name = obj['FruDataId']

    -- 通过对象名获取对象
    local frudata_obj = class_mgnt('FruData')[frudata_name]

    if not frudata_obj then
        log:error('get_ref_frudata_obj error')
        return nil
    end

    local print_buf = {
        [1] = string.format("FRU Device Description : Builtin FRU Device (FRUID %u, %s)\n", fru_id, fru_name) }

    print_buf[#print_buf + 1] = print_fru_chassis_info(frudata_obj)
    print_buf[#print_buf + 1] = print_fru_board_info(frudata_obj)
    print_buf[#print_buf + 1] = print_fru_product_info(frudata_obj)
    if fru_id == 0 then
        print_buf[#print_buf + 1] = print_fru_system_info(frudata_obj)
    end
    return table.concat(print_buf)
end

local function dump_fru_info_all(file_name)
    local fp = file_sec.open_s(file_name, "a+")
    if not fp then
        log:error('open fruinfo failed')
        return false
    end
    return utils.safe_close_file(fp, function()
        utils.chmod(file_name, utils.S_IRUSR | utils.S_IWUSR | utils.S_IRGRP)

        local objs = class_mgnt('Fru'):get_all()

        if not next(objs) then
            fp:write("System has no fru information.\n")
            return true
        end
        local ret = true
        local buf
        for _, obj in pairs(objs) do
            buf = print_fru_info(obj)
            if not buf then
                buf = string.format("Get fru%d information failed.\n", obj['FruId'])
                ret = false
            end
            fp:write(buf)
            skynet.sleep(DUMP_SLEEP_TIME) -- 优化dump阶段CPU占用率，fru的信息收集过程间隔做协程切换
        end
        return ret
    end)
end

-- 日志收集接口
function dump.log_dump_cb(ctx, path)
    if not path or file_sec.check_shell_special_character_s(path) ~= 0 then
        log:error('path is wrong')
        return false
    end
    local file_name = path .. '/fruinfo.txt'

    if not dump_fru_info_all(file_name) then
        log:error('dump_get_fruinfo failed')
        return false
    end
    log:debug('dump_get_fruinfo finished')
    return true
end

return dump
