/* $Id: e2p_tag.c 2064 2010-03-12 13:15:36Z tpgww $

Copyright (C) 2009-2010 tooar <tooar@emelfm2.net>

This file is part of emelFM2.
emelFM2 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, or (at your option)
any later version.

emelFM2 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 emelFM2; see the file GPL. If not, see http://www.gnu.org/licenses.
*/

/**
@file plugins/e2p_tag.c
@brief plugin to log selected items and reselect them later
*/

#include "emelfm2.h"
#include "e2_plugins.h"
#include "e2_fileview.h"
#include "e2_filelist.h"

#ifdef E2_VFSTMP
	FIXME app.vdir_cache is for vpath* s i.e path + spacedata
/*
static (GHashFunc) hash_func, ()
{
}
static (GEqualFunc) key_equal_func ()
{
}
static (GDestroyNotify) key_destroy_func ()
{
}
gpointer hash key (PlaceInfo *spacedata, gchar *path)
{
	return NULL;
}
*/
#endif

/**
@brief log the names of selected items, if any, in the specified pane

@param from the button, menu item etc which was activated
@param art action runtime data

@return TRUE if action completed successfully, else FALSE
*/
static gboolean _e2p_tag_selected (gpointer from, E2_ActionRuntime *art)
{
	E2_ListChoice p;
	E2_PaneRuntime *rt;
	ViewInfo *view;
	GtkTreeModel *model;
	GHashTable *selitems;
	GList *selpaths, *rowpath;
	E2_DirHistoryEntry *hist;

	rt = e2_pane_get_runtime (from, art->data, NULL);
	view = (ViewInfo *)rt;
#ifdef E2_VFS
	VPATH ddata = { view->dir, view->spacedata }; //CHECKME path encoding ?
	vpath *vdir = g_hash_table_lookup (app.vdir_cache, &ddata);
	if (G_UNLIKELY(vdir == NULL))
		return FALSE;
#endif

	p = (rt == curr_pane) ? PANEACTIVE : PANEINACTIVE;
	e2_filelist_disable_one_refresh (p);
	WAIT_FOR_REFRESH(view)

	selpaths = gtk_tree_selection_get_selected_rows (view->selection, &model);
	if (selpaths == NULL)
	{
		e2_filelist_enable_one_refresh (p);
		return FALSE;
	}

#ifdef E2_VFS
	hist = g_hash_table_lookup (app.dir_history, vdir);
#else
	hist = g_hash_table_lookup (app.dir_history, view->dir);
#endif
	if (hist->selitems != NULL)
		g_hash_table_destroy (hist->selitems);
	hist->selitems = selitems =
		g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);

	for (rowpath = selpaths; rowpath != NULL; rowpath = rowpath->next)
	{
		GtkTreeIter iter;
		GtkTreePath *path;
		FileInfo *info;

		path = (GtkTreePath *) rowpath->data;
		if (gtk_tree_model_get_iter (model, &iter, path))
		{
			gtk_tree_model_get (model, &iter, FINFO, &info, -1);
			//info doesn't persist
			g_hash_table_insert (selitems, g_strdup(info->filename), GINT_TO_POINTER(1));
		}
		gtk_tree_path_free (path);
	}
	g_list_free (selpaths);

	e2_filelist_enable_one_refresh (p);

	return TRUE;
}

/**
@brief re-select the 'tagged' items, if any, in the specified pane

@param from the button, menu item etc which was activated
@param art action runtime data

@return TRUE if action completed successfully, else FALSE
*/
static gboolean _e2p_retag (gpointer from, E2_ActionRuntime *art)
{
	E2_ListChoice p;
	E2_PaneRuntime *rt;
	ViewInfo *view;
	E2_DirHistoryEntry *hist;
	GtkTreeModel *model;
	GtkTreeIter iter;

	rt = e2_pane_get_runtime (from, art->data, NULL);
	view = (ViewInfo *)rt;

	//get history item for this dir
#ifdef E2_VFS
	vpath *vdir = g_hash_table_find (?, );
	if (G_UNLIKELY(vdir == NULL))
		return FALSE;
	hist = g_hash_table_lookup (app.dir_history, vdir);
#else
	hist = g_hash_table_lookup (app.dir_history, view->dir);
#endif
	if (G_UNLIKELY(hist == NULL || hist->selitems == NULL))
		return FALSE;	//should never happen

	p = (rt == curr_pane) ? PANEACTIVE : PANEINACTIVE;
	e2_filelist_disable_one_refresh (p);
	WAIT_FOR_REFRESH(view)

	model = view->model;
	if (gtk_tree_model_get_iter_first (model, &iter));
	{	//it's not empty now
		GHashTable *selitems;
		GtkTreeSelection *sel;

		selitems = hist->selitems;
		sel = view->selection;
		gtk_tree_selection_unselect_all (sel);	//start with clean slate
		do
		{
			FileInfo *info;

			gtk_tree_model_get (model, &iter, FINFO, &info, -1);
			//We only check for name, no other statbuf parameters are stored ATM
			if (g_hash_table_lookup(selitems, info->filename) != NULL)
				gtk_tree_selection_select_iter (sel, &iter);
		} while (gtk_tree_model_iter_next (model, &iter));
	}

	e2_filelist_enable_one_refresh (p);

	return TRUE;
}

