/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer
 *  Copyright (C) 2019,2020 Tibor 'Igor2' Palinkas
 *
 *  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., 31 Milk Street, # 960789 Boston, MA 02196 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/camv-rnd
 *    lead developer: http://repo.hu/projects/camv-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

#include "config.h"

#include <stdlib.h>
#include <puplug/libs.h>

/* hidlib headers */
#include <librnd/core/unit.h>
#include <librnd/hid/hid_init.h>
#include <librnd/hid/hid.h>
#include <librnd/core/conf.h>
#include <librnd/hid/buildin.hidlib.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/plugins.h>
#include <librnd/poly/polyarea.h>

/* local (app) headers */
#include "gui_act.h"
#include "data.h"
#include "plug_io.h"
#include "plug_io_act.h"
#include "conf_core.h"
#include "event.h"
#include "crosshair.h"
#include "draw.h"
#include "conf_internal.c"
#include "menu_internal.c"

#define pup_buildins camv_buildins
#include "buildin.c"
#undef pup_buildins

static const char *EXPERIMENTAL = NULL;

static const char *menu_file_paths[] = { "./", "~/" DOT_CAMV_RND "/", NULL, NULL };
static const char *menu_name_fmt = "menu.lht";

#define CONF_USER_DIR "~/" DOT_CAMV_RND

const char *rnd_conf_userdir_path = CONF_USER_DIR;
const char *rnd_conf_user_path = CONF_USER_DIR "/conf_core.lht";


extern void camv_main_act_init2(void);

static void gui_support_plugins(int load)
{
	static int loaded = 0;
	static pup_plugin_t *puphand;

	if (load && !loaded) {
		static const char *plugin_name = "gui";
		int state = 0;
		loaded = 1;
		rnd_message(RND_MSG_DEBUG, "Loading GUI support plugin: '%s'\n", plugin_name);
		puphand = pup_load(&rnd_pup, (const char **)rnd_pup_paths, plugin_name, 0, &state);
		if (puphand == NULL)
			rnd_message(RND_MSG_ERROR, "Error: failed to load GUI support plugin '%s'\n-> expect missing widgets and dialog boxes\n", plugin_name);
	}
	if (!load && loaded && (puphand != NULL)) {
		pup_unload(&rnd_pup, puphand, NULL);
		loaded = 0;
		puphand = NULL;
	}
}

/* action table number of columns for a single action */
const char *camv_action_args[] = {
/*short, -long, action, help, hint-on-error */
	NULL, "-show-actions",    "PrintActions()",     "Print all available actions (human readable) and exit",   NULL,
	NULL, "-dump-actions",    "DumpActions()",      "Print all available actions (script readable) and exit",  NULL,
	NULL, "-dump-plugins",    "DumpPlugins()",      "Print all available plugins (script readable) and exit",  NULL,
	NULL, "-dump-plugindirs", "DumpPluginDirs()",   "Print directories plugins might be loaded from and exit", NULL,
	NULL, "-show-paths",      "PrintPaths()",       "Print all configured paths and exit",                     NULL,
	"V",  "-version",         "PrintVersion()",     "Print version info and exit",                             NULL,
	"V",  "-dump-version",    "DumpVersion()",      "Print version info in script readable format and exit",   NULL,
	NULL, "-copyright",       "PrintCopyright()",   "Print copyright and exit",                                NULL,
	NULL, NULL, NULL, NULL, NULL /* terminator */
};

void camv_main_uninit(void)
{
	gui_support_plugins(0);
	camv_design_free_fields(&camv);
	camv_plug_io_act_uninit();
	rnd_hidlib_uninit(); /* plugin unload */
}

void camv_font_init(void);

static void camv_main_init(void)
{
	camv.lysel = -1;
	camv_font_init();
}

static void camv_main_init_actions()
{
	camv_plug_io_act_init();
	camv_main_act_init2();
	gui_act_init();
}


#ifdef RND_WANT_FLOATING_FHS
	char *camv_floating_confdir;
#endif

