/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - object access for scripts
 *  Copyright (C) 2019 Tibor 'Igor2' Palinkas in pcb-rnd
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  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/pcb-rnd
 *    lead developer: http://repo.hu/projects/pcb-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

/* includeed from act_read.c */

static const char csch_acts_IDPList[] =
	"IDPList(alloc)\n"
	"IDPList(free|clear|print|dup|length, list)\n"
	"IDPList(get|pop|remove, list, idx)\n"
	"IDPList(prepend|append|push, list, idpath)"
	;
static const char csch_acth_IDPList[] = "Basic idpath list manipulation.";
static fgw_error_t csch_act_IDPList(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	const char *cmd_;
	csch_oidpath_list_t *list;
	csch_oidpath_t *idp;
	int cmd;
	long idx;

	RND_ACT_CONVARG(1, FGW_STR, IDPList, cmd_ = argv[1].val.str);

	cmd = act_read_keywords_sphash(cmd_);
	if (cmd == act_read_keywords_alloc) {
		list = calloc(sizeof(csch_oidpath_list_t), 1);
		fgw_ptr_reg(&rnd_fgw, res, RND_PTR_DOMAIN_IDPATH_LIST, FGW_PTR | FGW_STRUCT, list);
		return 0;
	}
	RND_ACT_CONVARG(2, FGW_IDPATH_LIST, IDPList, list = fgw_idpath_list(&argv[2]));

	if (!fgw_ptr_in_domain(&rnd_fgw, &argv[2], RND_PTR_DOMAIN_IDPATH_LIST))
		return FGW_ERR_PTR_DOMAIN;

	switch(cmd) {
		case act_read_keywords_clear:
			csch_oidpath_list_clear(list);
			RND_ACT_IRES(0);
			return 0;

		case act_read_keywords_length:
			RND_ACT_IRES(csch_oidpath_list_length(list));
			return 0;

		case act_read_keywords_free:
			fgw_ptr_unreg(&rnd_fgw, &argv[2], RND_PTR_DOMAIN_IDPATH_LIST);
			csch_oidpath_list_clear(list);
			free(list);
			RND_ACT_IRES(0);
			return 0;

		case act_read_keywords_append:
		case act_read_keywords_push:
		case act_read_keywords_prepend:
			RND_ACT_CONVARG(3, FGW_IDPATH, IDPList, idp = fgw_idpath(&argv[3]));
			if (!fgw_ptr_in_domain(&rnd_fgw, &argv[3], RND_PTR_DOMAIN_IDPATH))
				return FGW_ERR_PTR_DOMAIN;
			if (cmd == act_read_keywords_append)
				csch_oidpath_list_append(list, idp);
			else /* prepend or push */
				csch_oidpath_list_insert(list, idp);
			RND_ACT_IRES(0);
			return 0;

		case act_read_keywords_remove:
			RND_ACT_CONVARG(3, FGW_LONG, IDPList, idx = argv[3].val.nat_long);
			idp = csch_oidpath_list_nth(list, idx);
			if (idp == NULL) {
				RND_ACT_IRES(-1);
				return 0;
			}
			csch_oidpath_list_remove(idp);
			RND_ACT_IRES(0);
			return 0;

		case act_read_keywords_get:
			RND_ACT_CONVARG(3, FGW_LONG, IDPList, idx = argv[3].val.nat_long);
			idp = csch_oidpath_list_nth(list, idx);
			if (idp == NULL) {
				res->type = FGW_PTR;
				res->val.ptr_struct = NULL;
				return 0;
			}
			fgw_ptr_reg(&rnd_fgw, res, RND_PTR_DOMAIN_IDPATH, FGW_PTR | FGW_STRUCT, idp);
			return 0;

		case act_read_keywords_pop:
			idp = csch_oidpath_list_first(list);
			if (idp == NULL) {
				res->type = FGW_PTR;
				res->val.ptr_struct = NULL;
				return 0;
			}
			fgw_ptr_reg(&rnd_fgw, res, RND_PTR_DOMAIN_IDPATH, FGW_PTR | FGW_STRUCT, idp);
			csch_oidpath_list_remove(idp);
			return 0;

		case act_read_keywords_print:
			{
				gds_t tmp;
				int first = 1;

				gds_init(&tmp);
				for(idp = csch_oidpath_list_first(list); idp != NULL; idp = csch_oidpath_list_next(idp)) {
					if (!first)
						gds_append(&tmp, ' ');
					csch_oidpath_to_str_append(&tmp, idp);
					first = 0;
				}
				res->type = FGW_STR | FGW_DYN;
				res->val.str = tmp.array;
			}
			return 0;

	}

	return -1;
}

