/*
 *                            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"
#include <stdio.h>

#define TDL_DONT_UNDEF
#include "oidpath.h"
#include <genlist/gentdlist_impl.c>
#undef TDL_DONT_UNDEF
#include <genlist/gentdlist_undef.h>

#include "concrete.h"

int csch_oidpath_parse_relative(csch_oidpath_t *dst, const char *src)
{
	const char *curr;
	char *next;

	dst->vt.used = 0;
	for(curr = src; curr != NULL; curr = next) {
		long oid = strtol(curr, &next, 10);

		if (*next == '\0')       next = NULL;
		else if (*next == '/')   next++;
		else                     return -1;

		csch_vtoid_append(&dst->vt, oid);
	}
	return 0;
}

int csch_oidpath_parse(csch_oidpath_t *dst, const char *src)
{
	if (*src != '/')
		return -1;
	src++;
	return csch_oidpath_parse_relative(dst, src);
}

RND_INLINE csch_chdr_t *csch_oidpath_resolve_in_(csch_cgrp_t *curr, const csch_oidpath_t *path, long start_idx)
{
	int n;

	for(n = start_idx; n < path->vt.used; n++) {
		if (!csch_obj_is_grp(&curr->hdr))
			return NULL;

		curr = htip_get(&curr->id2obj, path->vt.array[n]);
		if (curr == NULL)
			return NULL;
	}

	return &curr->hdr;
}

csch_chdr_t *csch_oidpath_resolve_in(csch_cgrp_t *grp, const csch_oidpath_t *path)
{
	return csch_oidpath_resolve_in_(grp, path, 0);
}


csch_chdr_t *csch_oidpath_resolve(csch_sheet_t *sheet, const csch_oidpath_t *path)
{
	csch_chdr_t *curr;

	if (path->vt.used < 1)
		return NULL;

	/* Note: resolves absolute paths only */

	/* first oid must be 1 or 2 for the top group */
	if (path->vt.array[0] == CSCH_TOP_OID_DIRECT)
		curr = &sheet->direct.hdr;
	else if (path->vt.array[0] == CSCH_TOP_OID_INDIRECT)
		curr = &sheet->indirect.hdr;
	else
		return NULL;

	return csch_oidpath_resolve_in_((csch_cgrp_t *)curr, path, 1);
}

void csch_oidpath_free(csch_oidpath_t *path)
{
	csch_vtoid_truncate(&path->vt, 0);
}


int csch_oidpath_to_str_append(gds_t *dst, const csch_oidpath_t *path)
{
	int n;
	for(n = 0; n < path->vt.used; n++) {
		char tmp[64];
		int len = sprintf(tmp, "/%ld", (long)path->vt.array[n]);
		gds_append_len(dst, tmp, len);
	}
	return path->vt.used;
}

char *csch_oidpath_to_str(const csch_oidpath_t *path)
{
	gds_t tmp;
	gds_init(&tmp);
	csch_oidpath_to_str_append(&tmp, path);
	return tmp.array;
}


void csch_oidpath_from_obj(csch_oidpath_t *dst, const csch_chdr_t *src)
{
	const csch_chdr_t *o;
	long len = 0;

	dst->vt.used = 0;
	for(o = src; o != NULL; o = (const csch_chdr_t *)o->parent) len++;
	for(o = src; o != NULL; o = (const csch_chdr_t *)o->parent)
		csch_vtoid_set(&dst->vt, --len, o->oid);
}


void csch_oidpath_list_clear(csch_oidpath_list_t *lst)
{
	csch_oidpath_t *i, *next;
	for(i = csch_oidpath_list_first(lst); i != NULL; i = next) {
		next = csch_oidpath_list_next(i);
		csch_oidpath_free(i);
		free(i);
	}
}


int csch_oidpath_eq(const csch_oidpath_t *p1, const csch_oidpath_t *p2)
{
	long n;

	if (p1->vt.used != p2->vt.used) return 0;

	for(n = 0; n < p1->vt.used; n++)
		if (p1->vt.array[n] != p2->vt.array[n])
			return 0;

	return 1;
}
