-- 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 singleton = require 'mc.singleton'
local class = require 'mc.class'
local common_def = require 'common_def'
local initiator = require 'mc.initiator'
local context = require 'mc.context'

local method_misc = class()

local NOT_SUPPORT_OOB_CTRL_LIST = {
    [10] = true,
    [19] = true,
    [20] = true
}

function method_misc:remove_ele_by_position(list, position)
    -- 使用反向遍历避免删除元素时索引变化导致的问题
    for i = #list, 1, -1 do
        if list[i] and list[i].position == position then
            table.remove(list, i)
            break
        end
    end
end

-- 如果val不合法返回默认值
function method_misc:update_if_valid(invalid, val, default)
    if val and val ~= invalid then
        return val
    end
    return default
end

-- 根据RAID卡TypeId判断是否支持OOBSUPPORT
function method_misc:test_controller_oob_support(type_id)
    if not NOT_SUPPORT_OOB_CTRL_LIST[type_id] then
        return true
    end
    return false
end

-- 检查RAID卡的厂商类型
local function test_controller_vendor(type_id, vendor_id)
    if vendor_id == common_def.VENDER_LSI then
        if type_id < common_def.PMC_3152_8I_SMART_RAID then
            return true
        end
    elseif vendor_id == common_def.VENDER_PMC then
        if type_id == common_def.PMC_3152_8I_SMART_RAID or type_id == common_def.PMC_2100_8I_SMART_HBA then
            return true
        end
    elseif vendor_id == common_def.VENDER_HUAWEI then
        if type_id >= common_def.HI1880_SP186_M_16i and type_id <= common_def.HI1880_SP186_M_8i then
            return true
        end
    end
    return false
end

-- 根据RAID卡类型判断缓存策略是否正确
function method_misc:check_io_policy(io_policy, type_id)
    -- vendor_lsi 只有博通卡支持
    if test_controller_vendor(type_id, common_def.VENDER_LSI) then
        if io_policy > common_def.LD_CACHE_DIRECT_IO then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    elseif test_controller_vendor(type_id, common_def.VENDER_PMC) or
        test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
    end
    return common_def.SM_CODE_SUCCESS
end

-- 根据RAID卡类型判断厂商类型
function method_misc:test_controller_vendor(type_id, vendor_id)
    return test_controller_vendor(type_id, vendor_id)
end

-- 根据RAID卡类型判断启动类型是否正确
function method_misc:check_boot_priority_param(boot_priority, type_id)
    -- vendor_lsi
    if test_controller_vendor(type_id, common_def.VENDER_LSI) then
        if boot_priority ~= common_def.BOOT_PRIORITY_PRIMARY then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    -- vendor_pmc
    elseif test_controller_vendor(type_id, common_def.VENDER_PMC) then
        if boot_priority > common_def.BOOT_PRIORITY_ALL then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    -- vendor_huawei
    elseif test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
        if boot_priority > common_def.BOOT_PRIORITY_PRIMARY then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    end
    return common_def.SM_CODE_SUCCESS
end

-- 根据RAID卡类型判断读策略是否正确
function method_misc:check_read_policy(read_policy, type_id)
    -- vendor_lsi
    if test_controller_vendor(type_id, common_def.VENDER_LSI) then
        if read_policy > common_def.READ_POLICY_READ_AHEAD_ADAPTIVE then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    -- vendor_pmc
    elseif test_controller_vendor(type_id, common_def.VENDER_PMC) then
        return common_def.SM_CODE_PARA_DATA_ILLEGAL
    -- vendor_huawei
    elseif test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
        if read_policy > common_def.LD_CACHE_READ_AHEAD then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    end
    return common_def.SM_CODE_SUCCESS
end

-- 根据RAID卡类型判断BGI是否正确
function method_misc:check_BGI(BGI_enable, type_id)
    -- vendor_lsi 只有博通卡支持
    if test_controller_vendor(type_id, common_def.VENDER_LSI) then
        if BGI_enable > common_def.LD_CACHE_DIRECT_IO then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    elseif test_controller_vendor(type_id, common_def.VENDER_PMC) or
        test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
        return common_def.SM_CODE_PARA_DATA_ILLEGAL
    end
    return common_def.SM_CODE_SUCCESS
end