static const char csch_acts_IDP[] = "IDP([print|free|dup], idpath)\n";
static const char csch_acth_IDP[] = "Basic idpath manipulation.";
static fgw_error_t csch_act_IDP(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	csch_sheet_t *sheet = CSCH_ACT_SHEET;
	const char *cmd;
	csch_oidpath_t *idp;
	csch_chdr_t *obj;

	RND_ACT_CONVARG(1, FGW_STR, IDP, cmd = argv[1].val.str);
	RND_ACT_CONVARG(2, FGW_IDPATH, IDP, idp = fgw_idpath(&argv[2]));
	if ((idp == NULL) || !fgw_ptr_in_domain(&rnd_fgw, &argv[2], RND_PTR_DOMAIN_IDPATH))
		return FGW_ERR_PTR_DOMAIN;


	switch(act_read_keywords_sphash(cmd)) {
		case act_read_keywords_free:
			csch_oidpath_list_remove(idp);
			fgw_ptr_unreg(&rnd_fgw, &argv[2], RND_PTR_DOMAIN_IDPATH);
			csch_oidpath_free(idp);
			free(idp);
			RND_ACT_IRES(0);
			return 0;

		case act_read_keywords_dup:
			obj = csch_oidpath_resolve(sheet, idp);
			idp = calloc(sizeof(csch_oidpath_t), 1);
			csch_oidpath_from_obj(idp, obj);
			res->type = FGW_IDPATH;
			fgw_ptr_reg(&rnd_fgw, res, RND_PTR_DOMAIN_IDPATH, FGW_PTR | FGW_STRUCT, idp);
			return 0;

		case act_read_keywords_print:
			res->type = FGW_STR | FGW_DYN;
			res->val.str = csch_oidpath_to_str(idp);
			return 0;
	}

	return -1;
}

static const char csch_acts_GetParentGrp[] = "GetParentGrp([root_data,] idpath)\n";
static const char csch_acth_GetParentGrp[] = "Return the oidpath of the immediate parent group of an object";
static fgw_error_t csch_act_GetParentGrp(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	csch_sheet_t *sheet = CSCH_ACT_SHEET;
	csch_oidpath_t *idp;
	csch_cgrp_t *root_grp = NULL;
	int iidx = 1;
	csch_chdr_t *obj;

	res->type = FGW_PTR | FGW_STRUCT;
	res->val.ptr_void = NULL;

	if (argc > 2) {
		RND_ACT_CONVARG(1, FGW_DATA, GetParentGrp, root_grp = fgw_data(&argv[1]));
		iidx++;
	}

	RND_ACT_CONVARG(iidx, FGW_IDPATH, IDPList, idp = fgw_idpath(&argv[iidx]));
	if ((idp == NULL) || !fgw_ptr_in_domain(&rnd_fgw, &argv[iidx], RND_PTR_DOMAIN_IDPATH))
		return FGW_ERR_PTR_DOMAIN;

	if (root_grp != NULL)
		obj = csch_oidpath_resolve_in(root_grp, idp);
	else
		obj = csch_oidpath_resolve(sheet, idp);

	if (obj == NULL)
		return 0;

	idp = calloc(sizeof(csch_oidpath_t), 1);
	csch_oidpath_from_obj(idp, &obj->parent->hdr);
	fgw_ptr_reg(&rnd_fgw, res, RND_PTR_DOMAIN_IDPATH, FGW_PTR | FGW_STRUCT, idp);
	return 0;
}

static const char csch_acts_GetObjType[] = "GetObjType([root_data,] idpath)\n";
static const char csch_acth_GetObjType[] = "Return the type of the object named in oidpath as a string.";
static fgw_error_t csch_act_GetObjType(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	csch_sheet_t *sheet = CSCH_ACT_SHEET;
	csch_oidpath_t *idp;
	csch_cgrp_t *root_grp = NULL;
	int iidx = 1;
	csch_chdr_t *obj;

	res->type = FGW_STR;
	res->val.str = NULL;

	if (argc > 2) {
		RND_ACT_CONVARG(1, FGW_DATA, GetObjType, root_grp = fgw_data(&argv[1]));
		iidx++;
	}

	RND_ACT_CONVARG(iidx, FGW_IDPATH, IDPList, idp = fgw_idpath(&argv[iidx]));
	if ((idp == NULL) || !fgw_ptr_in_domain(&rnd_fgw, &argv[iidx], RND_PTR_DOMAIN_IDPATH))
		return FGW_ERR_PTR_DOMAIN;

	if (root_grp != NULL)
		obj = csch_oidpath_resolve_in(root_grp, idp);
	else
		obj = csch_oidpath_resolve(sheet, idp);

	if (obj == NULL)
		return 0;

	res->val.cstr = csch_ctype_name(obj->type);
	return 0;
}
