/*
** 1998-09-12 -	We must have a Copy As command, since it's quite useful. Reuses all
**		copy_XXX() functions defined in the cmd_copy module, of course. Since
**		it so easy, I just had to let this module implement a Clone command, too!
** 1999-01-03 -	No longer passes the stat-structure from the dir listing to the copy module,
**		thus forcing it to do a re-read, which assures that the info (size) is fresh.
** 1999-03-06 -	Adapted for new selection/generic command handling.
** 1999-05-30 -	Added SymLinkAs and SymLinkClone commands. Nice.
*/

#include "gentoo.h"
#include "fileutil.h"
#include "dirpane.h"
#include "overwrite.h"
#include "progress.h"
#include "strutil.h"
#include "cmd_copy.h"
#include "cmd_generic.h"

#include "cmd_copyas.h"

#define	CMD_ID	"copy as"

/* ----------------------------------------------------------------------------------------- */

typedef enum { CPA_COPYAS, CPA_CLONE, CPA_SYMLINKAS, CPA_SYMLINKCLONE } CpaAction;

typedef struct {
	GtkWidget	*vbox;
	GtkWidget	*label;
	GtkWidget	*entry;
	CpaAction	action;
	MainInfo	*min;
	gint		ovw_open;
} CpaInfo;

/* ----------------------------------------------------------------------------------------- */

/* 1998-09-12 -	Update body of copy as GUI. */
static void cpa_copy_body(MainInfo *min, DirPane *src, DirRow *row, GtkWindow *win, gpointer user)
{
	gchar	buf[FILENAME_MAX + 32], *text;
	CpaInfo	*cpa = user;

	text = DP_ROW_NAME(row);
	if(cpa->action == CPA_COPYAS)
	{
		gtk_window_set_title(win, "Copy As");
		g_snprintf(buf, sizeof buf, "Enter name to copy \"%s\" as:", text);
	}
	else
	{
		gtk_window_set_title(win, "Clone");
		g_snprintf(buf, sizeof buf, "Enter name for clone of \"%s\":", text);
	}
	gtk_label_set_text(GTK_LABEL(cpa->label), buf);
	gtk_entry_set_text(GTK_ENTRY(cpa->entry), text);
	gtk_entry_select_region(GTK_ENTRY(cpa->entry), 0, -1);
	gtk_widget_grab_focus(cpa->entry);

	if(cpa->ovw_open == FALSE)
	{
		if(cpa->action == CPA_COPYAS)
			ovw_overwrite_begin(min, "\"%s\" already exists - continue with copy?", OVWF_HIDE);
		else
			ovw_overwrite_begin(min, "\"%s\" already exists - continue with clone?", OVWF_HIDE);
		pgs_progress_begin(min, cpa->action == CPA_COPYAS ? "Copy As" : "Clone", -1);
		cpa->ovw_open = TRUE;
	}
}

/* 1999-05-30 -	Update body for symlink operation. */
static void cpa_link_body(MainInfo *min, DirPane *src, DirRow *row, GtkWindow *win, gpointer user)
{
	gchar	buf[FILENAME_MAX + 32], *text;
	CpaInfo	*cpa = user;

	text = DP_ROW_NAME(row);
	if(cpa->action == CPA_SYMLINKAS)
	{
		gtk_window_set_title(win, "SymLinkAs");
		g_snprintf(buf, sizeof buf, "Enter name to link \"%s\" as:", text);
	}
	else if(cpa->action == CPA_SYMLINKCLONE)
	{
		gtk_window_set_title(win, "SymLinkClone");
		g_snprintf(buf, sizeof buf, "Enter name for link clone of \"%s\":", text);
	}
	gtk_label_set_text(GTK_LABEL(cpa->label), buf);
	gtk_entry_set_text(GTK_ENTRY(cpa->entry), text);
	gtk_entry_select_region(GTK_ENTRY(cpa->entry), 0, -1);
	gtk_widget_grab_focus(cpa->entry);

	if(cpa->ovw_open == FALSE)
	{
		ovw_overwrite_begin(min, "\"%s\" already exists - proceed with symlink?", OVWF_HIDE);
		pgs_progress_begin(min, "Linking", -1);
		cpa->ovw_open = TRUE;
	}
}

