/*
   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
   For a list of contributors, see the accompanying CONTRIBUTORS file.

   This file is part of GtkRadiant.

   GtkRadiant is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   GtkRadiant is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GtkRadiant; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "pluginmenu.h"

#include <gtk/gtk.h>

#include "stream/textstream.h"

#include "gtkutil/pointer.h"
#include "gtkutil/menu.h"

#include "pluginmanager.h"
#include "mainframe.h"
#include "preferences.h"


int m_nNextPlugInID = 0;

void plugin_activated(ui::Widget widget, gpointer data)
{
    const char *str = (const char *) g_object_get_data(G_OBJECT(widget), "command");
    GetPlugInMgr().Dispatch(gpointer_to_int(data), str);
}

#include <stack>

void PlugInMenu_Add(ui::Menu plugin_menu, IPlugIn *pPlugIn)
{
    ui::Widget item{ui::null}, parent{ui::null};
    ui::Menu menu{ui::null}, subMenu{ui::null};
    const char *menuText, *menuCommand;
    std::stack<ui::Menu> menuStack;

    parent = ui::MenuItem(pPlugIn->getMenuName());
    parent.show();
    plugin_menu.add(parent);

    std::size_t nCount = pPlugIn->getCommandCount();
    if (nCount > 0) {
        menu = ui::Menu(ui::New);
        /*if (g_Layout_enableOpenStepUX.m_value) {
            menu_tearoff(menu);
        }*/
        while (nCount > 0) {
            menuText = pPlugIn->getCommandTitle(--nCount);
            menuCommand = pPlugIn->getCommand(nCount);

            if (menuText != 0 && strlen(menuText) > 0) {
                if (!strcmp(menuText, "-")) {
                    item = ui::Widget::from(gtk_menu_item_new());
                    gtk_widget_set_sensitive(item, FALSE);
                } else if (!strcmp(menuText, ">")) {
                    menuText = pPlugIn->getCommandTitle(--nCount);
                    menuCommand = pPlugIn->getCommand(nCount);
                    if (!strcmp(menuText, "-") || !strcmp(menuText, ">") || !strcmp(menuText, "<")) {
                        globalErrorStream() << pPlugIn->getMenuName() << " Invalid title (" << menuText
                                            << ") for submenu.\n";
                        continue;
                    }

                    item = ui::MenuItem(menuText);
                    item.show();
                    menu.add(item);

                    subMenu = ui::Menu(ui::New);
                    gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), subMenu);
                    menuStack.push(menu);
                    menu = subMenu;
                    continue;
                } else if (!strcmp(menuText, "<")) {
                    if (!menuStack.empty()) {
                        menu = menuStack.top();
                        menuStack.pop();
                    } else {
                        globalErrorStream() << pPlugIn->getMenuName()
                                            << ": Attempt to end non-existent submenu ignored.\n";
                    }
                    continue;
                } else {
                    item = ui::MenuItem(menuText);
                    g_object_set_data(G_OBJECT(item), "command",
                                      const_cast<gpointer>( static_cast<const void *>( menuCommand )));
                    item.connect("activate", G_CALLBACK(plugin_activated), gint_to_pointer(m_nNextPlugInID));
                }
                item.show();
                menu.add(item);
                pPlugIn->addMenuID(m_nNextPlugInID++);
            }
        }
        if (!menuStack.empty()) {
            std::size_t size = menuStack.size();
            if (size != 0) {
                globalErrorStream() << pPlugIn->getMenuName() << " mismatched > <. " << Unsigned(size)
                                    << " submenu(s) not closed.\n";
            }
            for (std::size_t i = 0; i < (size - 1); i++) {
                menuStack.pop();
            }
            menu = menuStack.top();
            menuStack.pop();
        }
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent), menu);
    }
}

ui::Menu g_plugins_menu{ui::null};
ui::MenuItem g_plugins_menu_separator{ui::null};

void PluginsMenu_populate()
{
    class PluginsMenuConstructor : public PluginsVisitor {
        ui::Menu m_menu;
    public:
        PluginsMenuConstructor(ui::Menu menu) : m_menu(menu)
        {
        }

        void visit(IPlugIn &plugin)
        {
            PlugInMenu_Add(m_menu, &plugin);
        }
    };

    PluginsMenuConstructor constructor(g_plugins_menu);
    GetPlugInMgr().constructMenu(constructor);
}

void PluginsMenu_clear()
{
    m_nNextPlugInID = 0;

    GList *lst = g_list_find(gtk_container_get_children(GTK_CONTAINER(g_plugins_menu)),
                             g_plugins_menu_separator._handle);
    while (lst->next) {
        g_plugins_menu.remove(ui::Widget::from(lst->next->data));
        lst = g_list_find(gtk_container_get_children(GTK_CONTAINER(g_plugins_menu)), g_plugins_menu_separator._handle);
    }
}

ui::MenuItem create_plugins_menu()
{
    // Plugins menu
    auto plugins_menu_item = new_sub_menu_item_with_mnemonic("_Plugins");
    auto menu = ui::Menu::from(gtk_menu_item_get_submenu(plugins_menu_item));
    /*if (g_Layout_enableOpenStepUX.m_value) {
        menu_tearoff(menu);
    }*/

    g_plugins_menu = menu;

    //TODO: some modules/plugins do not yet support refresh
#if 0
    create_menu_item_with_mnemonic( menu, "Refresh", makeCallbackF(Restart) );

    // NOTE: the seperator is used when doing a refresh of the list, everything past the seperator is removed
    g_plugins_menu_separator = menu_separator( menu );
#endif

    PluginsMenu_populate();

    return plugins_menu_item;
}
