/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - property editor plugin
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *  (Adapted from propsel code in pcb-rnd by the same author)
 *
 *  (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., 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
 */

/* This API builds and maintains a collection of values for each named property.
   A value can be added any time. All values ever seen for a property is stored.
   Duplicate values per property are stored only once, but number of occurence
   per value (per property) is kept track on. Typically at the end of
   a query, but generally ny time, the caller may query for:
    - all known properties (it's a htsp)
    - all known values of a property
    - statistics of values of a property
*/

#include <limits.h>
#include <librnd/core/global_typedefs.h>
#include <libcschem/concrete.h>
#include <libminuid/libminuid.h>
#include <genht/htsp.h>
#include <genvector/vtl0.h>

typedef enum {
	CSCH_PROPT_invalid,
	CSCH_PROPT_STRING,
	CSCH_PROPT_COORD,
	CSCH_PROPT_ANGLE,
	CSCH_PROPT_DOUBLE,
	CSCH_PROPT_INT,
	CSCH_PROPT_BOOL,
	CSCH_PROPT_COMMS,
	CSCH_PROPT_ENUM,
	CSCH_PROPT_ATTRARR,
	CSCH_PROPT_UUID,
	CSCH_PROPT_max
} csch_prop_type_t;

typedef enum {
	CSCH_PROPCT_STRING = 0, /* default */
	CSCH_PROPCT_PEN
} csch_prop_comms_type_t;

typedef union {
	const char *string;
	csch_coord_t coord;
	rnd_angle_t angle;
	int i;
	double d;
	csch_comm_str_t comms;
	int attrarr;
	minuid_bin_t u;
} csch_propval_t;

typedef csch_propval_t htprop_key_t;
typedef unsigned long int htprop_value_t;
#define HT(x) htprop_ ## x
#include <genht/ht.h>
#undef HT

typedef struct {
	csch_prop_type_t type;
	csch_prop_comms_type_t comms_type; /* when type == CSCH_PROPT_COMMS: determine input method */
	const char **enum_names;
	htprop_t values;
	unsigned core:1;  /* 1 if it is a core property */
} csch_props_t;

typedef struct {
	htsp_t props;

	/* scope */
	csch_sheet_t *sheet;
	csch_cgrp_t *grp;
	htsp_t nets;

	/* target objects */
	csch_oidpath_list_t objs;
	unsigned use_selection:1;  /* all selected objects on the current pcb */
	unsigned use_sheet:1;      /* run on the board too */
	unsigned geo:1;            /* include fields related to geometry of objects */
	unsigned aregex:1;         /* when 1, attribute key is a regex */

	/* internal/cache */
	void *rx;
} csch_propedit_t;

/* A property list (props) is a string->csch_props_t. Each entry is a named
   property with a value that's a type and a value hash (vhash). vhash's
   key is each value that the property ever took, and vhash's value is an
   integer value of how many times the given property is taken */
void csch_props_init(csch_propedit_t *ctx, csch_sheet_t *sheet, csch_cgrp_t *grp);
void csch_props_uninit(csch_propedit_t *ctx);


/* Reset stored values from the hash (ctx->props) */
void csch_props_reset(csch_propedit_t *ctx);

/* Free and remove all items from the hash (ctx->props) */
void csch_props_clear(csch_propedit_t *ctx);

/* Add a value of a named property; if the value is already known, its counter
   is increased. If propname didn't exist, create it. Returns NULL on error.
   Error conditions:
    - invalid type
    - mismatching type for the property (all values of a given property must be the same)
*/
csch_props_t *csch_props_add(csch_propedit_t *ctx, const char *propname, csch_prop_type_t type, csch_propval_t val);

/* Retrieve values for a prop - returns NULL if propname doesn't exist */
csch_props_t *csch_props_get(csch_propedit_t *ctx, const char *propname);


/* Return the type name of a property type or NULL on error. */
const char *csch_props_type_name(csch_prop_type_t type);

/* Look up property p and calculate statistics for all values occured so far.
   Any of most_common, min, max and avg can be NULL. Returns non-zero if propname
   doesn't exist or stat values that can not be calculated for the given type
   are not NULL. Invalid type/stat combinations:
     type=string   min, max, avg
*/
int csch_props_stat(csch_propedit_t *ctx, csch_props_t *p, csch_propval_t *most_common, csch_propval_t *min, csch_propval_t *max, csch_propval_t *avg);

/* Return a key=NULL terminated array of all entries from the hash, alphabetically sorted */
htsp_entry_t *csch_props_sort(csch_propedit_t *ctx);

/* If propedit context is for a single object, return that object, else
   return NULL */
csch_oidpath_t *prop_scope_single_obj(csch_propedit_t *pe);