/* 1998-09-12 -	Perform action for copy as/clone command. */
static int cpa_action(MainInfo *min, DirPane *src, DirPane *dst, DirRow *row, gpointer user)
{
	gchar	dest[PATH_MAX], *text, *name;
	CpaInfo	*cpa = user;
	OvwRes	ores;

	if(!fut_cd(src->dir.path, NULL, 0))
		return 0;

	text = gtk_entry_get_text(GTK_ENTRY(cpa->entry));
	if(text && *text)
	{
		/* Enforce difference between clone and copy: clone name is without path. */
		switch(cpa->action)
		{
			case CPA_COPYAS:
			case CPA_SYMLINKAS:
				if(strchr(text, G_DIR_SEPARATOR) == NULL)
					g_snprintf(dest, sizeof dest, "%s/%s", dst->dir.path, text);
				else
					str_strncpy(dest, text, sizeof dest);
				break;
			case CPA_CLONE:
			case CPA_SYMLINKCLONE:
				if(strchr(text, G_DIR_SEPARATOR) != NULL)
					return 0;
				g_snprintf(dest, sizeof dest, "%s/%s", src->dir.path, text);
				break;
		}

		ores = ovw_overwrite_file(min, dest, dp_full_name(src, DP_ROW_INDEX(src, row)));
		if(ores == OVW_SKIP)
			return 1;
		else if(ores == OVW_CANCEL)
			return 0;

		if((cpa->action == CPA_COPYAS) || (cpa->action == CPA_CLONE))	/* Copy? */
		{
			mode_t	mode;

			name = DP_ROW_NAME(row);
			mode = DP_ROW_LSTAT(row).st_mode;
			if(S_ISLNK(mode))
				copy_link(min, name, dest);
			else if(S_ISDIR(mode))
				copy_dir(min, name, dest);
			else if(S_ISREG(mode))
				copy_file(min, name, dest, NULL);
			else if(S_ISCHR(mode) || S_ISBLK(mode))
				copy_device(min, name, dest, NULL);
		}
		else								/* Link. */
			symlink(dp_full_name(src, DP_ROW_INDEX(src, row)), dest);
	}
	if(errno == 0)
		dp_unselect(src, DP_ROW_INDEX(src, row));
	return errno == 0;
}

static void cpa_free(gpointer user)
{
	CpaInfo	*cpa = (CpaInfo *) user;

	if(cpa->ovw_open)
	{
		ovw_overwrite_end(cpa->min);
		pgs_progress_end(cpa->min);
	}
}

/* ----------------------------------------------------------------------------------------- */

/* 1998-09-12 -	Fire up either a COPYAS or a CLONE command, depending on the <action> arg. */
static int copyas_or_clone(MainInfo *min, DirPane *src, DirPane *dst, CpaAction action)
{
	static CpaInfo	cpa;

	cpa.action = action;
	cpa.min	   = min;
	cpa.ovw_open = FALSE;

	cpa.vbox = gtk_vbox_new(FALSE, 0);
	cpa.label = gtk_label_new("Copy As");
	cpa.entry = gtk_entry_new_with_max_length(FILENAME_MAX - 1);
	gtk_box_pack_start(GTK_BOX(cpa.vbox), cpa.label, FALSE, FALSE, 0);
	gtk_widget_show(cpa.label);
	gtk_box_pack_start(GTK_BOX(cpa.vbox), cpa.entry, FALSE, FALSE, 0);
	gtk_widget_show(cpa.entry);

	if(cpa.action == CPA_COPYAS)
		return cmd_generic(min, CGF_NOALL, cpa_copy_body, cpa_action, cpa_free, &cpa);
	else if(cpa.action == CPA_CLONE)
		return cmd_generic(min, CGF_NOALL | CGF_NODST | CGF_SRC, cpa_copy_body, cpa_action, cpa_free, &cpa);
	else if(cpa.action == CPA_SYMLINKAS)
		return cmd_generic(min, CGF_NOALL, cpa_link_body, cpa_action, cpa_free, &cpa);
	else if(cpa.action == CPA_SYMLINKCLONE)
		return cmd_generic(min, CGF_NOALL | CGF_NODST | CGF_SRC, cpa_link_body, cpa_action, cpa_free, &cpa);
	return 0;
}

/* ----------------------------------------------------------------------------------------- */

int cmd_copyas(MainInfo *min, DirPane *src, DirPane *dst, CmdArg *ca)
{
	return copyas_or_clone(min, src, dst, CPA_COPYAS);
}

int cmd_clone(MainInfo *min, DirPane *src, DirPane *dst, CmdArg *ca)
{
	return copyas_or_clone(min, src, dst, CPA_CLONE);
}

int cmd_symlinkas(MainInfo *min, DirPane *src, DirPane *dst, CmdArg *ca)
{
	return copyas_or_clone(min, src, dst, CPA_SYMLINKAS);
}

int cmd_symlinkclone(MainInfo *min, DirPane *src, DirPane *dst, CmdArg *ca)
{
	return copyas_or_clone(min, src, dst, CPA_SYMLINKCLONE);
}