//aname must be confined to this module
static gchar *aname;
static gchar *aname2;
/**
@brief plugin initialization function, called by main program

@param p ptr to plugin data struct

@return TRUE if the initialization succeeds, else FALSE
*/
gboolean init_plugin (Plugin *p)
{
#define ANAME "tag"
	aname = _("tag");
	aname2 = _("retag");
	//these are data for the "parent" plugin item
	p->signature = ANAME VERSION;
	p->menu_name = _("_Tag");
	//no tip will work for a submenu item, but we want to avoid silly default
	//string in config dialog until the plugin is actually loaded
	//this string will be replaced by "" when plugin is loaded ??
	p->description = "";
	p->icon = "plugin_"ANAME E2ICONTB;  //use icon file pathname if appropriate

	//child UI data
	gchar *sig1 = "0-"ANAME;
	gchar *label1 = (gchar *)p->menu_name;
//	gchar *icon1 = "";	//no icon "plugin_"ANAME E2ICONTB;  //use icon file pathname if appropriate
	gchar *tip1 = _("Log the selected item(s) in active pane");
	gchar *sig2 = "1-"ANAME;
	gchar *label2 = _("_Retag");
//	gchar *icon2 = "";
	gchar *tip2 = _("Re-select any logged item(s) in active pane");

	if (p->action == NULL)
	{
		gboolean retval;
		Plugin *pc = e2_plugins_create_child (p);
		if (pc != NULL)
		{
			//for reconciling with config treestore data, signatures must reflect
			//0-based index of each child's order in the list of children
			pc->signature = sig1; //begin with "n-", n=0,1, ...
			//these will generallly be discarded in favour of config treestore data
			//meaning that any non-constant string will leak
			pc->menu_name = label1;	//or whatever
//			pc->description = _("Copy selected item(s), with displayed progress details");
			pc->description = tip1;	//or whatever
//			pc->icon = "plugin_copy"E2ICONTB;  //use icon file pathname if appropriate
			//YUK _A(6) here makes the parent item file-specific, which prevents
			//_A(7) working for retag action
			//don't free name string here
			E2_Action plugact =
			{g_strconcat (_A(6),".",aname,NULL),_e2p_tag_selected,TRUE,E2_ACTION_TYPE_ITEM,0,NULL,NULL};
			pc->action = e2_plugins_action_register (&plugact);
			if G_LIKELY((pc->action != NULL))
				retval = TRUE;
			else
			{
				g_free (plugact.name);
				retval = FALSE;
			}
		}
		else
			retval = FALSE;

		//this will not be used, but MUST be set to allow checking whether to show
		//the item in the context menu
		if (retval)
			p->action = pc->action;

		pc = e2_plugins_create_child (p);
		if (pc != NULL)
		{
			pc->signature = sig2;	//for reconciling with config treestore data
			pc->menu_name = label2;
			pc->description = tip2;
//			pc->icon = "plugin_copy"E2ICONTB;  //use icon file pathname if appropriate
			//don't free name here FIXME some name not file-specific
			E2_Action plugact =
			{g_strconcat (_A(6),".",aname2,NULL),_e2p_retag,TRUE,E2_ACTION_TYPE_ITEM,0,NULL,NULL};
			pc->action = e2_plugins_action_register (&plugact);
			if G_LIKELY((pc->action != NULL))
				retval = TRUE;
			else
			{
				g_free (plugact.name);
				retval = FALSE;
			}
		}
		else
			retval = FALSE;

		if (retval && (p->action == NULL))
			p->action = pc->action;

		return retval;
	}
	else	//setup children UI data for pushing into a config dialog
	{
		E2_Sextet *uidata;
		uidata = e2_utils_sextet_new ();
		p->child_list = g_list_append (p->child_list, uidata);
		uidata->a = label1;
		uidata->b = "";	//no icon
		uidata->c = tip1;
		uidata->d = sig1;
		uidata = e2_utils_sextet_new ();
		p->child_list = g_list_append (p->child_list, uidata);
		uidata->a = label2;
		uidata->b = "";
		uidata->c = tip2;
		uidata->d = sig2;
	}

	return FALSE;
}
/**
@brief cleanup transient things for this plugin

@param p pointer to data struct for the plugin

@return TRUE if all cleanups were completed
*/
gboolean clean_plugin (Plugin *p)
{
	gchar *action_name = g_strconcat (_A(6),".",aname,NULL);
	gboolean ret1 = e2_plugins_action_unregister (action_name);
	g_free (action_name);
	action_name = g_strconcat (_A(6),".",aname2,NULL);
	gboolean ret2 = e2_plugins_action_unregister (action_name);
	g_free (action_name);
	return (ret1 && ret2);
}
