/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer
 *  Copyright (C) 2020 Tibor 'Igor2' Palinkas
 *  (based on pcb-rnd by the same 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., 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 <librnd/core/config.h>

#include <genvector/gds_char.h>

#include <librnd/hid/hid.h>
#include <librnd/hid/hid_cfg_input.h>
#include <librnd/hid/hid_dad.h>
#include <librnd/core/rnd_conf.h>
#include <librnd/plugins/lib_hid_common/xpm.h>
#include "data.h"
#include "conf_core.h"
#include "crosshair.h"

#include "status.h"

#define COMPACT 1


typedef struct {
	rnd_hid_dad_subdialog_t stsub, rdsub; /* st is for the bottom status line, rd is for the top readouts */
	int stsub_inited, rdsub_inited;
	int wst1, wsttxt;
	int st_has_text;
	int wrdunit, wrd2[2];
	gds_t buf; /* save on allocation */
	int lock;
	const rnd_unit_t *last_unit;
} status_ctx_t;

static status_ctx_t status;

static void build_st_line1(void)
{
	char kbd[128];
	rnd_hid_cfg_keys_t *kst = rnd_gui->key_state;

	if (kst != NULL) {
		if (kst->seq_len_action > 0) {
			int len;
			memcpy(kbd, "(last: ", 7);
			len = rnd_hid_cfg_keys_seq(kst, kbd+7, sizeof(kbd)-9);
			memcpy(kbd+len+7, ")", 2);
		}
		else
			rnd_hid_cfg_keys_seq(kst, kbd, sizeof(kbd));
	}
	else
		*kbd = '\0';


	rnd_append_printf(&status.buf,
	"%m+ "
	"grid=%$mS  "
	"kbd=%s view: %s",
	rnd_conf.editor.grid_unit->allow,
	camv.hidlib.grid,
	kbd, ((rnd_conf.editor.view.flip_x ^ rnd_conf.editor.view.flip_y) ? "top" : "bottom"));
}

static void build_st_help(void)
{
	static const rnd_unit_t *unit_mm = NULL, *unit_mil;
	const rnd_unit_t *unit_inv;

	if (unit_mm == NULL) { /* cache mm and mil units to save on the lookups */
		unit_mm  = rnd_get_unit_struct("mm");
		unit_mil = rnd_get_unit_struct("mil");
	}
	if (rnd_conf.editor.grid_unit == unit_mm)
		unit_inv = unit_mil;
	else
		unit_inv = unit_mm;

	rnd_append_printf(&status.buf,
		"%m+"
		"grid=%$mS\n"
		"looking from the %s",
		unit_inv->allow,
		camv.hidlib.grid,
		((rnd_conf.editor.view.flip_x ^ rnd_conf.editor.view.flip_y) ? "top" : "bottom")
		);
}


static void status_st_view2dlg(void)
{
	static rnd_hid_attr_val_t hv;

	if (!status.stsub_inited)
		return;

	status.buf.used = 0;
	build_st_line1();
	hv.str = status.buf.array;
	rnd_gui->attr_dlg_set_value(status.stsub.dlg_hid_ctx, status.wst1, &hv);

	status.buf.used = 0;
	build_st_help();
	rnd_gui->attr_dlg_set_help(status.stsub.dlg_hid_ctx, status.wst1, status.buf.array);
}

static void status_rd_view2dlg(void)
{
	static rnd_hid_attr_val_t hv;

	if ((status.lock) || (!status.rdsub_inited))
		return;

	/* coordinate readout (right side box) */
	if (COMPACT) {
		status.buf.used = 0;
		rnd_append_printf(&status.buf, "%m+%-mS", rnd_conf.editor.grid_unit->allow, camv.crosshair_x);
		hv.str = status.buf.array;
		rnd_gui->attr_dlg_set_value(status.rdsub.dlg_hid_ctx, status.wrd2[0], &hv);

		status.buf.used = 0;
		rnd_append_printf(&status.buf, "%m+%-mS", rnd_conf.editor.grid_unit->allow, camv.crosshair_y);
		hv.str = status.buf.array;
		rnd_gui->attr_dlg_set_value(status.rdsub.dlg_hid_ctx, status.wrd2[1], &hv);
		rnd_gui->attr_dlg_widget_hide(status.rdsub.dlg_hid_ctx, status.wrd2[1], 0);
	}
	else {
		status.buf.used = 0;
		rnd_append_printf(&status.buf, "%m+%-mS %-mS", rnd_conf.editor.grid_unit->allow, camv.crosshair_x, camv.crosshair_y);
		hv.str = status.buf.array;
		rnd_gui->attr_dlg_set_value(status.rdsub.dlg_hid_ctx, status.wrd2[0], &hv);
		rnd_gui->attr_dlg_widget_hide(status.rdsub.dlg_hid_ctx, status.wrd2[1], 1);
	}

	if (status.last_unit != rnd_conf.editor.grid_unit) {
		status.lock++;
		status.last_unit = rnd_conf.editor.grid_unit;
		hv.str = rnd_conf.editor.grid_unit->suffix;
		rnd_gui->attr_dlg_set_value(status.rdsub.dlg_hid_ctx, status.wrdunit, &hv);
		status.lock--;
	}
}

static void unit_change_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	if (rnd_conf.editor.grid_unit == rnd_get_unit_struct("mm"))
		rnd_actionva(&camv.hidlib, "SetUnits", "mil", NULL);
	else
		rnd_actionva(&camv.hidlib, "SetUnits", "mm", NULL);

	status_rd_view2dlg();
}

