/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - symbol library from the file system
 *  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., 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 <libcschem/config.h>
#include <libcschem/plug_io.h>
#include <libcschem/plug_library.h>
#include <libcschem/util_lib_fs.h>
#include <libcschem/cnc_grp.h>
#include <libcschem/cnc_any_obj.h>

#include <librnd/core/error.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/compat_fs.h>
#include <librnd/core/safe_fs.h>
#include <librnd/core/safe_fs_dir.h>
#include <librnd/core/plugins.h>

static csch_lib_backend_t be_symlib_fs;

static char *symlib_fs_realpath(rnd_design_t *hl, const char *root)
{
	/* accept only non-prefixed paths */
	if (strchr(root, '@') != NULL)
		return NULL;

	return csch_lib_fs_realpath(hl, root);
}

csch_lib_type_t symlib_fs_file_type(rnd_design_t *hl, const char *fn)
{
	char head[2] = {0, 0};
	FILE *f;
	int res;

	f = rnd_fopen(hl, fn, "r");
	if (f == NULL)
		return CSCH_SLIB_invalid;

	res = fread(head, 2, 1, f);

	if ((res < 1) || ((head[0] == '#') && (head[1] == '!'))) {
		fclose(f);
		return CSCH_SLIB_PARAMETRIC;
	}

	res = csch_test_parse_file(hl, f, fn, CSCH_IOTYP_GROUP);
	fclose(f);

	if (res > 0)
		return CSCH_SLIB_STATIC;
	return CSCH_SLIB_invalid;
}

static int symlib_fs_map(rnd_design_t *hl, csch_lib_t *root_dir)
{
	gds_t tmp = {0};
	gds_append_str(&tmp, root_dir->realpath);
	csch_lib_fs_map(hl, &be_symlib_fs, root_dir, &tmp, symlib_fs_file_type);
	gds_uninit(&tmp);
	return 0;
}

static int run_parametric(rnd_design_t *hl, const char *cmd, const char *params, const char *ofn)
{
	gds_t cmdl = {0};
	int res;

	gds_append_str(&cmdl, cmd);
	gds_append(&cmdl, ' ');
	if (params != NULL)
		gds_append_str(&cmdl, params);
	gds_append_str(&cmdl, " > ");
	gds_append_str(&cmdl, ofn);

	res = rnd_system(hl, cmdl.array);

	/* rnd_trace("parametric: '%s' is %d\n", cmdl.array, res); */

	gds_uninit(&cmdl);
	return res;
}

static int symlib_fs_load(csch_sheet_t *sheet, void *dst_, csch_lib_t *src, const char *params)
{
	csch_sheet_t *dst = dst_;
	csch_cgrp_t *grp = NULL;

	switch(src->type) {
		case CSCH_SLIB_PARAMETRIC:
		{
			char *tmp;
			int rv;

			tmp = rnd_tempfile_name_new("symlib_fs_p");
			if (tmp == NULL) {
				rnd_message(RND_MSG_ERROR, "symlib_fs_load(parametric): failed to create temp file\n");
				return -1;
			}

			rv = run_parametric(&sheet->hidlib, src->realpath, params, tmp);
			if (rv == 0) {
				grp = csch_load_grp(dst, tmp, NULL);
				if (grp != NULL) {
					/* do not let the system remember the temp file name, put back the real file name */
					free(grp->file_name);
					grp->file_name = rnd_strdup(src->realpath);
				}
			}
			else
				rnd_message(RND_MSG_ERROR, "symlib_fs_load(parametric): '%s' returned error %d\n", src->realpath, rv);
			rnd_tempfile_unlink(tmp);
		}
		break;
		case CSCH_SLIB_STATIC:
			grp = csch_load_grp(dst, src->realpath, NULL);
			break;

		case CSCH_SLIB_invalid:
		case CSCH_SLIB_DIR:
			return -1;
	}

	if (grp == NULL)
		return -1;

	grp->sym_prefer_loclib = 1;
	csch_cgrp_render_all(dst, &dst->direct);
	csch_cobj_update(dst, &dst->direct.hdr, 1);

	return 0;
}

static void symlib_fs_free(csch_lib_t *src)
{
}


int pplg_check_ver_symlib_fs(int ver_needed) { return 0; }

void pplg_uninit_symlib_fs(void)
{

}

int pplg_init_symlib_fs(void)
{
	RND_API_CHK_VER;

	be_symlib_fs.name = "symlib_fs";
	be_symlib_fs.realpath = symlib_fs_realpath;
	be_symlib_fs.map = symlib_fs_map;
	be_symlib_fs.load = symlib_fs_load; /* loads a group into dst sheet */
	be_symlib_fs.free = symlib_fs_free;

	csch_lib_backend_reg(csch_lib_get_master("symbol", 1), &be_symlib_fs);

	return 0;
}

