/*
 * ct_menu.h
 *
 * Copyright 2009-2020
 * Giuseppe Penone <giuspen@gmail.com>
 * Evgenii Gurianov <https://github.com/txe>
 *
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#pragma once

#include <string>
#include <libxml++/libxml++.h>
#include <gtkmm.h>
#include "ct_types.h"

class CtConfig;

struct CtMenuAction
{
    std::string category;
    std::string id;
    std::string image;
    std::string name;
    std::string built_in_shortcut;
    std::string desc;
    sigc::slot<void> run_action;

    sigc::signal<void, bool> signal_set_sensitive = sigc::signal<void, bool>();
    sigc::signal<void, bool> signal_set_visible = sigc::signal<void, bool>();

    const std::string& get_shortcut(CtConfig* pCtConfig) const;
};

class CtApp;
class CtActions;

class CtMenu
{
public:
    CtMenu(CtConfig* pCtConfig, CtActions* pActions);

public:
    const char*       None       = "";
    const std::string KB_CONTROL = "<control>";
    const std::string KB_SHIFT   = "<shift>";
    const std::string KB_ALT     = "<alt>";

    enum POPUP_MENU_TYPE {Node, Text, Code, Link, Codebox, Image, Anchor, EmbFile, PopupMenuNum };
    enum ACCEL_TYPE {Menu, TreeView };

public:
   static Gtk::MenuItem* create_menu_item(GtkWidget* pMenu, const char* name, const char* image, const char* desc);

public:
    void init_actions(CtActions* pActions);

    CtMenuAction*  find_action(const std::string& id);
    const std::list<CtMenuAction>& get_actions() { return _actions; }

    GtkAccelGroup* default_accel_group();

    static ACCEL_TYPE       get_accel_type(const std::string& action_name);
    static Gtk::MenuItem*   find_menu_item(Gtk::MenuBar* menuBar, std::string name);
    static Gtk::AccelLabel* get_accel_label(Gtk::MenuItem* item);

    std::vector<Gtk::Toolbar*> build_toolbars(Gtk::MenuToolButton*& pRecentDocsMenuToolButton);
    Gtk::MenuBar*              build_menubar();
    Gtk::Menu*                 build_bookmarks_menu(std::list<std::pair<gint64, std::string>>& bookmarks,
                                                    sigc::slot<void, gint64>& bookmark_action);
    Gtk::Menu*                 build_recent_docs_menu(const CtRecentDocsFilepaths& recentDocsFilepaths,
                                                      sigc::slot<void, const std::string&>& recent_doc_open_action,
                                                      sigc::slot<void, const std::string&>& recent_doc_rm_action);
    Gtk::Menu*                 build_special_chars_menu(const Glib::ustring& specialChars,
                                                        sigc::slot<void, gunichar>& spec_char_action);

    Gtk::Menu*                 get_popup_menu(POPUP_MENU_TYPE popupMenuType);
    Gtk::Menu*                 build_popup_menu(GtkWidget* pMenu, POPUP_MENU_TYPE popupMenuType);
    Gtk::Menu*                 build_popup_menu_table_cell(GtkWidget* pMenu, const bool first_row, const bool first_col, const bool last_row, const bool last_col);

private:
    GtkWidget*     _walk_menu_xml(GtkWidget* pMenu, const char* document, const char* xpath);
    void           _walk_menu_xml(GtkWidget* pMenu, xmlpp::Node* pNode);
    GtkWidget*     _add_submenu(GtkWidget* pMenu, const char* id, const char* name, const char* image);
    Gtk::MenuItem* _add_menu_item(GtkWidget* pMenu, CtMenuAction* pAction);
    static Gtk::MenuItem* _add_menu_item(GtkWidget* pMenu, const char* name, const char* image,
                                         const char*shortcut, GtkAccelGroup* accelGroup,
                                         const char* desc, gpointer action_data,
                                         sigc::signal<void, bool>* signal_set_sensitive,
                                         sigc::signal<void, bool>* signal_set_visible);

    static void    _add_menu_item_image_or_label(Gtk::Widget* pMenuItem, const char* image, GtkWidget* pLabel);
    GtkWidget*     _add_separator(GtkWidget* pMenu);

    std::vector<std::string> _get_ui_str_toolbars();
    const char*              _get_ui_str_menu();
    const char*              _get_popup_menu_ui_str_text();
    const char*              _get_popup_menu_ui_str_code();
    const char*              _get_popup_menu_ui_str_image();
    const char*              _get_popup_menu_ui_str_anchor();
    const char*              _get_popup_menu_ui_str_embfile();

private:
    CtConfig*                  _pCtConfig;
    std::list<CtMenuAction>    _actions;
    Glib::RefPtr<Gtk::Builder> _rGtkBuilder;
    GtkAccelGroup*             _pAccelGroup;
    Gtk::Menu*                 _popupMenus[POPUP_MENU_TYPE::PopupMenuNum] = {};
};
