/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - GUI
 *  Copyright (C) 2020,2022 Tibor 'Igor2' Palinkas
 *  (copied from camv-rnd by the author)
 *
 *  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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html
 *    mailing list: http://www.repo.hu/projects/sch-rnd/contact.html
 */

#include <libcschem/config.h>

#include <librnd/core/config.h>

#include <string.h>

#include <librnd/core/event.h>
#include <librnd/core/actions.h>
#include <librnd/core/hidlib.h>
#include <librnd/core/rnd_conf.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/compat_fs.h>
#include <librnd/core/globalconst.h>
#include <librnd/core/conf_hid.h>
#include <librnd/hid/tool.h>
#include <librnd/core/plugins.h>
#include <librnd/plugins/lib_hid_common/toolbar.h>
#include <librnd/plugins/lib_hid_common/dlg_export.h>

#include <libcschem/search.h>
#include <libcschem/event.h>
#include <libcschem/plug_io.h>
#include <sch-rnd/draw.h>
#include <sch-rnd/search.h>
#include <sch-rnd/funchash_core.h>
#include <sch-rnd/multi.h>
#include <sch-rnd/sheet.h>
#include <sch-rnd/export.h>

#include "layersel.h"
#include "sheetsel.h"
#include "act.h"
#include "status.h"

#include "infobar.c"
#include "title.c"

static const char *layersel_cookie = "sch_rnd_gui/layersel";
static const char *sheetsel_cookie = "sch_rnd_gui/sheetsel";
static const char *status_cookie = "sch_rnd_gui/status";
static const char *infobar_cookie = "sch_rnd_gui/infobar";
static const char *sch_rnd_gui_cookie = "sch_rnd_gui";
static const char *title_cookie = "lib_hid_pcbui/title";

static void sch_dwg_area_edit_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	csch_sheet_t *sheet = (csch_sheet_t *)hidlib;

	if (sheet->bbox_changed) {
		rnd_coord_t x1, y1, x2, y2;
		rnd_coord_t min_x = sch_rnd_sheet_attr_crd(sheet, "drawing_min_width", 0);
		rnd_coord_t min_y = sch_rnd_sheet_attr_crd(sheet, "drawing_min_height", 0);

		sheet->bbox_changed = 0;


		x1 = C2P(sheet->bbox.x1);
		y1 = C2P(sheet->bbox.y1);
		x2 = C2P(RND_MAX(min_x, sheet->bbox.x2));
		y2 = C2P(RND_MAX(min_y, sheet->bbox.y2));

		if ((sheet->hidlib.dwg.X1 == x1) && (sheet->hidlib.dwg.Y1 == y1) && (sheet->hidlib.dwg.X2 == x2) && (sheet->hidlib.dwg.Y2 == y2))
			return;

		sch_rnd_sheet_warn_size(sheet, sheet->bbox.x1, sheet->bbox.y1, RND_MAX(min_x, sheet->bbox.x2), RND_MAX(min_y, sheet->bbox.y2));

		sheet->hidlib.dwg.X1 = x1;
		sheet->hidlib.dwg.Y1 = y1;
		sheet->hidlib.dwg.X2 = x2;
		sheet->hidlib.dwg.Y2 = y2;
	}
}


#define NOGUI() \
do { \
	if ((rnd_gui == NULL) || (!rnd_gui->gui)) { \
		RND_ACT_IRES(1); \
		return 0; \
	} \
	RND_ACT_IRES(0); \
} while(0)

extern csch_chdr_t *csch_obj_clicked;

