/*
 *                            COPYRIGHT
 *
 *  sch-rnd, interactive printed circuit board design
 *  (this file is copied from pcb-rnd, interactive printed circuit board design)
 *  Copyright (C) 1994,1995,1996 Thomas Nau
 *  Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton
 *  Copyright (C) 2020,2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  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 2 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    lead developer: http://repo.hu/projects/pcb-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 *
 *
 *  Old contact info:
 *  Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
 *  haceaton@aplcomm.jhuapl.edu
 *
 */

#define Progname "sch-rnd"

#include <libcschem/config.h>

#include <stdio.h>

#include "crosshair.h"
#include <librnd/core/compat_misc.h>
#include <librnd/core/actions.h>
#include "conf_core.h"
#include "build_run.h"
#include <librnd/core/safe_fs.h>
#include <librnd/hid/hid_init.h>
#include <libcschem/undo.h>

/* print usage lines */
RND_INLINE void u(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	fputc('\n', stderr);
	va_end(ap);
}

static const char csch_acts_PrintUsage[] =
	"PrintUsage()\n"
	"PrintUsage(plugin)";

static const char csch_acth_PrintUsage[] = "Print command line arguments of sch-rnd or a plugin loaded.";

static int help0(void)
{
	rnd_hid_t **hl = rnd_hid_enumerate();
	int i;

	u("sch-rnd - Ringdove schematics program, http://repo.hu/projects/sch-rnd");
	u("For more information, please read the topic help pages:");
	u("  %s --help topic", Progname);
	u("Topics are:");
	u("  invocation           how to run sch-rnd");
	u("  main                 main/misc flags (affecting none or all plugins)");
	for (i = 0; hl[i]; i++)
		if (hl[i]->usage != NULL)
			u("  %-20s %s", hl[i]->name, hl[i]->description);
	return 0;
}

extern const char *sch_rnd_action_args[];
extern const int PCB_ACTION_ARGS_WIDTH;
static int help_main(void) {
	const char **cs;
	for(cs = sch_rnd_action_args; cs[2] != NULL; cs += RND_ACTION_ARGS_WIDTH) {
		fprintf(stderr, "%s [", Progname);
		if (cs[0] != NULL)
			fprintf(stderr, "-%s", cs[0]);
		if ((cs[0] != NULL) && (cs[1] != NULL))
			fprintf(stderr, "|");
		if (cs[1] != NULL)
			fprintf(stderr, "-%s", cs[1]);
		fprintf(stderr, "]    %s\n", cs[3]);
	}
	return 0;
}

static int help_invoc(void)
{
	rnd_hid_t **hl = rnd_hid_enumerate();
	int i;
	int n_printer = 0, n_gui = 0, n_exporter = 0;

	u("sch-rnd invocation:");
	u("");
	u("%s [main options]                                    See --help main", Progname);
	u("");
	u("%s [generics] [--gui GUI] [gui options] <sch file>   interactive GUI", Progname);

	u("Available GUI hid%s:", n_gui == 1 ? "" : "s");
	rnd_hid_print_all_gui_plugins();

	u("\n%s [generics] -p [printing options] <sch file>\tto print", Progname);
	u("Available printing hid%s:", n_printer == 1 ? "" : "s");
	for (i = 0; hl[i]; i++)
		if (hl[i]->printer)
			fprintf(stderr, "\t%-8s %s\n", hl[i]->name, hl[i]->description);

	u("\n%s [generics] -x hid [export options] <sch file>\tto export a single sheet", Progname);
	u("%s [generics] -x hid [export options] <sch1> <sch2> ...\tto export a multi-sheet as project", Progname);
	u("%s [generics] -x hid [export options] project.lht\tto export a whole project (multi-sheet)", Progname);
	u("Available export hid%s:", n_exporter == 1 ? "" : "s");
	for (i = 0; hl[i]; i++)
		if (hl[i]->exporter)
			fprintf(stderr, "\t%-8s %s\n", hl[i]->name, hl[i]->description);


	u("\nGenerics:");
	u("-c conf/path=value        set the value of a configuration item (in RND_CFR_CLI)");
	u("-C conffile               load config file (as RND_CFR_CLI; after all -c's)");

	return 0;
}

fgw_error_t csch_act_PrintUsage(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	const char *topic = NULL, *subt = NULL;
	RND_ACT_MAY_CONVARG(1, FGW_STR, PrintUsage, topic = argv[1].val.str);
	RND_ACT_IRES(0);

	u("");
	if (topic != NULL) {
		rnd_hid_t **hl = rnd_hid_enumerate();
		int i;

		if (strcmp(topic, "invocation") == 0)  return help_invoc();
		if (strcmp(topic, "main") == 0)        return help_main();

		for (i = 0; hl[i]; i++) {
			if ((hl[i]->usage != NULL) && (strcmp(topic, hl[i]->name) == 0)) {
				RND_ACT_MAY_CONVARG(2, FGW_STR, PrintUsage, subt = argv[2].val.str);
				RND_ACT_IRES(hl[i]->usage(hl[i], subt));
				return 0;
			}
		}
		fprintf(stderr, "No help available for %s\n", topic);
		RND_ACT_IRES(-1);
		return 0;
	}
	else
		help0();
	return 0;
}


static const char csch_acts_PrintVersion[] = "PrintVersion()";
static const char csch_acth_PrintVersion[] = "Print version.";
fgw_error_t csch_act_PrintVersion(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	printf("%s\n", sch_rnd_get_info_program());
	RND_ACT_IRES(0);
	return 0;
}

static const char csch_acts_DumpVersion[] = "DumpVersion()";
static const char csch_acth_DumpVersion[] = "Dump version in script readable format.";
fgw_error_t csch_act_DumpVersion(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	printf("%s\n", CSCH_VERSION);
	printf("%s\n", CSCH_REVISION);
	RND_ACT_IRES(0);
	return 0;
}

