/*
 *                            COPYRIGHT
 *
 *  pcb-rnd, interactive printed circuit board design
 *  Copyright (C) 2025 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://www.repo.hu/projects/librnd
 *    lead developer: http://www.repo.hu/projects/librnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

typedef struct {
	attr_dlg_t *hid_ctx;
	int attr_idx;

	/* markup related styles are done with attribute-text */
	unsigned palette_inited:1;
	unsigned char st2attr[16]; /* attribute value for each possible style; value 255 means uninitialized */
	mbtk_text_palette_t palette;
} dad_txt_t;

static void txt_free_cb(rnd_hid_attribute_t *attr, void *hid_ctx)
{
	dad_txt_t *tctx = hid_ctx;
	if (tctx->palette_inited)
		mbtk_text_palette_uninit(&tctx->palette);
	free(tctx);
}

static mbtk_event_handled_t txt_changed_cb(mbtk_widget_t *w, mbtk_kw_t id, void *user_data)
{
	/*mbtk_textedit_t *wtxt = w; */
	dad_txt_t *tctx = user_data;
	rnd_hid_attribute_t *attr = &tctx->hid_ctx->attrs[tctx->attr_idx];
	attr->changed = 1;
	change_cb(tctx->hid_ctx, attr);
	return MBTK_EVENT_HANDLED;
}

static void txt_get_xy(rnd_hid_attribute_t *attrib, void *hid_ctx, long *x, long *y)
{
	attr_dlg_t *ctx = hid_ctx;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;

	mbtk_textedit_cursor_get_char_xy(wtxt, x, y);
}

static long txt_get_offs(rnd_hid_attribute_t *attrib, void *hid_ctx)
{
	attr_dlg_t *ctx = hid_ctx;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;

	return mbtk_textedit_cursor_get_char_offs(wtxt);
}

static void txt_set_xy(rnd_hid_attribute_t *attrib, void *hid_ctx, long x, long y)
{
	attr_dlg_t *ctx = hid_ctx;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;

	mbtk_textedit_cursor_set_char_xy(wtxt, x, y);
}

static void txt_set_offs(rnd_hid_attribute_t *attrib, void *hid_ctx, long offs)
{
	attr_dlg_t *ctx = hid_ctx;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;

	mbtk_textedit_cursor_set_char_offs(wtxt, offs);
}

static void txt_set_text_(mbtk_textedit_t *wtxt, unsigned how, char *str, char *attr)
{
	switch(how & 0x0F) {
		case RND_HID_TEXT_INSERT:
			TODO("This ignores attr; do we need that in insert? - pcb-rnd doesn't use it anyway");
			mbtk_textedit_add_str(wtxt, str);
			break;
		case RND_HID_TEXT_REPLACE:
			mbtk_textedit_set_stra(wtxt, str, attr);
			break;
		case RND_HID_TEXT_APPEND:
			mbtk_textedit_append_stra(wtxt, str, attr);
			break;
	}
}

/* Return attribute value for a markup style; allocate (and cache) as needed */
RND_INLINE unsigned char st2attr(attr_dlg_t *ctx, dad_txt_t *tctx, mbtk_textedit_t *wtxt, rnd_markup_state_t st)
{
	unsigned clr = 0, style = 0;
	unsigned style_idx; /* LSB bits: SSCC where S is style, C is color; C==0 is normal color (black) */
	unsigned char av;
	int r = 0, g = 0, b = 0;
	mbtk_text_attr_t *a;
	mbtk_font_id_t *fid = &ctx->mctx->disp.default_fid;

	if (wtxt->palette == NULL) {
		wtxt->palette = &tctx->palette; /* was set to 0 on widget creation */
		tctx->palette_inited = 1;
		tctx->st2attr[0] = mbtk_text_palette_alloc(wtxt->palette); /* create default attribute, av=0 */
	}

	if (st & RND_MKS_RED) { clr = 1; r = 255; }
	else if (st & RND_MKS_GREEN) { clr = 2; g = 255; }
	else if (st & RND_MKS_BLUE) { clr = 3; b = 255; }
	if (st & RND_MKS_BOLD) { style |= 1; fid = &ctx->mctx->bold_fid; }
	if (st & RND_MKS_ITALIC) { style |= 2; fid = &ctx->mctx->italic_fid; }

	/* look up in already initialized attr styles */
	style_idx = style << 2 | clr;
	if (tctx->st2attr[style_idx] < 255)
		return tctx->st2attr[style_idx];

	/* not found, need to initialize anew */
	tctx->st2attr[style_idx] = av = mbtk_text_palette_alloc(wtxt->palette);
	a = mbtk_text_palette_get(wtxt->palette, av);
	assert(a != NULL);

	if (clr != 0) {
		a->has_color = 1;
		a->r = r;
		a->g = g;
		a->b = b;
		a->a = 255;
	}
	a->has_font = 1;
	a->fid = *fid;
}


