-- 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 c_object = require 'mc.orm.object'
local log = require 'mc.logging'
local c_network_port = require 'device.class.network_port'
local c_bridge_port = require 'device.class.network_bridge_port'
local c_object_manage = require 'mc.orm.object_manage'

local c_network_bridge = c_object('NetworkBridge')

function c_network_bridge:ctor()
end

function c_network_bridge:init()
    self:next_tick(self.create_network_bridge_port, self)
    self.super.init(self)
end

function c_network_bridge:create_network_bridge_port()
    local port_obj
    for id, port in ipairs(self.Ports) do
        log:debug("network bridge port name %s", port)
        port_obj = c_network_port.collection:find({Name = port})
        if port_obj then
            c_bridge_port.insert_or_update({
                BridgeId = self.Id,
                Id = id,
                NodeId = port_obj.NodeId,
                Name = port
            })
        end
    end
end

function c_network_bridge:update_network_bridge_port(ports)
    local port_obj
    for id, port in ipairs(ports) do
        port_obj = c_network_port.collection:find({Name = port})
        if port_obj and port_obj.WorkloadType ~= 1 then
            c_bridge_port.insert_or_update({
                BridgeId = self.Id,
                Id = id,
                NodeId = port_obj.NodeId,
                Name = port
            })
        end
    end

    local exist_ports = c_bridge_port.get_bridge_port(self.Id)
    for id, port  in ipairs(exist_ports) do
        if not ports[id] then
            port:dtor()
        end
    end
    self.Ports = ports
end

function c_network_bridge.update_by_physical_port_name(name, node_id)
    local br_port_obj = c_bridge_port.collection:find({Name = name})
    if br_port_obj then
        return
    end
    local port_id = nil
    local br_obj = c_network_bridge.collection:find(function (obj)
        for id, port_name in ipairs(obj.Ports) do
            if port_name == name then
                port_id = id
                return true
            end
        end
        return false
    end)

    if not br_obj or not port_id then
        return
    end

    c_bridge_port.insert_or_update({
        BridgeId = br_obj.Id,
        Id = port_id,
        NodeId = node_id,
        Name = name
    })
end

function c_network_bridge.update_ports(value)
    local obj = c_network_bridge.collection:find({Id = value.Id})
    if not obj then
        log:error("Update network bridge port(%s) failed.", value.Id)
        return
    end

    obj:update_network_bridge_port(value.Ports)
end

function c_network_bridge.create_mdb_object(value)
    local app = c_object_manage.get_instance().app
    return app:CreateNetworkBridge(1, value.Id, function (obj)
        log:debug("create network bridge id(%s), name(%s)", value.Id, value.Name)
        obj.Id = value.Id
        obj.Name = value.Name
        obj.Ports = value.Ports
    end)
end

function c_network_bridge.insert_or_update(value)
    local obj = c_network_bridge.collection:find({Id = value.Id, Name = value.Name})
    if obj then
        obj.Id = value.Id
        obj.Name = value.Name
        obj.Ports = value.Ports
    end
    return obj or c_network_bridge.__table(value)
end

function c_network_bridge:destroy()
    local ports = c_bridge_port.get_bridge_port(self.Id)
    for _, port in ipairs(ports) do
        port:dtor()
    end
    self:dtor()
end
return c_network_bridge