static const char csch_acts_PrintCopyright[] = "PrintCopyright()";
static const char csch_acth_PrintCopyright[] = "Print copyright notice.";
fgw_error_t csch_act_PrintCopyright(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	printf("%s\n", sch_rnd_get_info_copyright());
	printf("%s\n", sch_rnd_get_info_license());

	printf("    This program is free software; you can redistribute it and/or modify\n"
				 "    it under the terms of the GNU General Public License as published by\n"
				 "    the Free Software Foundation; either version 2 of the License, or\n"
				 "    (at your option) any later version.\n\n");
	printf("    This program is distributed in the hope that it will be useful,\n"
				 "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
				 "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
				 "    GNU General Public License for more details.\n\n");
	printf("    You should have received a copy of the GNU General Public License\n"
				 "    along with this program; if not, write to the Free Software\n"
				 "    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n");
	RND_ACT_IRES(0);
	return 0;
}

static const char csch_acts_PrintPaths[] = "PrintPaths()";
static const char csch_acth_PrintPaths[] = "Print full paths and search paths.";
static void print_list(const rnd_conflist_t *cl)
{
	int n;
	rnd_conf_listitem_t *ci;
	const char *p;

	printf(" ");
	rnd_conf_loop_list_str(cl, ci, p, n) {
		printf("%c%s", (n == 0) ? '"' : ':', p);
	}
	printf("\"\n");
}
fgw_error_t csch_act_PrintPaths(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	htsp_entry_t *e;
	rnd_conf_fields_foreach(e) {
		rnd_conf_native_t *n = e->value;
		if ((strncmp(n->hash_path, "rc/path/", 8) == 0) && (n->type == RND_CFN_STRING) && (n->used == 1))
			printf("%-32s = %s\n", n->hash_path, n->val.string[0]);
	}
	printf("rc/font_dirs                     ="); print_list(&conf_core.rc.font_dirs);
	printf("rc/library_search_paths          ="); print_list(&conf_core.rc.library_search_paths);

	RND_ACT_IRES(0);
	return 0;
}

/* Note: this can not be in librnd because of the app-specific setenvs */
static const char csch_acts_System[] = "System(shell_cmd)";
static const char csch_acth_System[] = "Run shell command";
fgw_error_t csch_act_System(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	char tmp[128];
	const char *cmd;

	RND_ACT_CONVARG(1, FGW_STR, System, cmd = argv[1].val.str);
	RND_ACT_IRES(0);

	rnd_setenv("SCH_RND_SHEET_FILE_NAME", RND_ACT_DESIGN->fullpath == NULL ? "" : RND_ACT_DESIGN->fullpath, 1);
	rnd_snprintf(tmp, sizeof(tmp), "%rr", sch_rnd_crosshair_x);
	rnd_setenv("SCH_RND_CROSSHAIR_X", tmp, 1);
	rnd_snprintf(tmp, sizeof(tmp), "%rr", sch_rnd_crosshair_y);
	rnd_setenv("SCH_RND_CROSSHAIR_Y", tmp, 1);

	/* for compatibility with old sch-rnd versions */
	rnd_setenv("PCB_RND_SHEET_FILE_NAME", RND_ACT_DESIGN->fullpath == NULL ? "" : RND_ACT_DESIGN->fullpath, 1);
	rnd_snprintf(tmp, sizeof(tmp), "%mm", sch_rnd_crosshair_x);
	rnd_setenv("PCB_RND_CROSSHAIR_X_MM", tmp, 1);
	rnd_snprintf(tmp, sizeof(tmp), "%mm", sch_rnd_crosshair_y);
	rnd_setenv("PCB_RND_CROSSHAIR_Y_MM", tmp, 1);
	RND_ACT_IRES(rnd_system(RND_ACT_DESIGN, cmd));
	return 0;
}

static int csch_act_execute_file(rnd_design_t *hidlib, const char *fn)
{
	int res;

	res = rnd_act_execute_file(hidlib, fn);

	csch_undo_inc_serial((csch_sheet_t *)hidlib);
	rnd_gui->invalidate_all(rnd_gui);

	return res;
}

static const char csch_acts_ExecActionFile[] = "ExecActionFile(filename)";
static const char csch_acth_ExecActionFile[] = "Run actions from the given file.";
fgw_error_t csch_act_ExecActionFile(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	const char *fname;

	RND_ACT_CONVARG(1, FGW_STR, ExecActionFile, fname = argv[1].val.str);
	RND_ACT_IRES(csch_act_execute_file(RND_ACT_DESIGN, fname));
	return 0;
}

static rnd_action_t main_action_list[] = {
	{"PrintUsage", csch_act_PrintUsage, csch_acth_PrintUsage, csch_acts_PrintUsage},
	{"PrintVersion", csch_act_PrintVersion, csch_acth_PrintVersion, csch_acts_PrintVersion},
	{"DumpVersion", csch_act_DumpVersion, csch_acth_DumpVersion, csch_acts_DumpVersion},
	{"PrintCopyright", csch_act_PrintCopyright, csch_acth_PrintCopyright, csch_acts_PrintCopyright},
	{"PrintPaths", csch_act_PrintPaths, csch_acth_PrintPaths, csch_acts_PrintPaths},
	{"System", csch_act_System, csch_acth_System, csch_acts_System},
	{"ExecCommand", csch_act_System, csch_acth_System, csch_acts_System},
	{"ExecActionFile", csch_act_ExecActionFile, csch_acth_ExecActionFile, csch_acts_ExecActionFile}
};

void sch_rnd_main_act_init2(void)
{
	RND_REGISTER_ACTIONS(main_action_list, NULL);
}
