/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2018,2019,2023 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., 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_PROJECT_H
#define CSCH_PROJECT_H

#include <librnd/core/project.h>
#include <libcschem/common_types.h>
#include <libcschem/concrete.h>
#include <libcschem/attrib.h>
#include <libcschem/engine.h>
#include <genvector/vtp0.h>
#include <genvector/vts0.h>
#include <liblihata/lihata.h>
#include <liblihata/dom.h>
#include <libfungw/fungw.h>

/* use currently active view of the project */
#define CSCH_VIEW_DEFAULT -1

struct csch_view_s {
	fgw_ctx_t fgw_ctx; /* name of the view is the name of the context */
	vtp0_t engines; /* priority-ordered list of (csch_view_eng_t *); highest prio (lowest numer) is at the end */
	csch_project_t *parent;
};

struct csch_project_s {
	rnd_project_t hdr;
	vtp0_t views;     /* of (csch_view_t *) */
	vtp0_t p4data;    /* per-plugin-per-project data indexed by csch_p4id_t registered by the plugin */

	long view_conf_rev;

	/* cached */
	csch_abstract_t *abst;  /* compiled for display attributes */
	int curr;               /* index of currently active view */
	long num_root_sheets;   /* cached from conf prj/root_sheets; filled in by the app */
	long num_aux_sheets;    /* cached from conf prj/aux_sheets; filled in by the app */
	unsigned dummy:1;       /* 1 when there's no real project but a dummy one is allocated */
};

csch_project_t *csch_project_alloc(void);
void csch_project_free(csch_project_t *prj);

/* Write out the project file */
void csch_project_flush(void);

/* Remove every view from prj */
void csch_project_clean_views(csch_project_t *prj);

/* Create a new view, returns the index; returns -1 on error */
csch_view_t *csch_view_create(csch_project_t *prj, const char *name);

/* Returns current view or NULL */
RND_INLINE csch_view_t *csch_view_get_current(csch_project_t *prj);

/* Returns view by name using linear search (there'd be only a few views) */
csch_view_t *csch_view_get(csch_project_t *prj, const char *name);
int csch_view_get_id(csch_project_t *prj, const char *name);

/* free all fields and view itself (but do not remove from parent!) */
void csch_view_free(csch_view_t *view);

/* Activate view by integer ID; returns 0 on success */
int csch_view_activate(csch_project_t *prj, int view_id);


/* Generate an event to get the GUI updated */
void csch_views_changed(csch_project_t *prj);


/* Create a new engine in a view, reassign priorities of other engines in
   the view as needed. On success return the index of the new engine (from 0);
   on failure return -1;
   user_name, eng_name and file_name are as specified for fgw_obj_new() */
int csch_view_eng_append(csch_view_t *view, const char *user_name, const char *eng_name, const char *file_name);
int csch_view_eng_insert_before(csch_view_t *view, const char *user_name, const char *eng_name, const char *file_name, int idx);

/* Remove a sheet from a project; returns the number of removals done,
   ideally 1. If it returns 0, sheet was not in the project, if >1,
   sheet was added multiple times (shouldn't happen) */
int csch_project_remove_sheet(csch_project_t *prj, csch_sheet_t *sheet);


/* Recalculate the ->hdr.fullpath and ->hdr.prjdir of prj using its
   ->hdr.loadname field */
int csch_proj_update_filename(csch_project_t *prj);

/* recalculate the filename (real, full path) of sheet, using prj's filename
   for CWD in case of relative path */
int csch_proj_sheet_update_filename(csch_project_t *prj, csch_sheet_t *sheet);

/* Remove and free all views of a project */
void csch_view_remove_all(csch_project_t *prj);

/* Renumber engine priorities, useful after a manual modification to the engine list */
void csch_view_renum(csch_view_t *view);

/* Return the stance value for a given stance name (config lookup) */
const char *csch_stance_get(const char *name);

/* Set the value of a named stance on the same config role the value is
   already set on, or on project level if stance was not defined */
int csch_stance_set(const char *name, const char *val);

/* Append val to the list of values for a named stance, if val is not
   already on the list. Operates on the same config role the stance value
   (not the list!) is on or on project level if stance was not defined */
int csch_stance_add_to_values(const char *name, const char *val);


/* Return a property of view prj:viewid, e.g. its "name"; returns NULL on
   error (or empty or not found) */
const char *csch_view_get_prop(csch_project_t *prj, int viewid, const char *name);


/*** loaders ***/
/* does not emit sheet post load event */
int csch_project_load_sheet(csch_project_t *prj, const char *fn, const char *fmt, csch_sheet_t **sheet_out, rnd_bool quiet, FILE *optf);
csch_project_t *csch_load_project_by_sheet_name(const char *sheet_load_fn, int with_sheets, rnd_bool quiet);


/*** implementation ***/
RND_INLINE csch_view_t *csch_view_get_current(csch_project_t *prj)
{
	if ((prj->curr < 0) || (prj->curr >= prj->views.used))
		return NULL;

	return prj->views.array[prj->curr];
}


/*** lib internal ***/

/* called by cschem_init() */
void csch_project_init(void);
void csch_project_uninit(void);

#endif