int main(int argc, char *argv[])
{
	int n;
	rnd_main_args_t ga;
	char *exec_prefix;
	vtp0_t startscripts = {0};

	rnd_app.package = "camv-rnd";
	rnd_app.version = CAMV_VERS;
	rnd_app.url = "http://www.repo.hu/projects/camv-rnd";
	rnd_app.multi_design = 0;
	rnd_app.menu_file_paths = menu_file_paths;
	rnd_app.menu_name_fmt   = menu_name_fmt;
	rnd_app.default_embedded_menu = camv_menu_internal;
	menu_file_paths[2] = rnd_concat(CONFDIR, "/", NULL);


#ifdef RND_WANT_FLOATING_FHS
	TODO("This ignores ./configure --confdir; the code is in librnd trunk/src/librnd/scconfig/hooks_common.h, search for ''set up confdir'' -> should save a variant usable here, without prefix");
	camv_floating_confdir = rnd_concat(rnd_w32_root, "/etc/camv-rnd", NULL);
	rnd_app.conf_sys_path = rnd_concat(CONFDIR, "/conf_core.lht", NULL);
#else
	rnd_app.conf_sys_path = CONFDIR "/conf_core.lht";
#endif


	rnd_app.conf_internal = camv_conf_internal;
	rnd_app.conf_sysdir_path = CONFDIR;
	rnd_app.conf_userdir_path = CONF_USER_DIR;
	rnd_app.conf_user_path = CONF_USER_DIR "/conf_core.lht";

	rnd_app.crosshair_move_to = camv_hidlib_crosshair_move_to;
	rnd_app.draw_attached = camv_draw_attached;
	rnd_app.expose_main = camv_expose_main;
	rnd_app.expose_preview = camv_expose_preview;

	rnd_app.dot_dir = DOT_CAMV_RND;
	rnd_app.lib_dir = LIBDIR;

	rnd_fix_locale_and_env();

	rnd_main_args_init(&ga, argc, camv_action_args);

	exec_prefix = rnd_exec_prefix(argv[0], BINDIR, BINDIR_TO_EXECPREFIX);
	rnd_hidlib_init1(conf_core_init, exec_prefix);
	free(exec_prefix);

	camv_event_init_app();
	for(n = 1; n < argc; n++) {
		if (strcmp(argv[n], "-s") == 0) {
			n++;
			vtp0_append(&startscripts, argv[n]);
		}
		else
			n += rnd_main_args_add(&ga, argv[n], argv[n+1]);
	}

	rnd_hidlib_init2(pup_buildins, camv_buildins);
	rnd_hidlib_init3_auto();

	camv_main_init();
	rnd_conf_set(RND_CFR_DESIGN, "editor/view/flip_y", 0, "1", RND_POL_OVERWRITE);

	if (rnd_main_args_setup1(&ga) != 0) {
		camv_main_uninit();
		rnd_main_args_uninit(&ga);
		exit(1);
	}

/* Initialize actions only when the gui is already known so only the right
   one is registered (there can be only one GUI). */
	camv_main_init_actions();

	if (rnd_main_args_setup2(&ga, &n) != 0) {
		camv_main_uninit();
		rnd_main_args_uninit(&ga);
		exit(n);
	}

	/* load files listed on command line, as a group, to keep their order from top to bottom */
	camv_group_load_begin(&camv);
	for(n = 0; ga.hid_argc > 0; n++, ga.hid_argc--) {
		if (camv_io_load(&camv, ga.hid_argv[n]) != 0) {
			rnd_message(RND_MSG_ERROR, "Can not load file '%s' (specified on command line) for exporting or printing\n", ga.hid_argv[n]);
			rnd_log_print_uninit_errs("Export load error");
			if (conf_core.rc.error_on_bad_cli_files)
				exit(1);
		}
	}
	camv_group_load_end(&camv);

	for(n = 0; n < startscripts.used; n++) {
		const char *fn = startscripts.array[n];
		if (rnd_act_execute_file(&camv.hidlib, fn) != 0) {
			rnd_message(RND_MSG_ERROR, "Failed to execute start-script '%s'\n", fn);
			rnd_log_print_uninit_errs("Start-script failure");
			exit(1);
		}
	}

	if (rnd_main_exported(&ga, &camv.hidlib, camv_is_empty(&camv), NULL)) {
		camv_main_uninit();
		rnd_main_args_uninit(&ga);
		exit(0);
	}

	camv_crosshair_gui_init();

	/* main loop */
	if (RND_HAVE_GUI_ATTR_DLG)
		gui_support_plugins(1);
	if (EXPERIMENTAL != NULL) {
		rnd_message(RND_MSG_ERROR, "******************************** IMPORTANT ********************************\n");
		rnd_message(RND_MSG_ERROR, "This revision of camv-rnd is experimental, unstable, do NOT attempt to use\n");
		rnd_message(RND_MSG_ERROR, "it for production. The reason for this state is:\n");
		rnd_message(RND_MSG_ERROR, "%s\n", EXPERIMENTAL);
		rnd_message(RND_MSG_ERROR, "******************************** IMPORTANT ********************************\n");
	}
	rnd_mainloop_interactive(&ga, &camv.hidlib);

	camv_crosshair_gui_uninit();
	camv_main_uninit();
	rnd_main_args_uninit(&ga);

	{ /* make sure -lrnd-poly really includes it */
		rnd_pline_t pl;
		rnd_vnode_t v;
		pl.head = &v;
		rnd_poly_contour_init(&pl);
	}

	return 0;
}