static void txt_set_text(rnd_hid_attribute_t *attrib, void *hid_ctx, rnd_hid_text_set_t how, const char *str)
{
	attr_dlg_t *ctx = hid_ctx;
	rnd_hid_text_t *txt = attrib->wdata;
	dad_txt_t *tctx = txt->hid_wdata;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;

	if (how & RND_HID_TEXT_MARKUP) { /* auto-converts the text widget to use palette */
		rnd_markup_state_t st = 0;
		const char *seg;

		long seglen;
		gds_t atmp = {0};

		while((seg = rnd_markup_next(&st, &str, &seglen)) != NULL) {
			unsigned char av = st2attr(ctx, tctx, wtxt, st);
			char *t;

			if (seglen >= atmp.alloced)
				gds_enlarge(&atmp, seglen*2+2);
			memset(atmp.array, av, seglen);
			atmp.array[seglen] = '\0';
			t = atmp.array + 1;
			memcpy(t, seg, seglen);
			t[seglen] = '\0';

			txt_set_text_(wtxt, how, t, atmp.array);
		}
		gds_uninit(&atmp);
	}
	else
		txt_set_text_(wtxt, how, (char *)str, NULL);
}

static int rnd_mbtk_text_set(attr_dlg_t *ctx, int idx, const rnd_hid_attr_val_t *val)
{
	txt_set_text(&ctx->attrs[idx], ctx, RND_HID_TEXT_REPLACE, val->str);
	return 0;
}

static char *txt_get_text(rnd_hid_attribute_t *attrib, void *hid_ctx)
{
	attr_dlg_t *ctx = hid_ctx;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;
	return mbtk_textedit_get_str(wtxt);
}

static void txt_set_readonly(rnd_hid_attribute_t *attrib, void *hid_ctx, rnd_bool readonly)
{
	attr_dlg_t *ctx = hid_ctx;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;
	mbtk_textedit_set_read_only(wtxt, readonly);
}

static void txt_scroll_to_bottom(rnd_hid_attribute_t *attrib, void *hid_ctx)
{
	attr_dlg_t *ctx = hid_ctx;
	int idx = attrib - ctx->attrs;
	mbtk_textedit_t *wtxt = (mbtk_textedit_t *)ctx->aw[idx].w;

	mbtk_textedit_scroll_to_bottom(wtxt);
}

static mbtk_textedit_t *rnd_mbtk_text_create(attr_dlg_t *ctx, rnd_hid_attribute_t *attr)
{
	mbtk_textedit_t *wtxt;
	rnd_hid_text_t *txt = attr->wdata;
	dad_txt_t *tctx;


TODO("we have only scrolled at the moment");
/*if (attr->rnd_hatt_flags & RND_HATF_SCROLL) {*/

	wtxt = mbtk_textedit_new(NULL, NULL, 0);

	tctx = calloc(sizeof(dad_txt_t), 1);
	tctx->hid_ctx = ctx;
	tctx->attr_idx = attr - ctx->attrs;
	txt->hid_wdata = tctx;

	mbtk_textedit_callback_changed(wtxt, txt_changed_cb, tctx);

	memset(&tctx->st2attr, 255, sizeof(tctx->st2attr));

	txt->hid_get_xy = txt_get_xy;
	txt->hid_get_offs = txt_get_offs;
	txt->hid_set_xy = txt_set_xy;
	txt->hid_set_offs = txt_set_offs;
	txt->hid_scroll_to_bottom = txt_scroll_to_bottom;
	txt->hid_set_text = txt_set_text;
	txt->hid_get_text = txt_get_text;
	txt->hid_set_readonly = txt_set_readonly;
	txt->hid_free_cb = txt_free_cb;
	return wtxt;
}
