/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - altium file format support
 *  Copyright (C) 2022, 2023 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022 and Entrust in 2023)
 *
 *  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/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 <librnd/core/safe_fs.h>
#include <libcschem/config.h>

#include <stdio.h>
#include <librnd/core/error.h>
#include <libucdf/ucdf.h>

#include "pcbdoc_ascii.h"
#include "schdoc.h"

#include "read.h"

#define BINLEN_NO_MAIN
#include "binlen2txt.c"

/* optional trace */
#if 1
#	include <stdio.h>
#	define tprintf printf
#else
	static int tprintf(const char *fmt, ...) { return 0; }
#endif

/**** binary ****/

static int read_cb(void *ctx, void *dst, long len)
{
	long res = ucdf_fread((ucdf_file_t *)ctx, dst, len);
	return (res == len) ? 0 : -1;
}

static int alti_load_bin_sheet(io_altium_rctx_t *rctx, ucdf_ctx_t *uctx, ucdf_file_t *fp)
{
	vts0_t tmp = {0};

	while(binlen2txt_readline(&tmp, read_cb, fp) == 0) {
		long slen;
		altium_block_t *blk = malloc(sizeof(altium_block_t) + tmp.used + 2);

		memset(&blk->link, 0, sizeof(blk->link));
		blk->size = tmp.used;
		memcpy(blk->raw, tmp.array, tmp.used);

		slen = strlen(blk->raw);
		blk->raw[slen] = '\n';
		blk->raw[slen+1] = '\0';
		gdl_append(&rctx->tree.blocks, blk, link);
	}


	vts0_uninit(&tmp);
	return pcbdoc_ascii_parse_blocks(&rctx->tree, rctx->fn);
}

int io_altium_bin_load_sheet(FILE *f, const char *fn, const char *fmt, csch_sheet_t *dst)
{
	int res, found = 0;
	ucdf_ctx_t uctx = {0};
	ucdf_direntry_t *de;
	io_altium_rctx_t rctx = {0};

	res = ucdf_open(&uctx, fn);
	if (res != 0)
		return -1;

	rctx.fn = fn;

	/* look at each main directory and see if we can parse them */
	for(de = uctx.root->children; de != NULL; de = de->next) {
/*		tprintf("de name='%s'\n", de->name);*/
		if ((de->type == UCDF_DE_FILE) && (strcmp(de->name, "FileHeader") == 0)) {
			ucdf_file_t fp;

			res = ucdf_fopen(&uctx, &fp, de);
			if (res != 0) {
				error_((&rctx), NULL, ("io_altium_load_sheet(): failed to open FileHeader\n"));
				break;
			}

			found = (alti_load_bin_sheet(&rctx, &uctx, &fp) == 0);
			break;
		}
	}

	ucdf_close(&uctx);

	if (!found) {
		error_((&rctx), NULL, ("io_altium_bin_load_sheet(): failed to find or parse sheet file\n"));
		res = -1;
	}
	else
		res = altium_parse_sheet(&rctx, dst);

	altium_tree_free(&rctx.tree);

	return res;
}

int io_altium_bin_test_parse(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type)
{
	return ucdf_test_parse(fn);
}


/**** ascii ****/

int io_altium_ascii_load_sheet(FILE *f_nope, const char *fn, const char *fmt, csch_sheet_t *dst)
{
	FILE *f;
	int res;
	long filesize;
	io_altium_rctx_t rctx = {0};

	rctx.fn = fn;

	filesize = rnd_file_size(NULL, fn);
	if (filesize <= 0)
		return -1;

	f = rnd_fopen(NULL, fn, "rb");
	if (f == NULL)
		return -1;

	res = pcbdoc_ascii_load_blocks(&rctx.tree, f, filesize);
	fclose(f);

	if (res != 0)
		return -1;

	res = pcbdoc_ascii_parse_blocks(&rctx.tree, fn);

	if (res == 0)
		res = altium_parse_sheet(&rctx, dst);

	altium_tree_free(&rctx.tree);

	return res;
}


int io_altium_ascii_test_parse(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type)
{
	char line[256], *s;

	/* first line should comply to the low level file format */
	s = fgets(line, sizeof(line), f);
	if (s == NULL)
		return -1;

	if (*s == '|') s++;

	/* every line must start with a RECORD or HEADER field, the first one too */
	if ((strncmp(s,"RECORD=", 7) != 0) && (strncmp(s,"HEADER=", 7) != 0))
		return -1;

	/* there must be a field separator */
	if (strchr(s, '|') == NULL)
		return -1;

	return 0;
}
