/*
 * SwamiguiTreeMenu_items.c - Built in menu items
 *
 * Swami
 * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
 *
 * 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; version 2
 * of the License only.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA or point your web browser to http://www.gnu.org.
 */
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <libinstpatch/libinstpatch.h>

#include "SwamiguiItemMenu.h"
#include "icons.h"
#include "patch_funcs.h"
#include "i18n.h"


static void item_action_paste_handler(SwamiguiItemMenu *menu,
                                      const char *action_id);
static void item_action_goto_link_handler(SwamiguiItemMenu *menu,
        const char *action_id);
static void item_action_load_samples_handler(SwamiguiItemMenu *menu,
        const char *action_id);
static void item_action_new_handler(SwamiguiItemMenu *menu,
                                    const char *action_id);

static void item_cb_paste_items(IpatchList *selection, gpointer data);
static void item_cb_find_item(IpatchList *selection, gpointer data);
static void item_cb_find_next_item(IpatchList *selection, gpointer data);
static void item_cb_goto_link_item(IpatchList *selection, gpointer data);
static void item_cb_load_samples(IpatchList *selection, gpointer data);
static void item_cb_new(IpatchList *selection, gpointer data);
static void item_cb_solo_toggle(IpatchList *selection, gpointer data);

typedef struct
{
    char *action_id;
    SwamiguiItemMenuHandler handler;
    SwamiguiItemMenuInfo info;
} MultiActionInfo;

MultiActionInfo item_action_info[] =
{
    {
        "copy", swamigui_item_menu_handler_multi,
        {
            100, N_("_Copy"), "<control>C", GTK_STOCK_COPY, 0,
            (SwamiguiItemMenuCallback)swamigui_copy_items, NULL
        }
    },
    {
        "paste", item_action_paste_handler,
        {
            200, N_("_Paste"), "<control>V", GTK_STOCK_PASTE, 0,
            (SwamiguiItemMenuCallback)item_cb_paste_items, NULL
        }
    },
    {
        "delete", swamigui_item_menu_handler_multi,
        {
            300, N_("_Delete"), "<control>D", GTK_STOCK_DELETE, 0,
            (SwamiguiItemMenuCallback)swamigui_delete_items, NULL
        }
    },
    {
        "find", swamigui_item_menu_handler_single_all,
        {
            400, N_("_Find"), "<control>F", GTK_STOCK_FIND, 0,
            item_cb_find_item, NULL
        }
    },
    {
        "find-next", swamigui_item_menu_handler_single_all,
        {
            410, N_("Find _Next"), "<control>G", GTK_STOCK_FIND, 0,
            item_cb_find_next_item, NULL
        }
    },
    {
        "goto-link", item_action_goto_link_handler,
        {
            500, N_("_Goto Link"), "<control>L", GTK_STOCK_JUMP_TO, 0,
            item_cb_goto_link_item, NULL
        }
    },
    {
        "save", swamigui_item_menu_handler_multi,
        {
            600, N_("_Save"), "<control>S", GTK_STOCK_SAVE, 0,
            (SwamiguiItemMenuCallback)swamigui_save_files, GINT_TO_POINTER(FALSE)
        }
    },
    {
        "save-as", swamigui_item_menu_handler_multi,
        {
            700, N_("Save _As"), NULL, GTK_STOCK_SAVE_AS, 0,
            (SwamiguiItemMenuCallback)swamigui_save_files, GINT_TO_POINTER(TRUE)
        }
    },
    {
        "close", swamigui_item_menu_handler_multi,
        {
            800, N_("Close"), "<control>W", GTK_STOCK_CLOSE, 0,
            (SwamiguiItemMenuCallback)swamigui_close_files, NULL
        }
    },
    {
        "load-samples", item_action_load_samples_handler,
        {
            900, N_("Load Samples"), NULL, GTK_STOCK_OPEN, 0,
            item_cb_load_samples, NULL
        }
    },
    {
        "export-samples", swamigui_item_menu_handler_multi,
        {
            1000, N_("Export Samples"), NULL, GTK_STOCK_SAVE, 0,
            (SwamiguiItemMenuCallback)swamigui_export_samples, NULL
        }
    },
    {
        "solo-item", swamigui_item_menu_handler_single,
        {
            1100, N_("Solo Toggle"), "<control>T", GTK_STOCK_MEDIA_PLAY, 0,
            (SwamiguiItemMenuCallback)item_cb_solo_toggle, NULL
        }
    },

    /* some of these fields are dynamically generated by the handler */
    {
        "new", item_action_new_handler,
        { 1100, "", NULL, GTK_STOCK_NEW, 0, item_cb_new, NULL }
    }
};