-- 根据RAID卡类型获取设置启动设备的操作日志描述
function method_misc:get_boot_priority_op_desc(boot_priority, type_id)
    -- vendor_lsi
    if test_controller_vendor(type_id, common_def.VENDER_LSI) then
        return common_def.AS_BOOT_DEVICE
    end
    -- vendor_pmc
    if test_controller_vendor(type_id, common_def.VENDER_PMC) then
        return 'boot priority to ' .. (common_def.PD_BOOT_PRIORITY[boot_priority] or common_def.INVALID_STRING)
    end
    -- vendor_huawei
    if test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
        return common_def.PD_BOOTABLE_DESC[boot_priority] or common_def.INVALID_STRING
    end
    return common_def.INVALID_STRING
end


-- 根据RAID卡类型判断访问策略是否正确
function method_misc:check_access_policy(access_policy, type_id)
    -- vendor_lsi 只有博通卡支持
    if test_controller_vendor(type_id, common_def.VENDER_LSI) then
        if access_policy > common_def.LD_ACCESS_BLOCKED then
            return common_def.SM_CODE_PARA_DATA_ILLEGAL
        end
    elseif test_controller_vendor(type_id, common_def.VENDER_PMC) or
        test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
        return common_def.SM_CODE_PARA_DATA_ILLEGAL
    end
    return common_def.SM_CODE_SUCCESS
end

-- 检查逻辑盘名称
function method_misc:check_volume_name(name, type_id)
    if self:check_ld_name_too_long(#name, type_id) then
        return common_def.SM_CODE_LD_NAME_EXCEED_MAX_LEN
    end
    if not self:check_string_is_valid_ascii(name) then
        return common_def.SM_CODE_LD_NAME_INVALID_ASCII
    end
    return common_def.SM_CODE_SUCCESS
end

function method_misc:get_ld_name_max_length(type_id)
    -- 博通卡逻辑盘最大长度15
    if test_controller_vendor(type_id, common_def.VENDER_LSI) then
       return 15
    -- PMC卡逻辑盘最大长度64
    elseif test_controller_vendor(type_id, common_def.VENDER_PMC) then
        return 64
    -- 自研卡逻辑盘最大长度20
    elseif test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
        return 20
    end
    return 0
end

function method_misc:check_ld_name_too_long(len, type_id)
    -- 博通卡逻辑盘最大长度15
    if test_controller_vendor(type_id, common_def.VENDER_LSI) and len > common_def.SL_LD_NAME_LENGTH then
       return true
    end
    -- PMC卡逻辑盘最大长度64
    if test_controller_vendor(type_id, common_def.VENDER_PMC) and len > common_def.SC_LD_NAME_LENGTH then
        return true
    end
    -- 自研卡逻辑盘最大长度20
    if test_controller_vendor(type_id, common_def.VENDER_HUAWEI) and len > common_def.HS_LD_NAME_LENGTH then
        return true
    end
    return false
end

function method_misc:check_string_is_valid_ascii(name)
    for i = 1, #name do
        local ch = name:byte(i, i)
        if ch > 0x7e or ch < 0x20 then
            return false
        end
    end
    return true
end

-- 根据RAID卡类型判断带外管理通道类型
function method_misc:get_oob_interface_type(type_id)
    if test_controller_vendor(type_id, common_def.VENDER_HUAWEI) or
        test_controller_vendor(type_id, common_def.VENDER_PMC) then
        return common_def.OOB_TYPE_OVER_PCIE
    elseif test_controller_vendor(type_id, common_def.VENDER_LSI) then
        return common_def.OOB_TYPE_OVER_I2C
    else
        return common_def.INVALID_U8
    end
end

function method_misc:get_op_initiator()
    local m_initiator = initiator.new('N/A', 'N/A', 'localhost')
    local ctx = context.get_context()
    return (ctx and ctx:has_initiator()) and ctx:get_initiator() or m_initiator
end

-- 根据 ManufacturerOUI 查找 ManufacturerName
function method_misc:get_manufacturer_name_by_oui(manufacturer_oui)
    for _, vendor in ipairs(common_def.DRIVE_VENDOR_TABLE) do
        local vendor_id = string.format("%X", vendor.vendor_id)
        if vendor_id == manufacturer_oui then
            return vendor.vendor_name
        end
    end
    return 'ATA'
end

return singleton(method_misc)