/*
 *                            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")
 */

#include <librnd/hid/hid_dad_tree.h>

/*** HID API callbacks ***/

static void rnd_mbtk_tree_insert_cb(rnd_hid_attribute_t *attr, void *hid_ctx, rnd_hid_row_t *new_row)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;
	rnd_hid_row_t *r_after, *r_par;
	mbtk_tbl_crs_row_t *nwr; /* new widget row */
	const char **cell = (const char **)new_row->cell;
	int level = 0;

	r_par = rnd_dad_tree_parent_row(htree, new_row);
	if (r_par != NULL) {
		rnd_hid_row_t *r;
		for(r = r_par, level = 1; r != NULL; r = rnd_dad_tree_parent_row(htree, r))
			level++;
	}
	
	/* first try to find the previous row on the same level to insert after */
	r_after = gdl_prev(new_row->link.parent, new_row);

	/* if that fails try to find the parent row to insert after that directly */
	if (r_after == NULL)
		r_after = r_par;

	/* if that fails too, we are inserting the first item on the top level */
	if (r_after == NULL)
		nwr = mbtk_tbl_crs_tree_prepend_str_line(wtree, new_row->cols, cell, level);
	else
		nwr = mbtk_tbl_crs_tree_insert_str_line_after(wtree, r_after->hid_data, new_row->cols, cell, level);

	new_row->hid_data = nwr;
	mbtk_tbl_crs_tree_set_row_user_data(nwr, new_row);
}

static void rnd_mbtk_tree_remove_cb(rnd_hid_attribute_t *attr, void *hid_ctx, rnd_hid_row_t *row)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;

	mbtk_tbl_crs_tree_remove_row(wtree, row->hid_data);
	row->hid_data = NULL;
}

static void rnd_mbtk_tree_modify_cb(rnd_hid_attribute_t *attr, void *hid_ctx, rnd_hid_row_t *row, int col)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;
	mbtk_tbl_crs_row_t *wrow = row->hid_data;

	if (col < 0) {
		for(col = 0; col < attr->rnd_hatt_table_cols; col++)
			mbtk_tbl_crs_tree_modify_str_in_row(wtree, wrow, col, row->cell[col]);
	}
	else
		mbtk_tbl_crs_tree_modify_str_in_row(wtree, wrow, col, row->cell[col]);
}


static void rnd_mbtk_tree_jumpto_cb(rnd_hid_attribute_t *attr, void *hid_ctx, rnd_hid_row_t *row)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;
	mbtk_tbl_crs_row_t *wrow = row->hid_data;

	mbtk_tbl_crs_tree_cursor_set_row(wtree, wrow);
}

static void rnd_mbtk_tree_expcoll_cb(rnd_hid_attribute_t *attr, void *hid_ctx, rnd_hid_row_t *row, int expanded)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;
	mbtk_tbl_crs_row_t *wrow = row->hid_data;

	mbtk_tbl_crs_tree_row_expcoll(wtree, wrow, expanded);
}

static void rnd_mbtk_tree_free_cb(rnd_hid_attribute_t *attr, void *hid_ctx, rnd_hid_row_t *row)
{
	/* nothing allocated on a per row basis */
}

static rnd_hid_row_t *rnd_mbtk_tree_get_selected_cb(rnd_hid_attribute_t *attr, void *hid_ctx)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;
	mbtk_tbl_crs_row_t *wrow;

	wrow = mbtk_tbl_crs_tree_get_sel_first(wtree);
	if (wrow == NULL)
		return NULL;

	return mbtk_tbl_crs_tree_get_row_user_data(wrow);
}

static int rnd_mbtk_tree_get_selected_multi_cb(rnd_hid_attribute_t *attr, void *hid_ctx, vtp0_t *dst)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;
	mbtk_tbl_crs_row_t *wrow;
	int found = 0;

	for(wrow = mbtk_tbl_crs_tree_get_sel_first(wtree); wrow != NULL; wrow = mbtk_tbl_crs_tree_get_sel_next(wtree, wrow)) {
		vtp0_append(dst, mbtk_tbl_crs_tree_get_row_user_data(wrow));
		found++;
	}

	return found ? 0 : -1;
}

