/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2018,2023,2024 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 Entrust in 2023)
 *
 *  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., 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
 */


#ifndef CSCH_PLUG_IO_H
#define CSCH_PLUG_IO_H

#include <stdio.h>
#include <libcschem/concrete.h>
#include <libcschem/abstract.h>
#include <genvector/vtp0.h>

typedef enum csch_plug_io_type_s { /* bitfield so multiple detections (e.g. sheet-or-project) can be handled */
	CSCH_IOTYP_PROJECT = 1,
	CSCH_IOTYP_SHEET   = 2,
	CSCH_IOTYP_BUFFER  = 4,    /* whole buffer (direct & indirect; similar to sheet) */
	CSCH_IOTYP_GROUP   = 8,    /* a single group (e.g. symbol) */
	CSCH_IOTYP_NETLIST = 16,
	CSCH_IOTYP_ATTBL   = 32    /* attribute table import with ->import_attbl(); either concrete or abstract */
} csch_plug_io_type_t;

typedef struct csch_plug_io_s {
	const char *name;

	int (*load_prio)(const char *fn, const char *fmt, csch_plug_io_type_t type);
	int (*save_prio)(const char *fn, const char *fmt, csch_plug_io_type_t type);
	int (*test_parse)(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type); /* returns 0 for accept */

	int (*load_sheet)(FILE *f, const char *fn, const char *fmt, csch_sheet_t *dst);
	int (*save_sheet)(const char *fn, const char *fmt, const csch_sheet_t *dst);
	int (*load_project)(FILE *f, const char *fn, const char *fmt, csch_project_t *dst, int with_sheets);

	int (*load_buffer)(FILE *f, const char *fn, const char *fmt, csch_sheet_t *dst);
	int (*save_buffer)(const char *fn, const char *fmt, const csch_sheet_t *dst);

	/* useful for saving/loading symbols */
	csch_cgrp_t *(*load_grp)(FILE *f, const char *fn, const char *fmt, const char *subsymname, csch_sheet_t *sheet);
	int (*save_grp)(const char *fn, const char *fmt, const csch_cgrp_t *src, int inhibit_uuid);

	int (*export_prio)(const char *fn, const char *fmt, csch_plug_io_type_t type);
	int (*export_sheet)(const char *fn, const char *fmt, csch_sheet_t *dst);
	int (*export_project_abst)(const char *fn, const char *fmt, csch_abstract_t *abs, rnd_hid_attr_val_t *options);

	int (*import_prio)(const char *fn, const char *fmt, csch_plug_io_type_t type);

/* for attribute table round-trip for external table-edit; sheet (concrete) or project (concrete or abstract) */
	int (*import_attbl)(FILE *f, const char *fn, const char *fmt, csch_sheet_t *sheet);

	/* Bundled files contain multiple sheets or symbols. For sheets, they
	   act as a project file. test_parse_bundled() is called before
	   test_parse; if it returns non-NULL, the file is considered
	   bundled and the _bundled() loader is called with the cookie
	   set to the intially returned value, in an iteration. If the
	   bundled() loader returns a positive value, the iteration stops.
	   Negative return means error (iteration stops). Return zero when the next
	   item was loaded succesfully. end_bundled() is called after the iteration.
	
	   WARNING: config is not available in test_parse_bundled(), only in
	   load_sheet_bundled().
	*/
	void *(*test_parse_bundled)(FILE *f, const char *fn, const char *fmt, csch_plug_io_type_t type);
	int (*load_sheet_bundled)(void *cookie, FILE *f, const char *fn, csch_sheet_t *dst);
	/* TODO: load_grp_bundled() */
	void (*end_bundled)(void *cookie, const char *fn);

	const char *ext_export_sheet; /* default extension for exporting sheets */
	const char *ext_save_sheet;   /* default extension for saving sheets */
	const char *ext_save_buffer;  /* default extension for saving buffers */
	const char *ext_save_grp; /* default extension for saving groups */
	const char *ext_export_project; /* default extension for exporting the whole project (e.g. abstract model for netlist or bundled export of concrete model) */
} csch_plug_io_t;

void csch_plug_io_register(const csch_plug_io_t *io);
void csch_plug_io_unregister(const csch_plug_io_t *io);

/* Load a sheet. If optf is NULL, use fopen()/fclose() using fn. optf
   is not closed but seeked/rewound. */
csch_sheet_t *csch_load_sheet(csch_project_t *proj, const char *fn, const char *fmt, int *already_in_proj, FILE *optf);

csch_project_t *csch_load_project(const char *fn, const char *fmt, int with_sheets);
csch_cgrp_t *csch_load_grp(csch_sheet_t *dst, const char *load_fn, const char *fmt, const char *subsymname);

int csch_save_sheet(csch_sheet_t *sheet, const char *fn, const char *fmt);
int csch_save_sheet_backup(csch_sheet_t *sheet, const char *fn, const char *fmt); /* does not make the sheet look saved */
int csch_save_grp(csch_cgrp_t *grp, const char *fn_, const char *fmt, int inhibit_uuid);

int csch_load_buffer(csch_sheet_t *buffer, const char *fn, const char *fmt);
int csch_save_buffer(csch_sheet_t *buffer, const char *fn, const char *fmt);


int csch_export_sheet(csch_sheet_t *sheet, const char *fn, const char *fmt);
int csch_export_project_abst(csch_abstract_t *abs, const char *fn, const char *fmt, rnd_hid_attr_val_t *options);

void csch_revert_sheet(csch_sheet_t *sheet, csch_sheet_t *(*sheet_new)(csch_sheet_t *));

/* Test-parse the file for type using all available io plugin in random
   order. Return -1 on error (e.g. file can not be open for read), 0 if
   no plugin accepted the file or 1 if a plugin accepted it. Rewind()s
   the file multiple times. */
int csch_test_parse_fn(rnd_design_t *hl, const char *fn, csch_plug_io_type_t type);

/* Same as csch_test_parse_fn() but takes FILE *f already open from the caller */
int csch_test_parse_file(rnd_design_t *hl, FILE *f, const char *real_fn, csch_plug_io_type_t type);

/* low level sheet loader. If optf is NULL, use fopen()/fclose() using real_fn.
   optf is not closed but seeked/rewound. */
csch_sheet_t *csch_load_sheet_io(csch_project_t *proj, csch_sheet_t *sheet, const char *load_fn, const char *real_fn, const char *fmt, int is_buffer, FILE *optf);


void *csch_test_parse_bundled(rnd_design_t *hl, const char *real_fn, csch_plug_io_type_t type, FILE **f_out, void **io_out);
csch_sheet_t *csch_load_bundled_sheets(void *cookie, void *io, FILE *f, const char *prj_fn, void (*post_load_cb)(csch_sheet_t *));

/* fmt is only a hint; may help with undetectable file formats like csv */
int csch_import_attbl(rnd_design_t *dsg, const char *fn, const char *fmt);

void csch_plug_io_uninit(void);

/* List of all IO plugins */
extern vtp0_t csch_ios;


#endif
