/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2019 Tibor 'Igor2' Palinkas
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.*
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; 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 "config.h"

/* fungw type extensions for cschem-only actions */

#include "config.h"

#include <stdlib.h>

#include <libfungw/fungw_conv.h>

#include <librnd/core/actions.h>
#include "actions_csch.h"
#include "oidpath.h"

const char *CSCH_PTR_DOMAIN_COBJ = "csch_fgw_ptr_domain_cobj";
const char *CSCH_PTR_DOMAIN_AOBJ = "csch_fgw_ptr_domain_aobj";
const char *CSCH_PTR_DOMAIN_PROJECT = "csch_fgw_ptr_domain_project";
const char *CSCH_PTR_DOMAIN_SHEET = "csch_fgw_ptr_domain_sheet";
const char *CSCH_PTR_DOMAIN_ATTRIB = "csch_fgw_ptr_domain_attrib";
const char *CSCH_PTR_DOMAIN_COBJ_ARR = "csch_fgw_ptr_domain_cobj_arr";


static int cobj_arg_conv(fgw_ctx_t *ctx, fgw_arg_t *arg, fgw_type_t target)
{
	if (target == FGW_LAYERID) { /* convert to layer id */
		csch_chdr_t *tmp = NULL;
		switch(FGW_BASE_TYPE(arg->type)) {
			ARG_CONV_CASE_LONG(tmp, conv_err)
			ARG_CONV_CASE_LLONG(tmp, conv_err)
			ARG_CONV_CASE_DOUBLE(tmp, conv_err)
			ARG_CONV_CASE_LDOUBLE(tmp, conv_err)
			ARG_CONV_CASE_PTR(tmp, conv_err)
			ARG_CONV_CASE_CLASS(tmp, conv_err)
			ARG_CONV_CASE_INVALID(tmp, conv_err)
			case FGW_STR:
			{
				csch_oidpath_t oidp;
				csch_sheet_t *sheet;
				int res = csch_oidpath_parse(&oidp, arg->val.str);
				if (res < 0) return -1;
				TODO("figure how to get sheet from hidlib");
				sheet = NULL;
				abort();
				tmp = csch_oidpath_resolve(sheet, &oidp);
				csch_oidpath_free(&oidp);
			}
		}
		if (tmp == NULL) return -1;
		arg->type = FGW_COBJ;
		fgw_cobj(arg) = tmp;
		return 0;
	}
	if (arg->type == FGW_COBJ) { /* convert from cobj */
		csch_chdr_t *tmp = fgw_cobj(arg);
		switch(target) {
			ARG_CONV_CASE_LONG(tmp, conv_err)
			ARG_CONV_CASE_LLONG(tmp, conv_err)
			ARG_CONV_CASE_DOUBLE(tmp, conv_err)
			ARG_CONV_CASE_LDOUBLE(tmp, conv_err)
			ARG_CONV_CASE_PTR(tmp, conv_err)
			ARG_CONV_CASE_CLASS(tmp, conv_err)
			ARG_CONV_CASE_INVALID(tmp, conv_err)
			case FGW_AUTO:
			case FGW_STR:
				{
					const csch_oidpath_t oidp;
					TODO("map oid path of an object");
					abort();
					arg->val.str = csch_oidpath_to_str(&oidp);
					arg->type = FGW_STR | FGW_DYN;
					return 0;
				}
		}
		(void)tmp; /* supress compiler warning */
		arg->type = target;
		return 0;
	}
	fprintf(stderr, "Neither side of the conversion is a cobj\n");
	abort();
}

#define conv_struct_from_str(str, DOMAIN, TYPE) \
	if ((str[0] == '0') && (str[1] == 'x')) { \
		fgw_arg_conv(&rnd_fgw, arg, FGW_PTR); \
			if (fgw_ptr_in_domain(&rnd_fgw, arg, DOMAIN)) { \
			arg->type = TYPE | FGW_PTR; \
			return 0; \
		} \
		arg->type = FGW_INVALID; \
		return -1; \
	}

static int idpath_arg_conv(fgw_ctx_t *ctx, fgw_arg_t *arg, fgw_type_t target)
{
	if (target == FGW_IDPATH) { /* convert to idpath */
		if (FGW_BASE_TYPE(arg->type) == FGW_STR) {
			const char *str = arg->val.str;
			csch_oidpath_t *idp;

			conv_struct_from_str(str, RND_PTR_DOMAIN_IDPATH, FGW_IDPATH);
			idp = malloc(sizeof(csch_oidpath_t));
			if (csch_oidpath_parse(idp, str) == 0) {
				fgw_ptr_reg(&rnd_fgw, arg, RND_PTR_DOMAIN_IDPATH, FGW_IDPATH, idp);
				return 0;
			}
			else
				free(idp);
		}
		if (FGW_BASE_TYPE(arg->type) == (FGW_PTR | FGW_STRUCT) && fgw_ptr_in_domain(&rnd_fgw, arg, RND_PTR_DOMAIN_IDPATH))
			return 0;
		arg->type = FGW_INVALID;
		return -1;
	}
	if (arg->type == FGW_IDPATH) { /* convert from idpath */
		if (fgw_ptr_in_domain(&rnd_fgw, arg, RND_PTR_DOMAIN_IDPATH)) {
			char *name = csch_oidpath_to_str(arg->val.ptr_void);
			if (name != NULL) {
				arg->val.str = name;
				arg->type = FGW_STR | FGW_DYN;
			}
			return 0;
		}
		return -1;
	}
	fprintf(stderr, "Neither side of the conversion is idpath\n");
	abort();
}

void csch_actions_init(fgw_ctx_t *ctx)
{
	if (fgw_reg_custom_type(ctx, FGW_COBJ, "cobj", cobj_arg_conv, NULL) != FGW_COBJ) {
		fprintf(stderr, "csch_actions_init: failed to register FGW_COBJ\n");
		abort();
	}
	if (fgw_reg_custom_type(&rnd_fgw, FGW_IDPATH, "idpath", idpath_arg_conv, NULL) != FGW_IDPATH) {
		fprintf(stderr, "pcb_actions_init: failed to register FGW_IDPATH\n");
		abort();
	}
}
