/* $Id: e2_cl_option.c 2552 2012-06-02 00:30:41Z tpgww $

Copyright (C) 2003-2012 tooar <tooar@emelfm2.net>

This file is part of emelFM2, which 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 src/config/e2_cl_option.c
@brief session-start command-line option processing, and help messages display

Glib's option parsing mechanism - GOptionContext and friends - ia not used
because several emelFM2 options may have whitespace inside an argument string -
and that is not supported by GOptionContext (nor is -h for help)
*/

#include "emelfm2.h"
#include <getopt.h>
#include <string.h>
#include "e2_cl_option.h"

/**
@brief print minimal usage message on console

@return
*/
static void _e2_cl_option_print_usage (void)
{
	printf (_("usage: %s [option]\n"), BINNAME);
}
/**
@brief print full usage message on console

@return
*/
static void _e2_cl_option_print_help (void)
{
	_e2_cl_option_print_usage ();
	/*NOTE for translators: do not translate the actual option strings
	  (-h, --help etc) but it's ok to translate any other part of this string */
	printf (
	  _("Program options:\n"
		"-1,--one=DIR           set 1st pane's start directory to DIR\n"
		"-2,--two=DIR           set 2nd pane's start directory to DIR\n"
		"-c,--config=DIR        set config directory to DIR (default: ~/.config/emelfm2)\n"
		"-e,--encoding=TYPE     set filesystem character encoding to TYPE\n"
		"-f,--fallback-encoding set fallback encoding (default: ISO-8859-1)\n"
		"-i,--ignore-problems   ignore encoding/locale problems (at your own risk!)\n"
		"-l,--log-all           maximise scope of error logging\n"
		"-m,--daemon            run program as daemon\n"
		"-o,--original          run program with default settings\n"
		"-r,--run-at-start=CMD  run command CMD at session start\n"
		"-s,--set-option=OPT    set one-line gui option using config-file formatted OPT\n"
		"-t,--trash=DIR         set trash directory to DIR (default: ~/.local/share/Trash/files)\n"
		"\n"
		"Help options:\n"
		"-b,--build             display build-time parameters\n"
		"-h,--help              show this help message\n"
		"-u,--usage             display brief usage message\n"
		"-v,--version           display version and build info\n")
	);
#ifdef DEBUG_MESSAGES
	/*need separate message to allow the main message to work regardless of debug
	  mode when the .po file is created and when the program is run */
	printf (
	  _("-d,--debug=[1-5]       set debug level from 1 (low) to 5 (high)\n"
		"-x,--verbose           display time/location info in debug messages\n")
	);
#endif
}
/**
@brief print build-related message on console

@return
*/
static void _e2_cl_option_print_version (void)
{
	printf (
		_("%s v. %s\n"
		"Licensed under the GPL\n"
		"Copyright (C) %s\n"	//&#169; doesn't work
		"Build date: %s\n"
		"Build platform: GTK+ %d.%d.%d %s\n"),
		PROGNAME, VERSION RELEASE, COPYRIGHT, BUILDDATE,	//BUILDDATE may be non-utf-8
		GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION, BUILDINFO
	);
}
/**
@brief print build-time options and parameters on console

@return
*/
static void _e2_cl_option_print_build (void)
{
	gchar **split, **tmp;
	printf (PROGNAME" %s:\n", _("build parameters"));
	split = g_strsplit (BUILDOPTS, "|", -1);
	for (tmp = split; *tmp != NULL; tmp++)
	{
		if (**tmp != '\0')
			printf (" %s\n", *tmp);
	}
	g_strfreev (split);
}
/**
@brief parse commandline options and store results for later use

@param argc no. of commandline arguments, as supplied to main()
@param argv array of commanline arguments, as supplied to main()

@return
*/
void e2_cl_option_process (gint argc, gchar *argv[])
{
	gchar *freeme;
	gint c;
#ifdef DEBUG_MESSAGES
	gint d = 0;
#endif
	static struct option long_options[] =
	{
		{"one", required_argument, NULL, '1'},
		{"two", required_argument, NULL, '2'},
		{"config", required_argument, NULL, 'c'},
#ifdef DEBUG_MESSAGES
		{"debug", required_argument, NULL, 'd'},
#endif
		{"encoding", required_argument, NULL, 'e'},
		{"fallback-encoding", required_argument, NULL, 'f'},
		{"trash", required_argument, NULL, 't'},
		{"ignore-problems", no_argument, NULL, 'i'},
		{"log-all", no_argument, NULL, 'l'},
		{"daemon", no_argument, NULL, 'm'},
		{"original", no_argument, NULL, 'o'},
		{"run-at-start", required_argument, NULL, 'r'},
		{"set-option", required_argument, NULL, 's'},
#ifdef DEBUG_MESSAGES
		{"verbose", no_argument, NULL, 'x'},
#endif
		{"build", no_argument, NULL, 'b'},
		{"help", no_argument, NULL, 'h'},
		{"usage", no_argument, NULL, 'u'},
		{"version", no_argument, NULL, 'v'},
		{NULL, no_argument, NULL, 0}
	};

	//non-string non-zero-default values need to be set before the options are parsed
#ifdef DEBUG_MESSAGES
	e2_cl_options.debug_level = E2_DEBUG_LEVEL;
#endif
	//default to no logging when detailed messaging happening
	e2_cl_options.suppress_gtk_log = TRUE;	//(E2_DEBUG_LEVEL > 2);

	while (TRUE)
	{
		gint option_index = 0;
#ifdef DEBUG_MESSAGES
		c = getopt_long (argc, argv, "1:2:c:d:e:f:t:ilmor:s:xbhuv", long_options, &option_index);
#else
		c = getopt_long (argc, argv, "1:2:c:e:f:t:ilmor:s:bhuv", long_options, &option_index);
#endif
		if (c == -1) break;
#ifdef DEBUG_MESSAGES
		d++;
#endif
		if (optarg != NULL && *optarg != '\0')
		{
			gchar *convert;
			switch (c)
			{
				case '1':
					printd (DEBUG, "setting pane 1 startup path '%s'", optarg);
					//no encoding conversion yet, the arrangements are not yet in place
					e2_cl_options.pane1_path = g_strdup (optarg);
					break;
				case '2':
					printd (DEBUG, "setting pane 2 startup path '%s'", optarg);
					//no encoding conversion yet, the arrangements are not yet in place
					e2_cl_options.pane2_path = g_strdup (optarg);
					break;
				case 'c':
					g_free (e2_cl_options.config_dir);
					if (g_path_is_absolute (optarg))
//#ifdef E2_FILES_UTF8ONLY
//						convert = g_strdup (optarg);
//#else
						convert = optarg;
//#endif
					else
					{
						freeme = g_get_current_dir ();
						convert = g_build_filename (freeme, optarg, NULL);
						g_free (freeme);
					}
//#ifdef E2_FILES_UTF8ONLY
//					e2_cl_options.config_dir = convert;
//#else
					e2_cl_options.config_dir = e2_utf8_filename_from_locale (convert);
					if (convert != optarg)
						g_free (convert);
//#endif
					printd (DEBUG, "setting config directory '%s'", e2_cl_options.config_dir);
					break;
#ifdef DEBUG_MESSAGES
				case 'd':
					printd (DEBUG, "setting debug level '%s'", optarg);
					{
						gchar *end;
						e2_cl_options.debug_level = g_ascii_strtoull (optarg, &end, 10);
						if (end == optarg)
						{
							e2_cl_options.debug_level = E2_DEBUG_LEVEL;
							printd (WARN, "failed setting debug level '%s'", optarg);
						}
//						e2_cl_options.suppress_gtk_log =
//							(e2_cl_options.debug_level > 2);
					}
					break;
#endif
				case 'e':
					g_free (e2_cl_options.encoding);
					e2_cl_options.encoding = g_strdup (optarg);
					break;
				case 'f':
					g_free (e2_cl_options.fallback_encoding);
					e2_cl_options.fallback_encoding = g_strdup (optarg);
					break;
				case 'r':
					e2_cl_options.startup_commands = g_list_append
						(e2_cl_options.startup_commands, g_strdup (optarg));
					break;
				case 's':
					e2_cl_options.option_overrides = g_list_append
						(e2_cl_options.option_overrides, g_strdup (optarg));
					break;
				case 't':
					g_free (e2_cl_options.trash_dir);
					if (g_path_is_absolute (optarg))
//#ifdef E2_FILES_UTF8ONLY
//						convert = g_strdup (optarg);
//#else
						convert = optarg;
//#endif
					else
					{
						freeme = g_get_current_dir ();
						convert = g_build_filename (freeme, optarg, NULL);
						g_free (freeme);
					}
//#ifdef E2_FILES_UTF8ONLY
//					e2_cl_options.trash_dir = convert;
//#else
					e2_cl_options.trash_dir = e2_utf8_filename_from_locale (convert);
					if (convert != optarg)
						g_free (convert);
//#endif
					printd (DEBUG, "setting trash directory '%s'", e2_cl_options.trash_dir);
					break;
				default:
					printd (ERROR, "unknown option with code: 0%o and value: %s", c, optarg);
					break;
			}
		}
		else	//no argument, or blank
		{
			switch (c)
			{
				case 'i':
					e2_cl_options.ignore_problems = TRUE;
					break;
				case 'l':
					e2_cl_options.suppress_gtk_log = FALSE;
				case 'm':
					e2_cl_options.detached = TRUE;
					break;
				case 'o':
					e2_cl_options.original = TRUE;
					break;
#ifdef DEBUG_MESSAGES
				case 'x':
					e2_cl_options.verbose = TRUE;
					break;
#endif
				case 'b':
					_e2_cl_option_print_build ();
					exit (0);
					break;
				case 'u':
					_e2_cl_option_print_usage ();
					exit (0);
					break;
				case 'h':
					_e2_cl_option_print_help ();
					exit (0);
					break;
				case 'v':
					_e2_cl_option_print_version ();
					exit (0);
					break;
				case '?':
					printd (ERROR, "unknown option");
//ignore			exit (0);
					break;
				default:
					printd (ERROR, "unknown option with code: 0%o", c);
					break;
			}
		}
	}

	if (optind < argc)
	{
		printf (_("Startup options must begin with \"-\" or \"--\"\n"));
		exit (0);	//FIXME do a clean exit
	}
	printd (DEBUG, "parsed %d command line options", d);

	//now we setup any missing default strings
	gboolean subdir;
	const gchar *usedir;
	const gchar *homedir = g_getenv ("HOME");
	if (e2_cl_options.config_dir != NULL && *e2_cl_options.config_dir != '\0')
	{
		usedir = e2_cl_options.config_dir;
		subdir = FALSE;
	}
	else
	{
		usedir = g_getenv ("XDG_CONFIG_HOME");
		if (usedir == NULL || *usedir == '\0')
			usedir = g_get_user_config_dir ();
		subdir = TRUE;
	}
	//check dir is suitable (su etc may not adjust variable)
	if (usedir != NULL && *usedir != '\0')
	{
		if (homedir != NULL && *homedir != '\0')
		{
			if (!g_str_has_prefix (usedir, homedir))
				usedir = NULL;
		}
		else
			usedir = NULL;
	}
	if (usedir == NULL || *usedir == '\0')
		freeme = g_build_filename (g_get_home_dir (), ".config", BINNAME, NULL);
	else if (subdir)
		freeme = g_build_filename (usedir, BINNAME, NULL);
	else
		freeme = (gchar*)usedir;

	g_free (e2_cl_options.config_dir); //if any
//#ifdef E2_FILES_UTF8ONLY
//	e2_cl_options.config_dir = freeme;
//#else
	e2_cl_options.config_dir = e2_utf8_filename_from_locale (freeme);
	if (freeme != usedir)
		g_free (freeme);
//#endif

	//setup local default trash dir (any others done elsewhere)
	if (e2_cl_options.trash_dir != NULL && *e2_cl_options.trash_dir != '\0')
		usedir = e2_cl_options.trash_dir;
	else
	{
		usedir = g_getenv ("XDG_DATA_HOME");
		if (usedir == NULL || *usedir == '\0')
			usedir = g_get_user_data_dir ();
	}

	if (usedir != NULL && *usedir != '\0')
	{
		if (homedir != NULL && *homedir != '\0')
		{
			if (!g_str_has_prefix (usedir, homedir))
				usedir = NULL;
		}
		else
			usedir = NULL;
	}
	if (usedir == NULL || *usedir == '\0')
		freeme = g_build_filename (g_get_home_dir (), ".local", "share", "Trash", NULL);
	else
		freeme = g_build_filename (usedir, "Trash", NULL);

	g_free (e2_cl_options.trash_dir); //if any
//#ifdef E2_FILES_UTF8ONLY
//	e2_cl_options.trash_dir = freeme;
//#else
	e2_cl_options.trash_dir = e2_utf8_filename_from_locale (freeme);
	g_free (freeme);
//#endif

	const gchar **encodings;
	g_get_filename_charsets (&encodings);
	if (e2_cl_options.encoding == NULL)
	{
		if (encodings[0] != NULL && *encodings[0] != '\0')
			e2_cl_options.encoding = g_strdup (encodings[0]);
		else
			e2_cl_options.encoding = g_strdup ("ISO-8859-15");
	}
	if (e2_cl_options.fallback_encoding == NULL)
	{
		if (encodings[1] != NULL && *encodings[1] != '\0')
			e2_cl_options.fallback_encoding = g_strdup (encodings[1]);
		else if (strcmp (e2_cl_options.encoding,"ISO-8859-1") == 0
			  || strcmp (e2_cl_options.encoding,"ISO-8859-15") == 0)
			e2_cl_options.fallback_encoding = g_strdup ("C");
		else
			e2_cl_options.fallback_encoding = g_strdup ("ISO-8859-15");
	}
}