const char csch_acts_Popup[] = "Popup(MenuName, [obj-type])";
const char csch_acth_Popup[] = "Bring up the popup menu specified by MenuName, optionally modified with the object type under the cursor.\n";
fgw_error_t csch_act_Popup(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	rnd_design_t *hidlib = RND_ACT_DESIGN;
	csch_sheet_t *sheet = (csch_sheet_t *)hidlib;
	char name[256], name2[256], wnname[256];
	const char *tn = NULL, *a0, *a1 = NULL, *misc = "misc";
	int r = 1;
	enum {
		CTX_NONE,
		CTX_OBJ_TYPE
	} ctx_sens = CTX_NONE;

	NOGUI();

	if (argc != 2 && argc != 3)
		RND_ACT_FAIL(Popup);

	RND_ACT_CONVARG(1, FGW_STR, Popup, a0 = argv[1].val.str);
	RND_ACT_MAY_CONVARG(2, FGW_STR, Popup, a1 = argv[2].val.str);

	*name = '\0';
	*name2 = '\0';

	if (argc == 3) {
		if (strcmp(a1, "obj-type") == 0) ctx_sens = CTX_OBJ_TYPE;
	}

	if (strlen(a0) < sizeof(name) - 32) {
		switch(ctx_sens) {
			case CTX_OBJ_TYPE:
				{
					rnd_coord_t x, y;
					csch_chdr_t *obj;

					rnd_hid_get_coords("context sensitive popup: select object", &x, &y, 0);
					x = rnd_grid_fit(x, hidlib->grid, hidlib->grid_ox);
					y = rnd_grid_fit(y, hidlib->grid, hidlib->grid_oy);
					obj = sch_rnd_search_first_gui_inspect(sheet, x, y);
					if (obj == NULL) {
						if (rnd_point_in_box(&hidlib->dwg, x, y)) {
							if (sheet->is_symbol)
								strcpy(name, "/popups/symbol-as-sheet");
							else
								strcpy(name, "/popups/sheet");
							misc = "none";
						}
						else
							tn = "none";
					}
					else if (csch_obj_is_grp(obj)) {
						csch_cgrp_t *grp = (csch_cgrp_t *)obj;
						if (grp->srole != NULL) {
							tn = ((csch_cgrp_t *)obj)->srole;
							misc = "unknown-grp";
						}
						else {
							const char *purp = csch_attrib_get_str(&grp->attr, "purpose");
							if (purp == NULL)
								purp = "unknown";
							rnd_snprintf(name, sizeof(name2), "/popups/%s-user-grp-%s", a0, purp);
							misc = "user-grp-unknown";
						}
					}
					else {
						if (obj->parent->role == CSCH_ROLE_WIRE_NET) {
							sprintf(wnname, "wire-net-%s", csch_ctype_name(obj->type));
							tn = wnname;
							misc = "wire-net";
						}
						else
							tn = csch_ctype_name(obj->type);
					}

					if (*name == '\0')
						rnd_snprintf(name, sizeof(name), "/popups/%s-%s", a0, tn);
					rnd_snprintf(name2, sizeof(name2), "/popups/%s-%s", a0, misc);
					csch_obj_clicked = obj;
				}
				break;
			case CTX_NONE:
				sprintf(name, "/popups/%s", a0);
				break;
				
		}
	}

rnd_trace("popup: name=%s name2=%s\n", name, name2);
	if (*name != '\0')
		r = rnd_gui->open_popup(rnd_gui, name);
	if ((r != 0) && (*name2 != '\0'))
		r = rnd_gui->open_popup(rnd_gui, name2);

	RND_ACT_IRES(r);
	return 0;
}

static char *dup_cwd(void)
{
	char tmp[RND_PATH_MAX + 1];
	return rnd_strdup(rnd_get_wd(tmp));
}

