/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  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
 */

#ifndef CSCH_SYMLIB_H
#define CSCH_SYMLIB_H

#include <genvector/vtp0.h>
#include <genht/htsp.h>
#include <librnd/core/conf.h>

#include <libcschem/common_types.h>

typedef enum { /* bitfield so that it can be OR'd for mask */
	CSCH_SLIB_invalid = 0,
	CSCH_SLIB_STATIC = 1,
	CSCH_SLIB_PARAMETRIC = 2,
	CSCH_SLIB_DIR = 4
} csch_lib_type_t;

typedef struct csch_lib_s csch_lib_t;
typedef struct csch_lib_backend_s csch_lib_backend_t;


struct csch_lib_backend_s {
	const char *name;

	/* called with a path to a resource; returns root or realpath(3) of root if applicable */
	char *(*realpath)(rnd_design_t *hl, const char *root);

	/* called with a path to a resource; map and build the slib tree under
	   root_dir. Return 0 on success. Do not add anything to the tree on error.
	   Not being able to map a few sub-resources is not considered an error. */
	int (*map)(rnd_design_t *hl, csch_lib_t *root_dir);
	int (*map_local)(rnd_design_t *hl, csch_lib_t *root_dir, const csch_cgrp_t *indirect);

	/* load an slib entry into a new group.1 under empty sheet */
	int (*load)(csch_sheet_t *sheet, void *dst, csch_lib_t *src, const char *params);

	/* optional: generate textual preview for the library window; return value
	   will be free()'d */
	char *(*preview_text)(csch_sheet_t *sheet, csch_lib_t *src, const char *parametric);

	/* free backend data in src; called on entries when they are removed from
	   the lib and roots on library/sheet removal. In the latter case first
	   it is called on the root then on all children recursively. */
	void (*free)(csch_lib_t *src);

	/*** helpers for local library entries (any may be NULL) ***/
	/* Refresh local lib copy within sheet from the external lib (if available) */
	int (*loc_refresh_from_ext)(csch_sheet_t *sheet, csch_lib_t *src);

	/* Count and list users of a given local lib entry on the sheet */
	int (*loc_list)(csch_sheet_t *sheet, csch_lib_t *src);

	/* Remove from local lib and tune references in sheet */
	int (*loc_del)(csch_sheet_t *sheet, csch_lib_t *src);

	/* Invoke interactive editor for an entry */
	int (*loc_edit)(csch_sheet_t *sheet, csch_lib_t *src);
};

struct csch_lib_s {
	char *name;
	char *realpath;          /* NULL if parent is not NULL; may point to name; on the filesystem it's the real-path so relative names like ./sym of different projects are different */
	csch_lib_type_t type;

	const csch_lib_backend_t *backend;
	struct {
		void *ptr[8];
		long lng[8];
	} backend_data;

	const char *error;   /* if not NULL, there was an error accessing this node */
	unsigned int hide:1; /* hide from the UI */
	unsigned just_mapped:1;   /* in root: set right after mapping/scanning a root from disk */

	csch_lib_t *parent; /* NULL in the first level of root dirs */
	vtp0_t children;
};

typedef struct csch_lib_root_s {
	csch_sheet_t *sheet;      /* sheet this lib set is for; NULL for the master (all-known) set */
	vtp0_t roots;             /* ordered list of (csch_lib_t *) root dirs as configured */
} csch_lib_root_t;

typedef struct csch_lib_master_s {
	char *name;
	int uid;
	htsp_t roots;       /* realpath -> (csch_lib_t *) root dir */
	vtp0_t backends;    /* list of (csch_lib_backend_t *) as registered */
} csch_lib_master_t;




/*** calls for lib users ***/

/* call csch_lib_add() for all configured lib paths in sheet; re-scan
   existing libs only if do_rehash is non-zero; new libraries found
   that were not present previously are always scanned */
void csch_lib_add_all(csch_sheet_t *sheet, csch_lib_master_t *master, const rnd_conflist_t *searchpath, int do_rehash);

/* Re-map the root of an existing node */
int csch_lib_rehash(csch_sheet_t *sheet, csch_lib_master_t *master, csch_lib_t *node);

/* Remove all roots from a library within sheet; useful before rehashing the
   whole library for that sheet:master combo */
void csch_lib_clear_sheet_lib(csch_sheet_t *sheet, int master_uid);

csch_lib_master_t *csch_lib_get_master(const char *name, int alloc);

int csch_lib_load(csch_sheet_t *sheet, void *dst, csch_lib_t *src, const char *params);

/* Linear search of a footprint by name within the libraries; returns first match */
csch_lib_t *csch_lib_search(csch_lib_root_t *lib, const char *name, csch_lib_type_t mask);
csch_lib_t *csch_lib_search_master(csch_lib_master_t *master, const char *name, csch_lib_type_t mask);

void csch_lib_free_sheet_local_libs(csch_sheet_t *sheet);
void csch_lib_free_sheet_libs(csch_sheet_t *sheet);

/* Removes l from its parent and frees it */
void csch_lib_remove(csch_lib_t *l);

/*** calls for symlib_ plugins ***/

/* Append a new child under parent; name is not strdup()'d, caller has to
   dup it or otherwise make it permament. On csch_lib_free() this field
   will be free()'d. */
csch_lib_t *csch_lib_alloc_append(const csch_lib_backend_t *be, csch_lib_t *parent, char *name, csch_lib_type_t type);

void csch_lib_backend_reg(csch_lib_master_t *master, const csch_lib_backend_t *be);

/*** calls for internal use ***/
/* Rehash (re-scan) existing libraries only if do_rehash is non-zero; new
   libraries just added are always scanned. skip_just_mapped is used by
   csch_lib_add_all() to avoid redundant mapping. path needs to be strdup'd by
   the caller, csch_lib_add() will take ownership of it. */
int csch_lib_add(csch_sheet_t *sheet, csch_lib_master_t *master, char *path, int append, int do_rehash, int skip_just_mapped);

int csch_lib_add_local(csch_sheet_t *sheet, csch_lib_master_t *master);
void csch_lib_free(csch_lib_t *slib); /* doesn't remove from parent! */
void csch_plug_symlib_init(void);
void csch_plug_library_init(void);
void csch_plug_library_uninit(void);

#endif
