-- 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_mgnt = require 'mc.class_mgnt'
local c_object = require 'mc.orm.object'
local c_object_manage = require 'mc.orm.object_manage'
local c_vlan_ipv4_address = require 'device.class.vlan.ipv4_address'
local c_vlan_ipv6_address = require 'device.class.vlan.ipv6_address'

local c_vlan = c_object('VLAN')

function c_vlan.create_mdb_object(value)
    local app = c_object_manage.get_instance().app
    return app:CreateVLAN(1, value.NetworkAdapterObjectName, value.NetworkPortObjectName,
        value.VLANId, function(obj)
            obj.PortID = value.PortID
            obj.NetworkAdapterId = value.NetworkAdapterId
            obj.VLANId = value.VLANId
            obj.VLANEnabled = value.VLANEnable
            obj.VLANPriority = value.VLANPriority
            obj.AutoConnectOnBoot = value.AutoConnectOnBoot
            obj.NetworkAdapterObjectName = value.NetworkAdapterObjectName
            obj.NetworkPortObjectName = value.NetworkPortObjectName

            local mdb_object = obj:get_mdb_object('bmc.kepler.Systems.NetworkPort.VLAN')
            rawset(mdb_object, 'get_parent', function (object)
                return class_mgnt('NetworkPort')[object.path:match('([^/]+)/VLANs/[^/]+$')]
            end)

        end)
end

function c_vlan.insert_or_update(port_id, na_id, na_object_name, np_object_name, vlan)
    local value = {PortID = port_id, NetworkAdapterId = na_id, VLANId = vlan.VLANId}
    local obj = c_vlan.collection:find(value)
    if obj then
        value = obj
    end

    value.NetworkAdapterObjectName = na_object_name
    value.NetworkPortObjectName = np_object_name
    value.VLANEnabled = vlan.VLANEnable
    value.VLANPriority = vlan.VLANPriority
    value.AutoConnectOnBoot = vlan.AutoConnectOnBoot
    return obj or c_vlan.__table(value)
end

function c_vlan.get_vlans(port_id, na_id)
    return c_vlan.collection:fetch({PortID = port_id, NetworkAdapterId = na_id})
end

function c_vlan:update_ipv4_addresses(ipv4_addresses)
    local addrs = {}
    for _, addr in ipairs(ipv4_addresses) do
        c_vlan_ipv4_address.insert_or_update(self.PortID, self.NetworkAdapterId,
            self.NetworkAdapterObjectName, self.NetworkPortObjectName, self.VLANId, addr):save()
        addrs[addr.Address] = true
    end
    local exist_addrs = c_vlan_ipv4_address.get_addresses(self.PortID, self.NetworkAdapterId, self.VLANId)
    for _, addr in ipairs(exist_addrs) do
        if not addrs[addr.Address] then
            addr:dtor()
        end
    end
end

function c_vlan:update_ipv6_addresses(ipv6_addresses)
    local addrs = {}
    for _, addr in ipairs(ipv6_addresses) do
        c_vlan_ipv6_address.insert_or_update(self.PortID, self.NetworkAdapterId,
            self.NetworkAdapterObjectName, self.NetworkPortObjectName, self.VLANId, addr):save()
        addrs[addr.Address] = true
    end
    local exist_addrs = c_vlan_ipv6_address.get_addresses(self.PortID, self.NetworkAdapterId)
    for _, addr in ipairs(exist_addrs) do
        if not addrs[addr.Address] then
            addr:dtor()
        end
    end
end

function c_vlan:ctor()
end

function c_vlan:reset()
    local ipv4 = c_vlan_ipv4_address.get_addresses(self.PortID, self.NetworkAdapterId, self.VLANId)
    for _, addr in ipairs(ipv4) do
        c_vlan_ipv4_address.collection:del_object(addr)
    end
    local ipv6 = c_vlan_ipv6_address.get_addresses(self.PortID, self.NetworkAdapterId)
    for _, addr in ipairs(ipv6) do
        c_vlan_ipv6_address.collection:del_object(addr)
    end
end

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

return c_vlan
