#include <libcschem/plug_io.h>
#include <genlist/gendlist.h>
#include <librnd/core/hidlib.h>
#include "altium_kw_sphash.h"

typedef struct altium_field_s {
	altium_kw_field_keys_t type; /* derived from ->key */
	const char *key;
	enum { ALTIUM_FT_STR, ALTIUM_FT_CRD, ALTIUM_FT_DBL, ALTIUM_FT_LNG } val_type;
	union {
		const char *str;
		rnd_coord_t crd;
		double dbl;
		long lng;                  /* also used for bool */
	} val;
	gdl_elem_t link;             /* in parent record */
} altium_field_t;

typedef struct altium_record_s {
	altium_kw_record_keys_t type; /* derived from ->type_s */
	const char *type_s;
	long idx;                     /* 0-based index of RECORDs within the file - SchDoc references by this */
	void *user_data;
	gdl_list_t fields;
	gdl_elem_t link;              /* in tree records */
} altium_record_t;

typedef struct altium_block_s {
	gdl_elem_t link;              /* in tree blocks */
	long size;                    /* allocated size of raw */
	char raw[1];                  /* bytes read from the file */
} altium_block_t;

typedef struct altium_tree_s {
	gdl_list_t rec[altium_kw_record_SPHASH_MAXVAL+1]; /* ordered list of records per type */
	gdl_list_t blocks;
} altium_tree_t;

#define altium_kw_AUTO (-2)
altium_record_t *pcbdoc_ascii_new_rec(altium_tree_t *tree, const char *type_s, int type);
altium_field_t *pcbdoc_ascii_new_field(altium_tree_t *tree, altium_record_t *rec, const char *key, int kw, const char *val);

/* Parse '|' separated fields and allocate new altium_field_t's for them and
   put them under rec. Return 0 on success. Stop at \n, 'fields' points to
   the next char after the \n */
int pcbdoc_ascii_parse_fields(altium_tree_t *tree, altium_record_t *rec, const char *fn, long line, char **fields);

int pcbdoc_ascii_parse_blocks(altium_tree_t *tree, const char *fn);

int pcbdoc_ascii_load_blocks(altium_tree_t *tree, FILE *f, long max);


void altium_tree_free(altium_tree_t *tree);


#include <plugins/lib_alien/read_helper.h>
#include <plugins/lib_alien/read_postproc.h>
#include <genht/htip.h>

typedef struct io_altium_rctx_s {
	altium_tree_t tree;
	const char *fn;
	htip_t id2rec;
	csch_alien_read_ctx_t alien;
	unsigned silent:1;
} io_altium_rctx_t;

#define error_(ctx, rec, args) \
	do { \
		if (!ctx->silent) { \
			altium_record_t *__rec__ = rec; \
			if (__rec__ != NULL) \
				rnd_message(RND_MSG_ERROR, "altium parse error at %s rec #%ld:\n", (ctx)->fn, (long)((__rec__)->idx)); \
			else \
				rnd_message(RND_MSG_ERROR, "altium parse error at %s:\n", (ctx)->fn); \
			rnd_msg_error args; \
		} \
	} while(0)

#define error(node, args) error_(rctx, node, args)
