-- 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 class = require 'mc.class'
local singleton = require 'mc.singleton'
local log = require 'mc.logging'
local handles = require 'bma.handles'
local c_bma_mdb_mgmt = require 'bma.bma_mdb_mgmt'
local signal = require 'mc.signal'

local c_bma = class()

function c_bma:ctor(bus)
    self.handles = {}
    self.bus = bus
    self.on_need_resource = signal.new()

    self.bma_mdb_mgmt = c_bma_mdb_mgmt.new(self)
end

function c_bma:init()
    self.bma_mdb_mgmt.on_add:on(function(path, obj)
        self:add(path, obj)
    end)
    self.bma_mdb_mgmt.on_update:on(function(path, obj)
        self:update(path, obj)
    end)
    self.bma_mdb_mgmt.on_delete:on(function(path)
        self:delete(path)
    end)
    self.bma_mdb_mgmt.on_reset:on(function()
        self:on_reset()
    end)
    for _, h in ipairs(handles) do
        local handle = h.new()
        self.handles[#self.handles + 1] = handle
        handle.on_need_update:on(function(_, path)
            self.on_need_resource:emit(path)
        end)
    end
end

function c_bma:add(path, resource)
    self:process('add', path, resource)
end

function c_bma:update(path, resource)
    self:process('update', path, resource)
end

function c_bma:delete(path)
    self:process('delete', path, {})
end

function c_bma:on_reset()
    for _, handle in ipairs(self.handles) do
        local process_ok, err = pcall(handle.reset, handle)
        if not process_ok then
            log:error('c_bma: process failed, %s', err)
        end
    end
    log:info('bma data reset complete')
end

function c_bma:process(method, path, all_path_data)
    for _, handle in ipairs(self.handles) do
        local object = handle:match_object(path, all_path_data)
        if object then
            local process_ok, err = pcall(handle[method], handle, path, all_path_data, object)
            if not process_ok then
                log:error('c_bma: process failed, %s', err)
            end
        end
    end
end

local bma = singleton(c_bma)

local old_destroy = bma.destroy
function bma.destroy()
    old_destroy()
    for _, h in ipairs(handles) do
        h.destroy()
    end
end

return bma