void
_swamigui_item_menu_actions_init(void)
{
    GValue value = { 0 };
    GType *types;
    guint count, i;

    /* register the item actions */
    for(i = 0; i < G_N_ELEMENTS(item_action_info); i++)
    {
        swamigui_register_item_menu_action(item_action_info[i].action_id,
                                           &item_action_info[i].info,
                                           item_action_info[i].handler);
    }

    swamigui_register_item_menu_include_type("copy", IPATCH_TYPE_ITEM, TRUE);
    swamigui_register_item_menu_exclude_type("copy", IPATCH_TYPE_VIRTUAL_CONTAINER,
            TRUE);
    swamigui_register_item_menu_include_type("paste",
            IPATCH_TYPE_CONTAINER, TRUE);
    swamigui_register_item_menu_include_type("paste",
            IPATCH_TYPE_VIRTUAL_CONTAINER, TRUE);
    swamigui_register_item_menu_include_type("delete",
            IPATCH_TYPE_ITEM, TRUE);
    swamigui_register_item_menu_exclude_type("delete", IPATCH_TYPE_BASE, TRUE);
    swamigui_register_item_menu_exclude_type("delete",
            IPATCH_TYPE_VIRTUAL_CONTAINER, TRUE);
    swamigui_register_item_menu_include_type("export-samples",
            IPATCH_TYPE_SAMPLE, TRUE);
    swamigui_register_item_menu_include_type("save", IPATCH_TYPE_ITEM, TRUE);

    swamigui_register_item_menu_include_type("save-as", IPATCH_TYPE_ITEM, TRUE);

    swamigui_register_item_menu_include_type("close", IPATCH_TYPE_BASE, TRUE);

    /* Add types for solo-item action to instrument ref and sample ref category types */
    g_value_init(&value, G_TYPE_INT);
    g_value_set_int(&value, IPATCH_CATEGORY_INSTRUMENT_REF);
    types = ipatch_type_find_types_with_property("category", &value, &count);     /* ++ alloc types */

    if(types)
    {
        for(i = 0; i < count; i++)
        {
            swamigui_register_item_menu_include_type("solo-item", types[i], TRUE);
        }

        g_free(types);      /* -- unref types */
    }

    g_value_set_int(&value, IPATCH_CATEGORY_SAMPLE_REF);
    types = ipatch_type_find_types_with_property("category", &value, &count);     /* ++ alloc types */

    if(types)
    {
        for(i = 0; i < count; i++)
        {
            swamigui_register_item_menu_include_type("solo-item", types[i], TRUE);
        }

        g_free(types);      /* -- unref types */
    }

#if 0
    { "wavetbl-load", N_("Wavetable Load"), "<control>L", 0,
        swamigui_ifaces_cb_wtbl_load_patch, NULL
    }
#endif
}

static void
item_action_paste_handler(SwamiguiItemMenu *menu, const char *action_id)
{
    GObject *item;

    item = swamigui_item_menu_get_selection_single(menu);

    if(!item)
    {
        return;
    }

    /* if item type matches an exclude type - return */
    if(!swamigui_test_item_menu_exclude_type(action_id, G_OBJECT_TYPE(item)))
    {
        return;
    }

    /* if item does not match an include type.. */
    if(!swamigui_test_item_menu_include_type(action_id, G_OBJECT_TYPE(item)))
    {
        GType link_type;

        /* IpatchItem's with a link type are valid */
        ipatch_type_get(G_OBJECT_TYPE(item), "link-type", &link_type, NULL);

        if(!IPATCH_IS_ITEM(item) || link_type == G_TYPE_NONE)
        {
            return;
        }
    }

    swamigui_item_menu_add_registered_info(menu, action_id);
}