static const char csch_acts_Load[] = "Load()\n" "Load(Project|Sheet)";
static const char csch_acth_Load[] = "Load a project or a schematics sheet from a user-selected file.";
static fgw_error_t csch_act_Load(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	static char *last_project = NULL, *last_layer = NULL;
	const char *function = "Sheet";
	char *name = NULL;
	rnd_design_t *hl = RND_ACT_DESIGN;
	static const char *flt_any[] = {"*", "*.*", NULL};

	if (last_layer == NULL)     last_layer = dup_cwd();
	if (last_project == NULL)   last_project = dup_cwd();

TODO("loadfrom action");
#if 0
	/* Called with both function and file name -> no gui */
	if (argc > 2)
		return RND_ACT_CALL_C(csch_act_LoadFrom, res, argc, argv);
#else
	if (argc > 2)
		return -1;
#endif

	RND_ACT_MAY_CONVARG(1, FGW_STR, Load, function = argv[1].val.str);

	if (rnd_strcasecmp(function, "Sheet") == 0) {
		int n, di, rem;
		static const char *pat_lht[] = {"*.rs", "*.lht", NULL};
		static const char *pat_tdx[] = {"*.tdx", NULL};
		char name_tmp[32][32];
		char ext_tmp[32][32];
		char *pat_tmp[32][2];
		rnd_hid_fsd_filter_t flt[32];
		static const rnd_hid_fsd_filter_t flt1[] = {
			{"lihata", "lihata", pat_lht},
			{"tEDAx", "tEDAx", pat_tdx},
		};
		static const rnd_hid_fsd_filter_t  flt2[] = {
			{"all",    NULL, flt_any},
			{NULL, NULL, NULL}
		};

		di = sizeof(flt1)/sizeof(flt1[0]);
		rem = sizeof(flt)/sizeof(flt[0]) - di - sizeof(flt2)/sizeof(flt2[0]);
		memcpy(flt, flt1, sizeof(flt1));

		for(n = 0; (n < csch_ios.used) && (rem > 0); n++) {
			char *sep, *ext;
			int namelen;
			csch_plug_io_t *io = csch_ios.array[n];

			if (io->load_sheet == NULL) continue;

			/* generate name */
			sep = strchr(io->name, ' ');
			if (sep != NULL) {
				namelen = sep - io->name;
				if (namelen > 31)
					namelen = 31;
			}
			else
				namelen = 31;
			strncpy(name_tmp[di], io->name, namelen);
			(name_tmp[di])[namelen] = '\0';

			if (strcmp(name_tmp[di], "lihata") == 0) continue;
			if (strcmp(name_tmp[di], "tEDAx") == 0) continue;

			/* generate pattern */
			ext = ext_tmp[di];
			ext[0] = '*'; ext[1] = '.';
			strncpy(ext+2, io->ext_save_sheet, 29);
			ext[31] = '\0';
			(pat_tmp[di])[0] = ext;
			(pat_tmp[di])[1] = NULL;

			flt[di].name = name_tmp[di];
			flt[di].mime = name_tmp[di];
			flt[di].pat = (const char **)pat_tmp[di];

			rem--;
			di++;
		}
		memcpy(flt+di, flt2, sizeof(flt2));

		name = rnd_hid_fileselect(rnd_gui, "Load sheet", "Import a sheet from file", last_layer, ".rs", flt, "sheet", RND_HID_FSD_READ, NULL);
	}
	else if (rnd_strcasecmp(function, "Project") == 0) {
		static const char *pat_prj[] = {"project.lht", NULL};
		static const rnd_hid_fsd_filter_t flt[] = {
			{"Project", "Project", pat_prj},
			{"all",    NULL, flt_any},
			{NULL, NULL, NULL}
		};
		name = rnd_hid_fileselect(rnd_gui, "Load a project file", "load project (all layers) from file", last_project, ".lht", flt, "project", RND_HID_FSD_READ, NULL);
	}
	else {
		rnd_message(RND_MSG_ERROR, "Invalid subcommand for Load(): '%s'\n", function);
		RND_ACT_IRES(1);
		return 0;
	}

	if (name != NULL) {
		if (rnd_conf.rc.verbose)
			fprintf(stderr, "Load:  Calling LoadFrom(%s, %s)\n", function, name);
		rnd_actionva(hl, "LoadFrom", function, name, NULL);
		free(name);
	}

	RND_ACT_IRES(0);
	return 0;
}