static void rnd_mbtk_tree_update_hide_cb(rnd_hid_attribute_t *attr, void *hid_ctx)
{
/*	attr_dlg_t *ctx = hid_ctx;*/
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree = htree->hid_wdata;
	mbtk_tbl_crs_row_t *wrow;

	wrow = mbtk_tbl_crs_row_first(wtree);
	while(wrow != NULL) {
		rnd_hid_row_t *hrow = mbtk_tbl_crs_tree_get_row_user_data(wrow);
		wrow = mbtk_tbl_crs_row_tree_set_visible(wtree, wrow, !hrow->hide);
	}
}


/*** widget callbacks ***/


static mbtk_event_handled_t tree_cursor_chg_cb(mbtk_widget_t *w, mbtk_kw_t id, void *user_data)
{
	attr_dlg_t *ctx = w->user_data2.p;
	rnd_hid_attribute_t *attr = w->user_data;
	mbtk_tbl_crs_tree_t *wtree = (mbtk_tbl_crs_tree_t *)w;
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_row_t *wrow = mbtk_tbl_crs_tree_cursor_get_row(wtree);
	rnd_hid_row_t *hrow = NULL;

	if (wrow != NULL)
		hrow = mbtk_tbl_crs_tree_get_row_user_data(wrow);

	/* update current value of the attribute (assuming single line selection) */
	if (hrow != NULL)
		attr->val.str = hrow->path;
	else
		attr->val.str = NULL;

	/* optional: user callback */
	if (htree->user_selected_cb != NULL)
		htree->user_selected_cb(attr, ctx, hrow);

	return MBTK_EVENT_HANDLED;
}

static mbtk_event_handled_t tree_activated_cb(mbtk_widget_t *w, mbtk_kw_t id, void *user_data)
{
	attr_dlg_t *ctx = w->user_data2.p;
	rnd_hid_attribute_t *attr = w->user_data;

	change_cb(ctx, attr);

	return MBTK_EVENT_HANDLED;
}


/*** create ***/
static mbtk_tbl_crs_tree_t *rnd_mbtk_tree_create(attr_dlg_t *ctx, rnd_hid_attribute_t *attr)
{
	rnd_hid_tree_t *htree = attr->wdata;
	mbtk_tbl_crs_tree_t *wtree;
	int is_tree = !!(attr->rnd_hatt_flags & RND_HATF_TREE_COL);
	int is_scrolled = !!(attr->rnd_hatt_flags & RND_HATF_SCROLL);
	long cols = attr->rnd_hatt_table_cols;
	mbtk_tbl_crs_cursor_type_t cty = (attr->hatt_flags & RND_HATF_TREE_MULTI) ? MBTK_TBL_CRS_CURSOR_MLINE : MBTK_TBL_CRS_CURSOR_1LINE;

	wtree = mbtk_tbl_crs_tree_new(NULL, cols, cty, is_scrolled, is_tree);

	htree->hid_insert_cb = rnd_mbtk_tree_insert_cb;
	htree->hid_remove_cb = rnd_mbtk_tree_remove_cb;
	htree->hid_modify_cb = rnd_mbtk_tree_modify_cb;
	htree->hid_jumpto_cb = rnd_mbtk_tree_jumpto_cb;
	htree->hid_expcoll_cb = rnd_mbtk_tree_expcoll_cb;
	htree->hid_free_cb = rnd_mbtk_tree_free_cb;
	htree->hid_get_selected_cb = rnd_mbtk_tree_get_selected_cb;
	htree->hid_get_selected_multi_cb = rnd_mbtk_tree_get_selected_multi_cb;
	htree->hid_update_hide_cb = rnd_mbtk_tree_update_hide_cb;

	/* create header if there's one */
	if (htree->hdr != NULL) {
		const char **c;
		long len = 0;

		/* need to count how many header strings are provided (may be less or more than number of cols) */
		for(c = htree->hdr; *c != NULL; c++) len++;

		/* make first row header and create the first row */
		mbtk_tbl_crs_tree_set_first_row_is_header(wtree, 1);
		mbtk_tbl_crs_tree_append_str_line(wtree, len, htree->hdr, 0);
	}


	mbtk_tbl_crs_callback_changed(wtree, tree_cursor_chg_cb, NULL);
	mbtk_tbl_crs_callback_invoked(wtree, tree_activated_cb, NULL);


	/* cross link widget and hid data */
	((mbtk_widget_t *)wtree)->user_data = attr;
	((mbtk_widget_t *)wtree)->user_data2.p = ctx;
	htree->hid_wdata = wtree;


	return wtree;
}
