-- 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_network_adapter = require 'device.class.network_adapter'
local c_network_port = require 'device.class.network_port'
local c_optical_module = require 'device.class.optical_module'
local dbus_sms = require 'dbus_sms'
local object_path = require 'dbus.object_path'
local signal = require 'mc.signal'
local unescape = object_path.unescape

local m = {}

function m.create_mds_object(object_name, props, parent, path)
    local property_changed = signal.new()
    return setmetatable({
        props = props,
        persist_data = {},
        props_set_by_cb = {},
        get_property_memory_value = function(self)
        end
    }, {
        __index = function(self, name)
            if name == 'get_object_name' then
                return function()
                    return object_name
                end
            elseif name == 'get_parent' then
                return function()
                    return parent
                end
            elseif name == 'path' then
                return path
            elseif name == 'property_changed' then
                return property_changed
            elseif name == 'register_mdb_objects' then
                return function ()
                end
            end
            return self.props[name]
        end,
        __newindex = function(self, name, value)
            if self.props[name] ~= value then
                self.props[name] = value
                property_changed:emit(name, value)
            end
        end
    })
end

local na_path<const> = '/bmc/kepler/Systems/1/NetworkAdapters/NetworkAdapter_1_000105'
local port_path<const> =
    '/bmc/kepler/Systems/1/NetworkAdapters/NetworkAdapter_1_0001010101/Ports/NetworkPort_0_0001010101'
local op_path<const> =
    '/bmc/kepler/Systems/1/NetworkAdapters/NetworkAdapter_1_0001010101/Ports/NetworkPort_0_0001010101/OpticalModule'
function m.add_network_adapter(object_manage, object_name, props, position, parent, path)
    local obj = m.create_mds_object(object_name, props, parent, path or na_path)
    object_manage.mc:before_add_object(c_network_adapter.__class_name, obj)
    object_manage.mc:add_object(c_network_adapter.__class_name, obj, position)
    return obj
end

function m.add_network_port(object_manage, object_name, props, position, parent, path)
    local obj = m.create_mds_object(object_name, props, parent, path or port_path)
    object_manage.mc:before_add_object(c_network_port.__class_name, obj)
    object_manage.mc:add_object(c_network_port.__class_name, obj, position)
    return obj
end

function m.add_optical_module(object_manage, object_name, props, position, parent, path)
    local obj = m.create_mds_object(object_name, props, parent, path or op_path)
    object_manage.mc:add_object(c_optical_module.__class_name, obj, position)
    return obj
end

function m.add_object_complete(object_manage, position)
    object_manage.mc:add_object_complete(position)
end

function m.ipv4_obj(addr)
    return {
        Address = addr.Address,
        AddressOrigin = addr.AddressOrigin,
        SubnetMask = addr.SubnetMask,
        Gateway = type(addr.Gateway) == 'table' and table.concat(addr.Gateway, ' ') or addr.Gateway
    }
end

function m.ipv6_obj(addr)
    return {
        Address = addr.Address,
        AddressState = addr.AddressState,
        AddressOrigin = addr.AddressOrigin,
        PrefixLength = addr.PrefixLength
    }
end

function m.find_address(addrs, addr)
    for _, v in ipairs(addrs) do
        if v.Address == addr then
            return v
        end
    end
end

function m.CreateIPv4Address(SystemID, ID1, ID2, ID3, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemID .. '/NetworkAdapters/' .. ID1 .. '/Ports/' ..
                     ID2 .. '/IPv4Addresses/' .. ID3 .. ''
    local obj = {path = path}
    prop_setting_cb(obj)
    return obj
end

function m.CreateIPv6Address(SystemID, ID1, ID2, ID3, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemID .. '/NetworkAdapters/' .. ID1 .. '/Ports/' ..
                     ID2 .. '/IPv6Addresses/' .. ID3 .. ''
    local obj = {path = path}
    prop_setting_cb(obj)
    return obj
end

function m.CreateVLANIPv4Address(SystemID, ID1, ID2, ID3, ID4, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemID .. '/NetworkAdapters/' .. ID1 .. '/Ports/' ..
                     ID2 .. '/VLANs/' .. ID3 .. '/IPv4Addresses/' .. ID4 .. ''
    local obj = {path = path}
    prop_setting_cb(obj)
    return obj
end

function m.CreateVLANIPv6Address(SystemID, ID1, ID2, ID3, ID4, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemID .. '/NetworkAdapters/' .. ID1 .. '/Ports/' ..
                     ID2 .. '/VLANs/' .. ID3 .. '/IPv6Addresses/' .. ID4 .. ''
    local obj = {path = path}
    prop_setting_cb(obj)
    return obj
end

function m.CreateVLAN(SystemID, ID1, ID2, ID3, prop_setting_cb)
    local path = '/bmc/kepler/Systems/' .. SystemID .. '/NetworkAdapters/' .. ID1 .. '/Ports/' ..
                     ID2 .. '/VLANs/' .. ID3 .. ''
    local obj = {path = path}
    obj.get_mdb_object = function ()
        return {}
    end
    prop_setting_cb(obj)
    return obj
end

function m.table_clone(t)
    local r = {}
    for k, v in pairs(t) do
        if type(v) == 'table' then
            r[k] = m.table_clone(v)
        else
            r[k] = v
        end
    end
    return r
end

function m.json_data_to_dbus_data(json_data)
    local data = {}
    for k, v in pairs(json_data) do
        if k == '@odata.id' then
            data[k] = unescape(dbus_sms.to_bmc_url(v))
        elseif type(v) == 'table' then
            data[k] = m.json_data_to_dbus_data(v)
        else
            data[k] = v
        end
    end

    return data
end
return m