static void status_docked_create_st()
{
	RND_DAD_BEGIN_VBOX(status.stsub.dlg);
		RND_DAD_COMPFLAG(status.stsub.dlg, RND_HATF_EXPFILL | RND_HATF_TIGHT);
		RND_DAD_LABEL(status.stsub.dlg, "");
			RND_DAD_COMPFLAG(status.stsub.dlg, RND_HATF_HIDE);
			status.wsttxt = RND_DAD_CURRENT(status.stsub.dlg);
		RND_DAD_LABEL(status.stsub.dlg, "<pending update>");
			status.wst1 = RND_DAD_CURRENT(status.stsub.dlg);
	RND_DAD_END(status.stsub.dlg);
}

/* append an expand-vbox to eat up excess space for center-align */
static void vpad(rnd_hid_dad_subdialog_t *sub)
{
	RND_DAD_BEGIN_VBOX(sub->dlg);
		RND_DAD_COMPFLAG(sub->dlg, RND_HATF_EXPFILL | RND_HATF_TIGHT);
	RND_DAD_END(sub->dlg);
}

static void btn_support_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	rnd_actionva(&camv.hidlib, "irc", NULL);
}

static void status_docked_create_rd(rnd_design_t *hidlib)
{
	const char *xpm_ = "", **support_icon = &xpm_;
	fgw_arg_t res, args[2];
	int n;

	/* fetch the xpm using the action API so the plugin doesn't start depending on GUI plugins */
	args[1].type = FGW_STR;
	args[1].val.str = "online_help";
	if ((rnd_actionv_bin(hidlib, "rnd_dlg_xpm_by_name", &res, 2, args) == 0) && (res.type == FGW_PTR))
		support_icon = res.val.ptr_void;

	RND_DAD_BEGIN_HBOX(status.rdsub.dlg);
		RND_DAD_COMPFLAG(status.rdsub.dlg, RND_HATF_TIGHT);
		RND_DAD_PICBUTTON(status.rdsub.dlg, support_icon);
			RND_DAD_CHANGE_CB(status.rdsub.dlg, btn_support_cb);
		RND_DAD_BEGIN_VBOX(status.rdsub.dlg);
			RND_DAD_COMPFLAG(status.rdsub.dlg, RND_HATF_EXPFILL | RND_HATF_FRAME);
			vpad(&status.rdsub);
			for(n = 0; n < 2; n++) {
					RND_DAD_LABEL(status.rdsub.dlg, "<pending>");
							status.wrd2[n] = RND_DAD_CURRENT(status.rdsub.dlg);
			}
			vpad(&status.rdsub);
		RND_DAD_END(status.rdsub.dlg);
		RND_DAD_BUTTON(status.rdsub.dlg, "<un>");
			status.wrdunit = RND_DAD_CURRENT(status.rdsub.dlg);
			RND_DAD_CHANGE_CB(status.rdsub.dlg, unit_change_cb);
	RND_DAD_END(status.rdsub.dlg);
}


void camv_status_gui_init_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	if ((RND_HAVE_GUI_ATTR_DLG) && (rnd_gui->get_menu_cfg != NULL)) {
		status_docked_create_st();
		if (rnd_hid_dock_enter(&status.stsub, RND_HID_DOCK_BOTTOM, "status") == 0) {
			status.stsub_inited = 1;
			status_st_view2dlg();
		}

		status_docked_create_rd(hidlib);
		if (rnd_hid_dock_enter(&status.rdsub, RND_HID_DOCK_TOP_RIGHT, "readout") == 0) {
			status.rdsub_inited = 1;
			status_rd_view2dlg();
		}
	}
}

void camv_status_st_update_conf(rnd_conf_native_t *cfg, int arr_idx, void *user_data)
{
	status_st_view2dlg();
}

void camv_status_rd_update_conf(rnd_conf_native_t *cfg, int arr_idx, void *user_data)
{
	status_rd_view2dlg();
}

void camv_status_st_update_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	status_st_view2dlg();
}

void camv_status_rd_update_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	status_rd_view2dlg();
}

const char camv_acts_StatusSetText[] = "StatusSetText([text])\n";
const char camv_acth_StatusSetText[] = "Replace status printout with text temporarily; turn status printout back on if text is not provided.";
fgw_error_t camv_act_StatusSetText(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	const char *text = NULL;

	if (argc > 2)
		RND_ACT_FAIL(StatusSetText);

	RND_ACT_MAY_CONVARG(1, FGW_STR, StatusSetText, text = argv[1].val.str);

	if (text != NULL) {
		rnd_hid_attr_val_t hv;
		hv.str = text;
		rnd_gui->attr_dlg_set_value(status.stsub.dlg_hid_ctx, status.wsttxt, &hv);
		rnd_gui->attr_dlg_widget_hide(status.stsub.dlg_hid_ctx, status.wst1, 1);
		rnd_gui->attr_dlg_widget_hide(status.stsub.dlg_hid_ctx, status.wsttxt, 0);
		status.st_has_text = 1;
	}
	else {
		status.st_has_text = 0;
		rnd_gui->attr_dlg_widget_hide(status.stsub.dlg_hid_ctx, status.wst1, 0);
		rnd_gui->attr_dlg_widget_hide(status.stsub.dlg_hid_ctx, status.wsttxt, 1);
		status_st_view2dlg();
	}

	RND_ACT_IRES(0);
	return 0;
}