static int save_as(rnd_design_t *hl, int what, int as, const char *name)
{
	csch_sheet_t *sheet = (csch_sheet_t *)hl;
	const char *prev_fn, *whats, *prev_loadfn;
	char *free_me = NULL, *free_me2 = NULL;
	int need_fsd, save_res = -1;
	int append_rs = 0;

	if ((hl->fullpath != NULL) && (hl->fullpath[0] == '<')) {
		as = 1; /* force save-as on <none> */
		append_rs = 1;
	}

	/* figure previous file name and whether we need to invoke FSD */
	if (as) {
		if (name == NULL) {
			prev_fn = sheet->hidlib.fullpath;
			if (prev_fn == NULL)
				prev_fn = free_me = dup_cwd();
			prev_loadfn = sheet->hidlib.loadname;
			if (prev_loadfn == NULL)
				prev_loadfn = prev_fn;
			need_fsd = 1;
		}
		else {
			prev_fn = name;
			need_fsd = 0;
		}
	}
	else {
		prev_fn = name = sheet->hidlib.fullpath;
		if (name == NULL) {
			prev_fn = free_me = dup_cwd();
			need_fsd = 1;
		}
		else
			need_fsd = 0;

		prev_loadfn = sheet->hidlib.loadname;
		if (prev_loadfn == NULL)
			prev_loadfn = prev_fn;
	}

	if (append_rs)
		prev_loadfn = free_me2 = rnd_concat(prev_loadfn, ".rs", NULL);

	/* invoke FSD if needed */
	switch(what) {
		case F_Sheet:
			if (need_fsd)
				name = rnd_hid_fileselect(rnd_gui, "Save sheet", "Save a sheet to file", prev_loadfn, ".rs", NULL, "sheet", 0, NULL);
			whats = "sheet";
			break;
		case F_Project:
			if (need_fsd)
				name = rnd_hid_fileselect(rnd_gui, "Save a project file", "save project (all layers) to file", prev_loadfn, ".lht", NULL, "project", 0, NULL);
			whats = "project";
			break;
		default:
			rnd_message(RND_MSG_ERROR, "Invalid first argument for Save() or SaveAs()\n");
			goto error;
	}

	if (name != NULL) { /* NULL means cancel */
		if (rnd_conf.rc.verbose)
			fprintf(stderr, "Save:  Calling SaveTo(%s, %s)\n", whats, name);
		save_res = rnd_actionva(hl, "SaveTo", whats, name, NULL);
	}
	else if (rnd_conf.rc.verbose)
		fprintf(stderr, "Save: SaveTo(%s, ...) cancelled\n", whats);

	free(free_me);
	free(free_me2);
	return save_res;

	error:;
	free(free_me);
	free(free_me2);
	return 1;
}

static const char csch_acts_Save[] = "Save()\n" "Save(Project|Sheet)";
static const char csch_acth_Save[] = "Save a project or a schmeatics sheet trying to preserve original file name.";
static const char csch_acts_SaveAs[] = "SaveAs(Project|Sheet, [filename])";
static const char csch_acth_SaveAs[] = "Save a project or a schmeatics sheet using a new file name.";
static fgw_error_t csch_act_Save(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	rnd_design_t *hl = RND_ACT_DESIGN;
	const char *actname = argv[0].val.func->name;
	int as = (actname[4] == 'a') || (actname[4] == 'A');
	int what = F_Sheet;
	const char *name = NULL;

	if (as) {
		RND_ACT_MAY_CONVARG(1, FGW_KEYWORD, SaveAs, what = fgw_keyword(&argv[1]));
		RND_ACT_MAY_CONVARG(2, FGW_STR, SaveAs, name = argv[2].val.cstr);
	}
	else
		RND_ACT_MAY_CONVARG(1, FGW_KEYWORD, SaveAs, what = fgw_keyword(&argv[1]));

	RND_ACT_IRES(save_as(hl, what, as, name));
	return 0;
}

