-- Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
--
-- this file licensed under the 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 singleton = require 'mc.singleton'
local class = require 'mc.class'
local log = require 'mc.logging'
local org_freedesktop_dbus = require 'sd_bus.org_freedesktop_dbus'
local match_rule = org_freedesktop_dbus.MatchRule
local interfaces_added = org_freedesktop_dbus.ObjMgrInterfacesAdded
local interfaces_removed = org_freedesktop_dbus.ObjMgrInterfacesRemoved

local fructl_data_keeping = require 'basic_cooling.data_keeping.fructl_data_keeping'
local disks_data_keeping = require 'basic_cooling.data_keeping.disks_data_keeping'
local cards_data_keeping = require 'basic_cooling.data_keeping.cards_data_keeping'
local hdd_backplane_data_keeping = require 'basic_cooling.data_keeping.hddbackplane_data_keeping'
local fans_data_keeping = require 'basic_cooling.data_keeping.fans_data_keeping'
local pump_data_keeping = require 'basic_cooling.data_keeping.pump_data_keeping'
local bmc_soc_data_keeping = require 'basic_cooling.data_keeping.bmc_soc_data_keeping'
local fan_group_data_keeping = require 'basic_cooling.data_keeping.fan_group_data_keeping'
local pump_group_data_keeping = require 'basic_cooling.data_keeping.pump_group_data_keeping'
local manufacture = require 'basic_cooling.data_keeping.manufacture'

local external_data_keeping = class()

function external_data_keeping:ctor(bus)
    self.bus = bus
    self.data_keeping_objs = {}
    self.objs = {}
end

function external_data_keeping:init()
    self.data_keeping_objs.fructl_data_keeping = fructl_data_keeping.new(self.bus)
    self.data_keeping_objs.disks_data_keeping = disks_data_keeping.new(self.bus)
    self.data_keeping_objs.cards_data = cards_data_keeping.new(self.bus)
    self.data_keeping_objs.hdd_backplane_data = hdd_backplane_data_keeping.new(self.bus)
    self.data_keeping_objs.fans_data = fans_data_keeping.new(self.bus)
    self.data_keeping_objs.pump_data_keeping = pump_data_keeping.new(self.bus)
    self.data_keeping_objs.bmc_soc_data_keeping = bmc_soc_data_keeping.new(self.bus)
    self.objs.fan_group_data_keeping = fan_group_data_keeping.new(self.bus)
    self.objs.pump_group_data_keeping = pump_group_data_keeping.new(self.bus)
    self.objs.manufacture = manufacture.new(self.bus)
    self.slot = self:register_listen_callback()
    skynet.fork_once(function()
        -- 初次获取资源树信息放在对象初始化后做，为了保证对象先注册到监听回调中，然后再从资源树获取信息
        for _, obj in pairs(self.data_keeping_objs) do
            if obj.get_all_infos then
                obj:get_all_infos()
            end
        end
        for _, obj in pairs(self.objs) do
            if obj.get_infos then
                obj:get_infos()
            end
        end
    end)
    self.data_keeping_objs.pump_data_keeping:get_pump_info()
    -- 10min 后整体再更新一次关键数据
    skynet.timeout(10 * 60 * 100, function()
        for _, obj in pairs(self.data_keeping_objs) do
            if obj.update_all_datas then
                obj:update_all_datas()
            end
        end
    end)
end

-- 执行对象添加回调
function external_data_keeping:register_interface_added_callback(sender, path, interfaces_and_properties)
    local ok, err_info
    for _, obj in pairs(self.data_keeping_objs) do
        if obj.interface_added_callback then
            ok, err_info = pcall(obj.interface_added_callback, obj, sender, path, interfaces_and_properties)
            if not ok then
                log:error("[DataKeeping] Add object(path: %s) failed, err_info: %s", path, err_info)
            end
        end
    end
end

-- 执行对象移除回调
function external_data_keeping:register_interface_removed_callback(sender, path, interfaces)
    local ok, err_info
    for _, obj in pairs(self.data_keeping_objs) do
        if obj.interface_removed_callback then
            ok, err_info = pcall(obj.interface_removed_callback, obj, sender, path, interfaces)
            if not ok then
                log:error("[DataKeeping] Remove object(path: %s) failed, err_info: %s", path, err_info)
            end
        end
    end
end

-- 注册对象添加和删除的回调
function external_data_keeping:register_listen_callback()
    local interfaces_added_sig = match_rule.signal(interfaces_added.name, interfaces_added.interface)
    local interfaces_removed_sig = match_rule.signal(interfaces_removed.name, interfaces_removed.interface)

    return {
        self.bus:match(interfaces_added_sig, function(msg)
            self:register_interface_added_callback(msg:sender(), msg:read('oa{sa{sv}}'))
        end),
        self.bus:match(interfaces_removed_sig, function(msg)
            self:register_interface_removed_callback(msg:sender(), msg:read('oas'))
        end)
    }
end

return singleton(external_data_keeping)