static void
item_action_goto_link_handler(SwamiguiItemMenu *menu, const char *action_id)
{
    IpatchList *list;
    GObject *item, *origin;

    list = swamigui_item_menu_get_selection(menu);

    /* make sure exactly one item is selected */
    if(!list || !list->items || list->items->next)
    {
        return;
    }

    /* only makes sense to goto link if a tree is the origin of selection */
    origin = swami_object_get_origin(G_OBJECT(list));     // ++ ref origin object

    if(!origin || !SWAMIGUI_IS_TREE(origin))
    {
        if(origin)
        {
            g_object_unref(origin);    // -- unref origin object
        }

        return;
    }

    g_object_unref(origin);                               // -- unref origin object

    item = (GObject *)(list->items->data);

    /* if item type matches an exclude type - return */
    if(!swamigui_test_item_menu_exclude_type(action_id, G_OBJECT_TYPE(item)))
    {
        return;
    }

    /* if item does not match an include type.. */
    if(!swamigui_test_item_menu_include_type(action_id, G_OBJECT_TYPE(item)))
    {
        GType link_type;
        GObject *link;

        /* if object has link-type type property and link-item property is set,
        create menu item */

        ipatch_type_get(G_OBJECT_TYPE(item), "link-type", &link_type, NULL);

        if(!IPATCH_IS_ITEM(item) || link_type == G_TYPE_NONE)
        {
            return;
        }

        g_object_get(item, "link-item", &link, NULL);

        if(link)
        {
            g_object_unref(link);
        }

        if(!link)
        {
            return;
        }
    }

    swamigui_item_menu_add_registered_info(menu, action_id);
}

static void
item_action_load_samples_handler(SwamiguiItemMenu *menu, const char *action_id)
{
    GObject *item;
    const GType *child_types, child;
    int category;

    item = swamigui_item_menu_get_selection_single(menu);

    if(!item)
    {
        return;
    }

    /* if item type matches an exclude type - return */
    if(!swamigui_test_item_menu_exclude_type(action_id, G_OBJECT_TYPE(item)))
    {
        return;
    }

    /* if item does not match an include type.. */
    if(!swamigui_test_item_menu_include_type(action_id, G_OBJECT_TYPE(item)))
    {
        /* virtual container which contains sample category items? - Add */
        if(IPATCH_IS_VIRTUAL_CONTAINER(item))
        {
            ipatch_type_get(G_OBJECT_TYPE(item), "virtual-child-type", &child, NULL);

            if(child == G_TYPE_NONE)
            {
                return;
            }

            ipatch_type_get(child, "category", &category, NULL);

            if(category != IPATCH_CATEGORY_SAMPLE)
            {
                return;
            }
        }
        else /* IpatchBase derived and has child item with sample category? - add */
        {
            if(!IPATCH_IS_BASE(item))
            {
                return;
            }

            child_types = ipatch_container_get_child_types(IPATCH_CONTAINER(item));

            for(; *child_types; child_types++)
            {
                ipatch_type_get(*child_types, "category", &category, NULL);

                if(category == IPATCH_CATEGORY_SAMPLE)
                {
                    break;
                }
            }

            if(!*child_types)
            {
                return;
            }
        }
    }

    swamigui_item_menu_add_registered_info(menu, action_id);
}

