-- 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 ipmi = require 'ipmi'
local mdb = require 'mc.mdb'
local skynet = require 'skynet'
local class = require 'mc.class'
local open_db = require 'pcie_device.db'
local app_base = require 'mc.service_app_base'
local open_local_db = require 'pcie_device.local_db'
local object_manage = require 'mc.mdb.object_manage'
local persist_client = require 'persistence.persist_client_lib'
local orm_classes = require 'pcie_device.orm_classes'
local ok, datas = pcall(require, 'pcie_device.datas')
if not ok then
    datas = nil -- 如果没有datas配置，证明当前组件不需要datas，仅打开数据库
end

local PCIeDevicesTypes = require 'pcie_device.json_types.PCIeDevices'
local PropertiesTypes = require 'pcie_device.json_types.Properties'
local PCIeDeviceTypes = require 'pcie_device.json_types.PCIeDevice'
local RASTypes = require 'pcie_device.json_types.RAS'
local PCIeCardTypes = require 'pcie_device.json_types.PCIeCard'
local UnitTypes = require 'pcie_device.json_types.Unit'
local PcieAddrInfoTypes = require 'pcie_device.json_types.PcieAddrInfo'
local UnitConfigErrorTypes = require 'pcie_device.json_types.UnitConfigError'

local PCIeDevices = mdb.register_object('/bmc/kepler/Systems/:SystemId/PCIeDevices', {
    {name = 'bmc.kepler.Systems.PCIeDevices', interface = PCIeDevicesTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function PCIeDevices:ctor(SystemId)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices'
end

local PCIeDevice = mdb.register_object('/bmc/kepler/Systems/:SystemId/PCIeDevices/:Id', {
    {name = 'bmc.kepler.Systems.PCIeDevices.PCIeDevice', interface = PCIeDeviceTypes.interface},
    {name = 'bmc.kepler.Systems.PCIeDevices.PCIeDevice.RAS', interface = RASTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function PCIeDevice:ctor(SystemId, Id)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/' .. Id
end

local PCIeCard = mdb.register_object('/bmc/kepler/Systems/:SystemId/PCIeDevices/PCIeCards/:Id', {
    {name = 'bmc.kepler.Systems.PCIeDevices.PCIeCard', interface = PCIeCardTypes.interface},
    {name = 'bmc.kepler.Systems.Board.Unit', interface = UnitTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function PCIeCard:ctor(SystemId, Id)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/PCIeCards/' .. Id
end

local OCPCard = mdb.register_object('/bmc/kepler/Systems/:SystemId/PCIeDevices/OCPCards/:Id', {
    {name = 'bmc.kepler.Systems.PCIeDevices.PCIeCard', interface = PCIeCardTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function OCPCard:ctor(SystemId, Id)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/OCPCards/' .. Id
end

local PcieAddrInfo = mdb.register_object('/bmc/kepler/Systems/:SystemId/PCIeDevices/PcieAddrInfo/:ID', {
    {name = 'bmc.kepler.Systems.PcieAddrInfo', interface = PcieAddrInfoTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function PcieAddrInfo:ctor(SystemId, ID)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/PcieAddrInfo/' .. ID
end

local BusinessConnector = mdb.register_object('/bmc/kepler/Systems/:SystemId/BusinessConnector/:Id', {
    {name = 'bmc.kepler.Systems.UnitConfigError', interface = UnitConfigErrorTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function BusinessConnector:ctor(SystemId, Id)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/BusinessConnector/' .. Id
end

local UnitConfiguration = mdb.register_object('/bmc/kepler/Systems/:SystemId/UnitConfiguration/:Id', {
    {name = 'bmc.kepler.Systems.UnitConfigError', interface = UnitConfigErrorTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function UnitConfiguration:ctor(SystemId, Id)
    self.path = '/bmc/kepler/Systems/' .. SystemId .. '/UnitConfiguration/' .. Id
end

local model = require 'class.model'

local pcie_device_service = class(app_base.Service)

pcie_device_service.package = 'pcie_device'

function pcie_device_service:CreatePCIeDevices(SystemId, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices'
    return object_manage.create_object('PCIeDevices', path, path, prop_setting_cb)
end

function pcie_device_service:CreatePCIeDevice(SystemId, Id, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/' .. Id
    return object_manage.create_object('PCIeDevice', path, path, prop_setting_cb)
end

function pcie_device_service:CreatePCIeCard(SystemId, Id, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/PCIeCards/' .. Id
    return object_manage.create_object('PCIeCard', path, path, prop_setting_cb)
end

function pcie_device_service:CreateOCPCard(SystemId, Id, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/OCPCards/' .. Id
    return object_manage.create_object('OCPCard', path, path, prop_setting_cb)
end

function pcie_device_service:CreatePcieAddrInfo(SystemId, ID, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/PCIeDevices/PcieAddrInfo/' .. ID
    return object_manage.create_object('PcieAddrInfo', path, path, prop_setting_cb)
end

function pcie_device_service:CreateBusinessConnector(SystemId, Id, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/BusinessConnector/' .. Id
    return object_manage.create_object('BusinessConnector', path, path, prop_setting_cb)
end

function pcie_device_service:CreateUnitConfiguration(SystemId, Id, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/UnitConfiguration/' .. Id
    return object_manage.create_object('UnitConfiguration', path, path, prop_setting_cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesSetPcieErrorStatus(cb)
    model.ImplPCIeDevicesPCIeDevicesSetPcieErrorStatus(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesSetBandwidthReduction(cb)
    model.ImplPCIeDevicesPCIeDevicesSetBandwidthReduction(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesSetUCEByBIOS(cb)
    model.ImplPCIeDevicesPCIeDevicesSetUCEByBIOS(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesSetDiagnosticFault(cb)
    model.ImplPCIeDevicesPCIeDevicesSetDiagnosticFault(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesSetPredictiveFault(cb)
    model.ImplPCIeDevicesPCIeDevicesSetPredictiveFault(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesGetDeviceName(cb)
    model.ImplPCIeDevicesPCIeDevicesGetDeviceName(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesGetPCIeCardNum(cb)
    model.ImplPCIeDevicesPCIeDevicesGetPCIeCardNum(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesSetFaultByBios(cb)
    model.ImplPCIeDevicesPCIeDevicesSetFaultByBios(cb)
end

function pcie_device_service:ImplPCIeDevicesPCIeDevicesSetLinkSpeedReduced(cb)
    model.ImplPCIeDevicesPCIeDevicesSetLinkSpeedReduced(cb)
end

function pcie_device_service:get_bus()
    return self.bus
end

function pcie_device_service:register_ipmi_cmd(ipmi_cmd, cb)
    self.ipmi_cmds[ipmi_cmd.name] = ipmi.register_ipmi_cmd(self.bus, self.service_name, ipmi_cmd,
        cb or self[ipmi_cmd.name])
end

function pcie_device_service:unregister_ipmi_cmd(ipmi_cmd)
    local cmd_obj = self.ipmi_cmds[ipmi_cmd.name]
    if not cmd_obj then
        return
    end

    cmd_obj:unregister()
    self.ipmi_cmds[ipmi_cmd.name] = nil
end

function pcie_device_service:ctor()
    self.ipmi_cmds = {}
    self.signal_slots = {}
    self.name = self.name or pcie_device_service.package
    self.db = open_db(':memory:', datas)
    if skynet.getenv('TEST_DATA_DIR') then
        self.reset_local_db = open_local_db(skynet.getenv('TEST_DATA_DIR') .. '/pcie_device_reset.db', datas, 'reset')
    else
        self.reset_local_db = open_local_db('/opt/bmc/pram/persistence.local/pcie_device.db', datas, 'reset')
    end

    orm_classes.init(self.db)
    self.bus:request_name(app_base.Service.get_service_name(self.name))
    model.init(self.bus)
    pcie_device_service.bus = self.bus
end

function pcie_device_service:pre_init()
    pcie_device_service.super.pre_init(self)
    self.persist = persist_client.new(self.bus, self.db, self, {
        ['t_pcie_dev_info'] = true,
        ['t_pcie_addr_info'] = true,
        ['t_bdf_config'] = true
    })
    object_manage.set_persist_client(self.persist)
end

function pcie_device_service:init()
    pcie_device_service.super.init(self)
end

return pcie_device_service
