/*
 *                            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")
 */

#include <librnd/config.h>

#include <string.h>

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

#define GVT_DONT_UNDEF
#include "gedraw.h"
#include <genvector/genvector_impl.c>
#undef GVT_DONT_UNDEF

#include "geparse.h"

gedraw_inst_t *gedraw_alloc(gedraw_ctx_t *ctx, long line, long col)
{
	gedraw_inst_t *i;
	i = vtgd_alloc_append(&ctx->code, 1);
	i->line = line;
	i->col = col;
	return i;
}

void gedraw_dump_inst(FILE *f, gedraw_ctx_t *ctx, gedraw_inst_t *i)
{
	fprintf(f, "[%04ld %04ld.%02ld]    ", (long)(i - ctx->code.array), (long)i->line, (long)i->col);
	switch(i->cmd) {
		case GEC_invalid:    fprintf(f, "invalid\n"); break;
		case GEC_MACRO_DEF:  fprintf(f, "MACRO_DEF %s\n", i->data.aper.data.macro.name); break;
		case GEC_APER_DEF:   fprintf(f, "APER_DEF %ld\n", i->data.aper.id); break;
		case GEC_APER_SEL:   fprintf(f, "APER_SEL %ld\n", i->data.id); break;
		case GEC_DRAW:       fprintf(f, "DRAW\n"); break;
		case GEC_MOVE:       fprintf(f, "MOVE\n"); break;
		case GEC_FLASH:      fprintf(f, "FLASH\n"); break;
		case GEC_DO:         fprintf(f, "DO\n"); break;
		case GEC_SET_X:      fprintf(f, "X %f mm\n", i->data.coord / 1000000.0); break;
		case GEC_SET_Y:      fprintf(f, "Y %f mm\n", i->data.coord / 1000000.0); break;
		case GEC_SET_I:      fprintf(f, "I %f mm\n", i->data.coord / 1000000.0); break;
		case GEC_SET_J:      fprintf(f, "J %f mm\n", i->data.coord / 1000000.0); break;
		case GEC_SET_RELCRD: fprintf(f, "RELCRD %s\n", i->data.on ? "on" : "off"); break;
		case GEC_SET_POLCLR: fprintf(f, "POLCLR %s\n", i->data.on ? "clear" : "draw"); break;
		case GEC_SET_POLY:   fprintf(f, "POLY %s\n", i->data.on ? "on" : "off"); break;
		case GEC_SET_RELAT:  fprintf(f, "RELAT %s\n", i->data.on ? "on" : "off"); break;
		case GEC_SET_INTERP:
			switch(i->data.interp) {
				case GEI_LIN:    fprintf(f, "INTERP linear\n"); break;
				case GEI_CW:     fprintf(f, "INTERP cw\n"); break;
				case GEI_CCW:    fprintf(f, "INTERP ccw\n"); break;
			}
			break;
		case GEC_SET_QUADR:
			switch(i->data.quadr) {
				case GEQ_INVALID:fprintf(f, "QUADR !!!invalid!!!\n"); break;
				case GEQ_SINGLE: fprintf(f, "QUADR single\n"); break;
				case GEQ_MULTI:  fprintf(f, "QUADR multi\n"); break;
			}
			break;
		case GEC_STEPREP:
			if (i->data.steprep.end)
				fprintf(f, "STEPREP end\n");
			else
				fprintf(f, "STEPREP %d;%d %f;%f\n", i->data.steprep.x, i->data.steprep.y, i->data.steprep.i / 1000000.0, i->data.steprep.j / 1000000.0);
			break;
	}
}

void gedraw_dump_code(FILE *f, gedraw_ctx_t *ctx)
{
	gedraw_inst_t *i;
	size_t n;
	for(n = 0, i = ctx->code.array; n < ctx->code.used; n++,i++)
		gedraw_dump_inst(f, ctx, i);
}

void gedraw_free(gedraw_ctx_t *ctx)
{
	gedraw_inst_t *i;
	size_t n;
	for(n = 0, i = ctx->code.array; n < ctx->code.used; n++,i++)
		if (i->cmd == GEC_APER_DEF)
			vtd0_uninit(&i->data.aper.data.macro.param);

	vtgd_uninit(&ctx->code);
}