static void
item_action_new_handler(SwamiguiItemMenu *menu, const char *action_id)
{
    GObject *item;
    const GType *child_types;
    GType type;
    SwamiguiItemMenuInfo newinfo, *infop;
    char *type_name;
    int category;

    item = swamigui_item_menu_get_selection_single(menu);

    if(!item)
    {
        return;
    }

    /* if item type matches an exclude type - return */
    if(!swamigui_test_item_menu_exclude_type(action_id, G_OBJECT_TYPE(item)))
    {
        return;
    }

    if(IPATCH_IS_VIRTUAL_CONTAINER(item))
    {
        swamigui_lookup_item_menu_action(action_id, &infop, NULL);
        newinfo = *infop;

        ipatch_type_get(G_OBJECT_TYPE(item), "virtual-child-type", &type, NULL);

        if(type == G_TYPE_NONE)
        {
            return;
        }

        /* only New for Program and Instrument types */
        ipatch_type_get(type, "category", &category, NULL);

        if(category != IPATCH_CATEGORY_PROGRAM
                && category != IPATCH_CATEGORY_INSTRUMENT)
        {
            return;
        }

        ipatch_type_get(type, "name", &type_name, NULL);
        newinfo.label = g_strdup_printf(_("New %s"), type_name ? type_name
                                        : g_type_name(type));
        g_free(type_name);
        newinfo.data = GSIZE_TO_POINTER(type);

        swamigui_item_menu_add(menu, &newinfo, action_id);

        g_free(newinfo.label);

        return;
    }

    if(!IPATCH_IS_CONTAINER(item))
    {
        return;
    }

    swamigui_lookup_item_menu_action(action_id, &infop, NULL);
    newinfo = *infop;

    child_types = ipatch_container_get_child_types(IPATCH_CONTAINER(item));

    for(; *child_types; child_types++)
    {
        /* skip any types in exclude list */
        if(!swamigui_test_item_menu_exclude_type(action_id, *child_types))
        {
            continue;
        }

        /* only New for Program and Instrument types */
        ipatch_type_get(*child_types, "category", &category, NULL);

        if(category != IPATCH_CATEGORY_PROGRAM
                && category != IPATCH_CATEGORY_INSTRUMENT)
        {
            continue;
        }

        newinfo.order++;
        ipatch_type_get(*child_types, "name", &type_name, NULL);
        newinfo.label = g_strdup_printf(_("New %s"), type_name ? type_name
                                        : g_type_name(*child_types));
        g_free(type_name);
        newinfo.data = GSIZE_TO_POINTER(*child_types);

        swamigui_item_menu_add(menu, &newinfo, action_id);

        g_free(newinfo.label);
    }
}

/* SwamiguiItemMenu action callbacks */

static void
item_cb_paste_items(IpatchList *selection, gpointer data)
{
    if(!selection->items || selection->items->next)
    {
        return;
    }

    swamigui_paste_items(IPATCH_ITEM(selection->items->data), NULL);
}

static void
item_cb_find_item(IpatchList *selection, gpointer data)
{
    GObject *origin;

    origin = swami_object_get_origin(G_OBJECT(selection));        // ++ ref origin object

    if(!origin || !SWAMIGUI_IS_TREE(origin))
    {
        if(origin)
        {
            g_object_unref(origin);    // -- unref origin object
        }

        return;
    }

    swamigui_tree_search_set_visible(SWAMIGUI_TREE(origin), TRUE);

    g_object_unref(origin);	/* -- unref */
}

static void
item_cb_find_next_item(IpatchList *selection, gpointer data)
{
    GObject *origin;

    origin = swami_object_get_origin(G_OBJECT(selection));        // ++ ref origin object

    if(!origin || !SWAMIGUI_IS_TREE(origin))
    {
        if(origin)
        {
            g_object_unref(origin);    // -- unref origin object
        }

        return;
    }

    swamigui_tree_search_next(SWAMIGUI_TREE(origin));

    g_object_unref(origin);	/* -- unref */
}

static void
item_cb_goto_link_item(IpatchList *selection, gpointer data)
{
    GObject *origin;

    if(!selection->items || selection->items->next)
    {
        return;
    }

    origin = swami_object_get_origin(G_OBJECT(selection));        // ++ ref origin object

    if(!origin || !SWAMIGUI_IS_TREE(origin))
    {
        if(origin)
        {
            g_object_unref(origin);    // -- unref origin object
        }

        return;
    }

    swamigui_goto_link_item(IPATCH_ITEM(selection->items->data),
                            SWAMIGUI_TREE(origin));

    g_object_unref(origin);	/* -- unref */
}

static void
item_cb_load_samples(IpatchList *selection, gpointer data)
{
    if(!selection->items || selection->items->next)
    {
        return;
    }

    swamigui_load_files(G_OBJECT(selection->items->data), TRUE);
}

static void
item_cb_new(IpatchList *selection, gpointer data)
{
    if(!selection->items || selection->items->next)
    {
        return;
    }

    swamigui_new_item(IPATCH_ITEM(selection->items->data),
                      (GType)GPOINTER_TO_SIZE(data));
}

static void
item_cb_solo_toggle(IpatchList *selection, gpointer data)
{
    gboolean enabled;

    if(!selection->items || selection->items->next)
    {
        return;
    }

    /* Toggle solo-item-enable property of swamiguiroot */
    g_object_get(swamigui_root, "solo-item-enable", &enabled, NULL);
    g_object_set(swamigui_root, "solo-item-enable", !enabled, NULL);
}