static const char csch_acts_SwitchRelative[] = "SwitchRelative(steps)\n";
static const char csch_acth_SwitchRelative[] = "Switch to a different sheet by traversing integer steps on the linked list of sheets loaded";
static fgw_error_t csch_act_SwitchRelative(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	int step;

	RND_ACT_MAY_CONVARG(1, FGW_INT, SwitchRelative, step = argv[1].val.nat_int);
	sch_rnd_multi_switch_to_delta(NULL, step);
	RND_ACT_IRES(0);
	return 0;
}

const char csch_acts_ExportProjectDialog[] = "ExportDialog()\n";
const char csch_acth_ExportProjectDialog[] = "Open the export dialog for exporting the project (all sheets of the project).";
fgw_error_t csch_act_ExportProjectDialog(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	static sch_rnd_export_appspec_t appspec = {0};

	appspec.exp_prj = 1;
	rnd_dlg_export("Export project to file(s)", 1, 0, RND_ACT_DESIGN, &appspec);
	return 0;
}


#include "edit_act.c"

static rnd_action_t sch_rnd_gui_action_list[] = {
	{"Load", csch_act_Load, csch_acth_Load, csch_acts_Load},
	{"Save", csch_act_Save, csch_acth_Save, csch_acts_Save},
	{"SaveAs", csch_act_Save, csch_acth_SaveAs, csch_acts_SaveAs},
	{"Zoom", csch_act_Zoom, csch_acth_Zoom, csch_acts_Zoom_},
	{"ZoomTo", csch_act_Zoom, csch_acth_Zoom, csch_acts_Zoom_},
	{"SwitchRelative", csch_act_SwitchRelative, csch_acth_SwitchRelative, csch_acts_SwitchRelative},
	EDIT_ACTS
	{"Popup", csch_act_Popup, csch_acth_Popup, csch_acts_Popup},
	{"StatusSetText", csch_act_StatusSetText, csch_acth_StatusSetText, csch_acts_StatusSetText},
	{"ExportProjectDialog", csch_act_ExportProjectDialog, csch_acth_ExportProjectDialog, csch_acts_ExportProjectDialog},
};

int pplg_check_ver_gui(int ver_needed) { return 0; }

void pplg_uninit_gui(void)
{
	rnd_toolbar_uninit();
	rnd_event_unbind_allcookie(infobar_cookie);
	rnd_event_unbind_allcookie(layersel_cookie);
	rnd_event_unbind_allcookie(sheetsel_cookie);
	rnd_event_unbind_allcookie(status_cookie);
	rnd_event_unbind_allcookie(title_cookie);
	rnd_remove_actions_by_cookie(sch_rnd_gui_cookie);
	rnd_conf_hid_unreg(status_cookie);
	rnd_conf_hid_unreg(infobar_cookie);
}

static void gui_conf_val_change_post(rnd_conf_native_t *cfg, int arr_idx, void *user_data)
{
	if (strncmp(cfg->hash_path, "editor/style/tool", 17) == 0) {
		/* re-activate current tool to get this applied */
		rnd_tool_chg_mode(rnd_multi_get_current());
	}
}

static rnd_conf_hid_id_t install_events(const char *cookie, const char *paths[], rnd_conf_hid_callbacks_t cb[], void (*update_cb)(rnd_conf_native_t*,int,void*))
{
	const char **rp;
	rnd_conf_native_t *nat;
	int n;
	rnd_conf_hid_id_t conf_id;
	static rnd_conf_hid_callbacks_t global_cb = {0};

	global_cb.val_change_post = gui_conf_val_change_post;

	conf_id = rnd_conf_hid_reg(cookie, &global_cb);
	for(rp = paths, n = 0; *rp != NULL; rp++, n++) {
		memset(&cb[n], 0, sizeof(cb[0]));
		cb[n].val_change_post = update_cb;
		nat = rnd_conf_get_field(*rp);
		if (nat != NULL)
			rnd_conf_hid_set_cb(nat, conf_id, &cb[n]);
	}

	return conf_id;
}

