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

local ThresholdSensorTypes = require 'sensor.json_types.ThresholdSensor'
local ThresholdSensorDisplayTypes = require 'sensor.json_types.ThresholdSensorDisplay'
local PropertiesTypes = require 'mdb.bmc.kepler.Object.PropertiesInterface'
local SensorsTypes = require 'sensor.json_types.Sensors'
local DiscreteSensorTypes = require 'sensor.json_types.DiscreteSensor'
local DiscreteSensorDisplayTypes = require 'sensor.json_types.DiscreteSensorDisplay'
local EntityTypes = require 'sensor.json_types.Entity'
local DiscreteEventTypes = require 'sensor.json_types.DiscreteEvent'
local SensorSelInfoTypes = require 'sensor.json_types.SensorSelInfo'
local IPMIEventTypes = require 'sensor.json_types.IPMIEvent'

local ThresholdSensor = mdb.register_object('/bmc/kepler/Systems/:SystemId/ThresholdSensors/:ID', {
    {name = 'bmc.kepler.Systems.ThresholdSensor', interface = ThresholdSensorTypes.interface},
    {name = 'bmc.kepler.Systems.ThresholdSensorDisplay', interface = ThresholdSensorDisplayTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

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

local Sensors = mdb.register_object('/bmc/kepler/Chassis/:ChassisId/Sensors', {
    {name = 'bmc.kepler.Chassis.Sensors', interface = SensorsTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function Sensors:ctor(ChassisId)
    self.path = '/bmc/kepler/Chassis/' .. ChassisId .. '/Sensors'
end

local DiscreteSensor = mdb.register_object('/bmc/kepler/Systems/:SystemId/DiscreteSensors/:ID', {
    {name = 'bmc.kepler.Systems.DiscreteSensor', interface = DiscreteSensorTypes.interface},
    {name = 'bmc.kepler.Systems.DiscreteSensorDisplay', interface = DiscreteSensorDisplayTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

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

local Entity = mdb.register_object('/bmc/kepler/Systems/:SystemId/Entities/:ID', {
    {name = 'bmc.kepler.Systems.Entity', interface = EntityTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

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

local DiscreteEvent = mdb.register_object('/bmc/kepler/Systems/:SystemId/DiscreteEvents/:Id', {
    {name = 'bmc.kepler.Systems.DiscreteEvent', interface = DiscreteEventTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

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

local SensorSelInfo = mdb.register_object('/bmc/kepler/Chassis/:ChassisId/SensorSelInfo', {
    {name = 'bmc.kepler.Chassis.SensorSelInfo', interface = SensorSelInfoTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

function SensorSelInfo:ctor(ChassisId)
    self.path = '/bmc/kepler/Chassis/' .. ChassisId .. '/SensorSelInfo'
end

local BootError = mdb.register_object('/bmc/kepler/Systems/:SystemId/EventEntries/BootError', {
    {name = 'bmc.kepler.Systems.IPMIEvent', interface = IPMIEventTypes.interface},
    {name = 'bmc.kepler.Object.Properties', interface = PropertiesTypes.interface}
})

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

local model = require 'class.model'

local sensor_service = class(app_base.Service)

sensor_service.package = 'sensor'

function sensor_service:CreateThresholdSensor(SystemId, ID, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/ThresholdSensors/' .. ID
    return object_manage.create_object('ThresholdSensor', path, path, prop_setting_cb)
end

function sensor_service:CreateSensors(ChassisId, prop_setting_cb)
    local path = '/bmc/kepler/Chassis/' .. ChassisId .. '/Sensors'
    return object_manage.create_object('Sensors', path, path, prop_setting_cb)
end

function sensor_service:CreateDiscreteSensor(SystemId, ID, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/DiscreteSensors/' .. ID
    return object_manage.create_object('DiscreteSensor', path, path, prop_setting_cb)
end

function sensor_service:CreateEntity(SystemId, ID, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/Entities/' .. ID
    return object_manage.create_object('Entity', path, path, prop_setting_cb)
end

function sensor_service:CreateDiscreteEvent(SystemId, Id, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/DiscreteEvents/' .. Id
    return object_manage.create_object('DiscreteEvent', path, path, prop_setting_cb)
end

function sensor_service:CreateSensorSelInfo(ChassisId, prop_setting_cb)
    local path = '/bmc/kepler/Chassis/' .. ChassisId .. '/SensorSelInfo'
    return object_manage.create_object('SensorSelInfo', path, path, prop_setting_cb)
end

function sensor_service:CreateBootError(SystemId, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemId .. '/EventEntries/BootError'
    return object_manage.create_object('BootError', path, path, prop_setting_cb)
end

function sensor_service:ImplSensorsSensorsGetThresholdSensorList(cb)
    model.ImplSensorsSensorsGetThresholdSensorList(cb)
end

function sensor_service:ImplSensorsSensorsMockSensor(cb)
    model.ImplSensorsSensorsMockSensor(cb)
end

function sensor_service:ImplSensorsSensorsGetSensorList(cb)
    model.ImplSensorsSensorsGetSensorList(cb)
end

function sensor_service:ImplSensorsSensorsSetSensorStatus(cb)
    model.ImplSensorsSensorsSetSensorStatus(cb)
end

function sensor_service:ImplSensorsSensorsExportSel(cb)
    model.ImplSensorsSensorsExportSel(cb)
end

function sensor_service:ImplSensorsSensorsGetSel(cb)
    model.ImplSensorsSensorsGetSel(cb)
end

function sensor_service:ImplSensorsSensorsGetDiscreteSensorList(cb)
    model.ImplSensorsSensorsGetDiscreteSensorList(cb)
end

function sensor_service:ImplSensorsSensorsGetReportedSel(cb)
    model.ImplSensorsSensorsGetReportedSel(cb)
end

function sensor_service:ImplSensorsSensorsDumpSDR(cb)
    model.ImplSensorsSensorsDumpSDR(cb)
end

function sensor_service:ImplSensorsSensorsAddOemSel(cb)
    model.ImplSensorsSensorsAddOemSel(cb)
end

function sensor_service:ImplSensorsSensorsClearSel(cb)
    model.ImplSensorsSensorsClearSel(cb)
end

function sensor_service:ImplSensorsSensorsSetThresholds(cb)
    model.ImplSensorsSensorsSetThresholds(cb)
end

function sensor_service:get_bus()
    return self.bus
end

function sensor_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 sensor_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 sensor_service:ctor()
    self.ipmi_cmds = {}
    self.signal_slots = {}
    self.name = self.name or sensor_service.package
    self.db = open_db(':memory:', datas)
    self.local_db = open_local_db(app_base.Service:get_local_db_path(self.name) .. '/sensor.db', datas, 'poweroff')
    if skynet.getenv('TEST_DATA_DIR') then
        self.reset_local_db = open_local_db(skynet.getenv('TEST_DATA_DIR') .. '/sensor_reset.db', datas, 'reset')
    else
        self.reset_local_db = open_local_db('/opt/bmc/pram/persistence.local/sensor.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)
    sensor_service.bus = self.bus
end

function sensor_service:pre_init()
    sensor_service.super.pre_init(self)
    self.persist = persist_client.new(self.bus, self.db, self, {
        ['t_sel_info'] = true,
        ['t_boot_error'] = true,
        ['t_pef_config'] = true,
        ['t_pef_control'] = true
    })
    object_manage.set_persist_client(self.persist)
end

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

return sensor_service
