-- 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 json = require 'cjson'
local MenuNode = class()

function MenuNode:ctor(name)
    self.name = name or 'root'
    self.nodes = {}
    self.node_order = {}
    self.attributes = json.json_object_new_array()
    self.attribute_order = {}
    self.read_only = false
end

function MenuNode:insert(menu_paths, index, read_only)
    local menu_name = menu_paths[index]
    if not menu_name then
        return
    end
    if not self.nodes[menu_name] then
        self.nodes[menu_name] = MenuNode.new(menu_name)
        table.insert(self.node_order, menu_name)
    end
    self.nodes[menu_name]:insert(menu_paths, index + 1, read_only)
    if not menu_paths[index + 1] then
        self.read_only = read_only
    end
end

function MenuNode:add_attribute(menu_paths, index, data)
    local menu_name = menu_paths[index]
    -- 没有下一级目录，说明当前目录是最后一级
    if not menu_name then
        data.SettingValue = json.null
        data.DefaultHidden = data.Hidden
        data.DefaultImmutable = data.Immutable
        data.DefaultReadOnly = data.ReadOnly
        table.insert(self.attributes, data)
        self.attribute_order[data.AttributeName] = #self.attributes
        return
    else
        local node = self.nodes[menu_name]
        if not node then
            return
        end
        node:add_attribute(menu_paths, index + 1, data)
    end
end

function MenuNode:construct_menu_table()
    local config_info_table = json.json_object_new_object()
    -- 当前Menu的信息：SubMenu、ReadOnly、Attributes、Name
    config_info_table['SubMenu'] = json.json_object_new_array()
    config_info_table['ReadOnly'] = self.read_only
    config_info_table['Attributes'] = self.attributes
    config_info_table['Name'] = self.name
    return config_info_table
end

function MenuNode:traverse(config_info)
    if not self.nodes or not next(self.nodes) then
        table.insert(config_info, self:construct_menu_table(config_info))
        return
    end
    local traverse_table, current_table
    if self.name == 'root' then
        traverse_table = config_info
    else
        current_table = self:construct_menu_table()
        traverse_table = current_table['SubMenu']
    end
    for _, v in pairs(self.node_order) do
        -- traverse_table是current_table['SubMenu']，存放下一级的Menu
        self.nodes[v]:traverse(traverse_table)
    end
    if self.name ~= 'root' then
        -- 将当前Menu信息加入上一级Menu
        table.insert(config_info, current_table)
    end
    return
end

-- 更新CurrentValue、SettingValue
function MenuNode:update_value(menu_paths, index, attribute)
    local menu_name = menu_paths[index]
    -- 没有下一级目录，说明当前目录是最后一级
    if not menu_name then
        local order_num = self.attribute_order[attribute.attribute_name]
        if not order_num then
            return
        end
        if self.attributes[order_num][attribute.attribute_prop] == nil then
            return
        end
        self.attributes[order_num]
            [attribute.attribute_prop] = attribute.attribute_value
    else
        local node = self.nodes[menu_name]
        if not node then
            return
        end
        node:update_value(menu_paths, index + 1, attribute)
    end
end

function MenuNode:clear_value(menu_paths, index, attribute_name)
    local menu_name = menu_paths[index]
    -- 没有下一级目录，说明当前目录是最后一级
    if not menu_name then
        local order_num = self.attribute_order[attribute_name]
        if not order_num then
            return
        end
        self.attributes[order_num]['Hidden'] = self.attributes[order_num]['DefaultHidden']
        self.attributes[order_num]['Immutable'] = self.attributes[order_num]['DefaultImmutable']
        self.attributes[order_num]['ReadOnly'] = self.attributes[order_num]['DefaultReadOnly']
    else
        local node = self.nodes[menu_name]
        if not node then
            return
        end
        node:clear_value(menu_paths, index + 1, attribute_name)
    end
end

return MenuNode