/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer - low level gerber parser
 *  Copyright (C) 2019 Tibor 'Igor2' Palinkas
 *
 *  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/camv-rnd
 *    lead developer: http://repo.hu/projects/camv-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

#ifndef GEDRAW_H
#define GEDRAW_H

#include <stdlib.h>
#include <stdio.h>
#include <genht/htip.h>
#include <genht/hash.h>
#include <genvector/vtp0.h>

#include <librnd/core/global_typedefs.h>
#include <librnd/core/vtc0.h>
#include "gexpr.h"

typedef rnd_coord_t ge_coord_t; /* nanometer */
typedef rnd_angle_t ge_angle_t; /* degree */

typedef enum {
	GEP_NEXT, /* all fine, read the next char */
	GEP_END,  /* all fine, end of stream */
	GEP_ERROR /* stop reading */
} ge_parse_res_t;

typedef enum {
	GEU_NONE = 0,
	GEU_INCH,
	GEU_MM
} ge_unit_t;

typedef enum {
	GEA_CIRC,
	GEA_RECT,
	GEA_OBLONG,
	GEA_POLY,
	GEA_MACRO
} ge_aper_shape_t;

typedef enum {
	GEMO_CIRC = 1,
	GEMO_POLY = 4,
	GEMO_REGPOLY = 5,
	GEMO_MOIRE = 6,
	GEMO_THERM = 7,
	GEMO_LINE_XY = 20,
	GEMO_LINE_WH = 21,

	GEMO_SET /* this one doesn't have a numeric code but it is really just an instruction; operant[0] is target param idx, operand[1] is the expression */
} ge_macro_op_t;

typedef struct ge_macro_line_s ge_macro_line_t;
struct ge_macro_line_s {
	ge_macro_op_t op;            /* operator: type of primitive */
	vtp0_t operand;              /* each entry is the first item of a linked list of a (ge_expr_prg_t *) */
	int idx;                     /* only for GEMO_SET: target index, so it doesn't need to be converted to an expression */
	ge_macro_line_t *next;
};

typedef struct ge_aper_macro_s {
	ge_macro_line_t *line1; /* frist line of a singly linked list of macro lines to execute in order */
	ge_macro_line_t *last;  /* last line of a singly linked list of macro lines (for cheap append) */
	int argc;
	double *argv;
} ge_aper_macro_t;

typedef struct {
	ge_aper_shape_t shape; /* macro aper doesn't have it */
	ge_coord_t hole;       /* macro aper doesn't have it */
	union {
		struct {
			ge_coord_t dia;
		} circ;
		struct {
			ge_coord_t xs, ys;
		} rect;
		struct {
			ge_coord_t xs, ys;
		} oblong;
		struct {
			ge_coord_t dia, corners;
			ge_angle_t rot;
		} poly;
		struct {
			const char *name; /* allocated in the macro hash (as key) */
			const ge_aper_macro_t *am; /* allocated in the macro hash (as value) */
			vtd0_t param; /* only for aperture def */
		} macro;
	} data;
	long id;
	void *cached; /* optional: generated/cached prototype, specific ot the drawing code */
} ge_aper_t;

typedef enum { /* interpolation mode */
	GEI_LIN = 0, /* linear (default) */
	GEI_CW,      /* circular, clock-wise */
	GEI_CCW      /* circular, counter-clock-wise */
} ge_interp_t;

typedef enum {     /* circular interpolation quadrants */
	GEQ_INVALID = 0, /* default: invalid, yields error */
	GEQ_SINGLE,      /* span must be less than 90 deg */
	GEQ_MULTI        /* span may be more than 90 deg */
} ge_quadr_t;

typedef struct {
	int x, y; /* x and y repeat */
	ge_coord_t i, j;
	int end; /* coords are invalid */
} ge_steprep_t;

typedef enum {    /* field to use */
	GEC_invalid = 0,
	GEC_MACRO_DEF,  /* -> aper */
	GEC_APER_DEF,   /* -> aper */
	GEC_APER_SEL,   /* -> id */
	GEC_DRAW,       /* n/a */
	GEC_MOVE,       /* n/a */
	GEC_FLASH,      /* n/a */
	GEC_DO,         /* n/a */
	GEC_STEPREP,    /* -> steprep */
	GEC_SET_X,      /* -> coord */
	GEC_SET_Y,      /* -> coord */
	GEC_SET_I,      /* -> coord */
	GEC_SET_J,      /* -> coord */
	GEC_SET_RELCRD, /* -> on (relative coordinates) */
	GEC_SET_POLCLR, /* -> on (polarity; when on, clear instead of draw (negative polarity)) */
	GEC_SET_POLY,   /* -> on */
	GEC_SET_RELAT,  /* -> on */
	GEC_SET_INTERP, /* -> interp */
	GEC_SET_QUADR   /* -> quadr */
} gedraw_cmd_t;

typedef struct {
	gedraw_cmd_t cmd;
	union {
		ge_aper_t aper;
		ge_coord_t coord;
		int on;
		long id;
		ge_interp_t interp;
		ge_quadr_t quadr;
		ge_steprep_t steprep;
	} data;

	long line, col; /* location in the input file for error messages */
} gedraw_inst_t;

#define GVT(x) vtgd_ ## x
#define GVT_ELEM_TYPE gedraw_inst_t
#define GVT_SIZE_TYPE size_t
#define GVT_DOUBLING_THRS 4096
#define GVT_START_SIZE 32
#define GVT_FUNC
#define GVT_SET_NEW_BYTES_TO 0

#include <genvector/genvector_impl.h>
#define GVT_REALLOC(vect, ptr, size)  realloc(ptr, size)
#define GVT_FREE(vect, ptr)           free(ptr)
#include <genvector/genvector_undef.h>

typedef struct {
	ge_unit_t aper_unit;          /* unit used for macro apertures */
	rnd_coord_t acceptable_error; /* depends on coord precision determined by the parser */
	unsigned aper_inited:1; /* aperutre hash initialized */
	unsigned poly_closed:1; /* set by the contour append code if current polyline is closed at the moment (curos is at starting point) */
	ge_interp_t interp;
	ge_quadr_t quadr;
	htip_t aper;
	vtgd_t code;
	vtc0_t contour;/* polygon drawing state */
	rnd_coord_t ox, oy; /* rendering origin - 0;0 for the main drawing, modified by SR */
	long line, col; /* location in the source file (as seen from the last instruction, the one being executed at the time of draw) */
} gedraw_ctx_t;

gedraw_inst_t *gedraw_alloc(gedraw_ctx_t *ctx, long line, long col);

void gedraw_dump_inst(FILE *f, gedraw_ctx_t *ctx, gedraw_inst_t *i);
void gedraw_dump_code(FILE *f, gedraw_ctx_t *ctx);

void gedraw_free(gedraw_ctx_t *ctx);


#endif