int pplg_init_gui(void)
{
	const char *st_paths[] = {"editor/line_refraction", "editor/line_cont", "editor/rubber_band_mode", "editor/rubber_band_ortho", "editor/grid", NULL};
	const char *ibpaths[] = { "rc/file_changed_interval", NULL };
	static rnd_conf_hid_callbacks_t st_cb[sizeof(st_paths)/sizeof(st_paths[0])];
	static rnd_conf_hid_callbacks_t ibcb[sizeof(ibpaths)/sizeof(ibpaths[0])];

	RND_API_CHK_VER;

	rnd_event_bind(RND_EVENT_GUI_INIT, sch_rnd_sheetsel_gui_init_ev, NULL, sheetsel_cookie);
	rnd_event_bind(RND_EVENT_GUI_INIT, sch_rnd_layersel_gui_init_ev, NULL, layersel_cookie);
	rnd_event_bind(RND_EVENT_GUI_INIT, sch_status_gui_init_ev, NULL, layersel_cookie);
	rnd_event_bind(RND_EVENT_USER_INPUT_KEY, sch_status_st_update_ev, NULL, status_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_SET_CURRENT, sch_status_st_update_ev, NULL, status_cookie);
	rnd_event_bind(CSCH_EVENT_SHEET_POSTLOAD, sch_status_postload_ev, NULL, status_cookie);
	rnd_event_bind(RND_EVENT_CROSSHAIR_MOVE, sch_status_rd_update_ev, NULL, status_cookie);
	rnd_event_bind(CSCH_EVENT_SHEET_EDITED, sch_status_rd_edit_ev, NULL, status_cookie);
	rnd_event_bind(CSCH_EVENT_PRJ_STANCE_CHANGED, sch_status_rd_edit_ev, NULL, status_cookie);
	rnd_event_bind(CSCH_EVENT_SHEET_EDITED, sch_dwg_area_edit_ev, NULL, status_cookie);
	rnd_event_bind(RND_EVENT_GUI_INIT, pcb_infobar_gui_init_ev, NULL, infobar_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_SET_CURRENT, pcb_infobar_brdchg_ev, NULL, infobar_cookie);
	rnd_event_bind(CSCH_EVENT_SHEET_POSTSAVE, pcb_infobar_postsave_ev, NULL, infobar_cookie);
	rnd_event_bind(CSCH_EVENT_SHEET_POSTLOAD, pcb_infobar_postload_ev, NULL, infobar_cookie);
	rnd_event_bind(CSCH_EVENT_PRJ_VIEW_ACTIVATED, sch_status_view_activated_ev, NULL, infobar_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_SET_CURRENT, sch_title_board_changed_ev, NULL, title_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_SET_CURRENT, sch_sheetsel_board_changed_ev, NULL, sheetsel_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_FN_CHANGED, sch_title_board_changed_ev, NULL, title_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_META_CHANGED, sch_title_meta_changed_ev, NULL, title_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_META_CHANGED, sch_sheetsel_meta_changed_ev, NULL, title_cookie);
	rnd_event_bind(RND_EVENT_GUI_INIT, sch_title_gui_init_ev, NULL, title_cookie);
	rnd_event_bind(RND_EVENT_LOAD_POST, sch_sheetsel_load_post_ev, NULL, sheetsel_cookie);
	rnd_event_bind(RND_EVENT_DESIGN_FN_CHANGED, sch_sheetsel_fn_changed_ev, NULL, sheetsel_cookie);
	rnd_event_bind(CSCH_EVENT_SHEET_POSTUNLOAD, sch_sheetsel_unload_post_ev, NULL, sheetsel_cookie);
	rnd_event_bind(CSCH_EVENT_LAYERVIS_CHANGED, sch_rnd_layersel_vis_chg_ev, NULL, layersel_cookie);

	RND_REGISTER_ACTIONS(sch_rnd_gui_action_list, sch_rnd_gui_cookie);

	install_events(status_cookie, st_paths, st_cb, sch_status_st_update_conf);
	install_events(infobar_cookie, ibpaths, ibcb, pcb_infobar_update_conf);

	rnd_toolbar_init();
	return 0;
}
