/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer
 *  Copyright (C) 2020,2023 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 "obj_text.h"
#include "obj_any.h"
#include "conf_core.h"

#include "geo.h"
#include <gengeo2d/box.h>
#include "obj_poly.h"

#include <librnd/hid/hid_inlines.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/rnd_conf.h>
#include <librnd/core/rotate.h>
#include <librnd/font/font.h>

static rnd_font_t embf_, *embf = &embf_;
rnd_font_t *camv_font = &embf_;

#include "font_internal.c"

static void camv_text_free_fields(camv_any_obj_t *obj)
{
	free(obj->text.s);
	obj->text.s = NULL;
}

static void camv_text_draw_atom_cb(void *cb_ctx, const rnd_glyph_atom_t *a)
{
	rnd_hid_gc_t gc = cb_ctx;
	long h;

	switch(a->type) {
		case RND_GLYPH_LINE:
			rnd_hid_set_line_width(gc, a->line.thickness);
			rnd_render->draw_line(gc, a->line.x1, a->line.y1, a->line.x2, a->line.y2);
			break;
		case RND_GLYPH_ARC:
			rnd_hid_set_line_width(gc, a->arc.thickness);
			rnd_render->draw_arc(gc, a->arc.cx, a->arc.cy, a->arc.r, a->arc.r, a->arc.start, a->arc.delta);
			break;
		case RND_GLYPH_POLY:
			h = a->poly.pts.used / 2;
			rnd_render->fill_polygon(gc, h, &a->poly.pts.array[0], &a->poly.pts.array[h]);
			break;
	}
}

static void camv_text_draw(camv_any_obj_t *obj, rnd_hid_gc_t gc, rnd_xform_mx_t *mx)
{
	rnd_font_draw_string(camv_font, (unsigned char *)obj->text.s, obj->text.x + obj->text.dx, obj->text.y + obj->text.dy, obj->text.scale, obj->text.scale, obj->text.rot, RND_FONT_MIRROR_Y, obj->text.thickness, 0, 0, RND_FONT_TINY_HIDE, camv_text_draw_atom_cb, gc);
}

static void camv_text_bbox(camv_any_obj_t *obj)
{
	int n;
	obj->text.bbox.x1 = obj->text.bbox.y1 = RND_COORD_MAX;
	obj->text.bbox.x2 = obj->text.bbox.y2 = -RND_COORD_MAX;
	for(n = 0; n < 4; n++) {
		if (obj->text.cx[n] < obj->text.bbox.x1) obj->text.bbox.x1 = obj->text.cx[n];
		if (obj->text.cx[n] > obj->text.bbox.x2) obj->text.bbox.x2 = obj->text.cx[n];
		if (obj->text.cy[n] < obj->text.bbox.y1) obj->text.bbox.y1 = obj->text.cy[n];
		if (obj->text.cy[n] > obj->text.bbox.y2) obj->text.bbox.y2 = obj->text.cy[n];
	}
	obj->text.bbox_valid = 1;
}

void camv_text_update(rnd_design_t *hidlib, camv_text_t *text, camv_layer_t *ly)
{
	rnd_coord_t cx[4], cy[4], w, h;

	/* measure width and height */
	rnd_font_string_bbox(cx, cy, camv_font, (unsigned char *)text->s, 0, 0, text->scale, text->scale, 0, RND_FONT_MIRROR_Y, text->thickness, 0);
	w = cx[1] - cx[0];
	h = cy[0] - cy[3];

	text->dx = -w/2;
	text->dy = h*1.5;

	if (text->rot != 0) {
		double rad = -text->rot / RND_RAD_TO_DEG;
		rnd_rotate(&text->dx, &text->dy, 0, 0, cos(rad), sin(rad));
	}

	rnd_font_string_bbox(text->cx, text->cy, camv_font, (unsigned char *)text->s, text->x + text->dx, text->y + text->dy, text->scale, text->scale, text->rot, RND_FONT_MIRROR_Y, text->thickness, 0);
	camv_text_bbox((camv_any_obj_t *)text);
}

static void camv_text_copy(camv_any_obj_t *dst, const camv_any_obj_t *src)
{
	memcpy(&dst->text, &src->text, sizeof(camv_text_t));
	dst->text.s = rnd_strdup(src->text.s);
}

static void camv_text_move(camv_any_obj_t *o, rnd_coord_t dx, rnd_coord_t dy)
{
	int n;
	o->text.x += dx;
	o->text.y += dy;
	for(n = 0; n < 4; n++) {
		o->text.cx[n] += dx;
		o->text.cy[n] += dy;
	}
	if (o->text.bbox_valid) {
		o->text.bbox.x1 += dx; o->text.bbox.y1 += dy;
		o->text.bbox.x2 += dx; o->text.bbox.y2 += dy;
	}
}

static camv_any_obj_t *camv_text_alloc(void) { return (camv_any_obj_t *)camv_text_new(); }

static int camv_text_isc_box(const camv_any_obj_t *o, const camv_rtree_box_t *box)
{
	camv_any_obj_t op;
	rnd_coord_t xy[8];

	op.poly.points.alloced = op.poly.points.used = 8;
	op.poly.points.array = xy;
	op.poly.x = xy;
	op.poly.y = xy+4;

	return 0;

	TODO("TODO: text may be rotated; use rotated box; see sch-rnd text_isc_with_box() triangle tests");
	return camv_poly_isc_box(&op, box);
}

static const camv_objcalls_t camv_text_calls = {
	camv_text_alloc,
	camv_text_free_fields,
	camv_text_draw,
	camv_text_bbox,
	camv_text_copy,
	camv_text_move,
	camv_text_isc_box
};

void camv_text_init(camv_text_t *text)
{
	memset(text, 0, sizeof(camv_text_t));
	text->type = CAMV_OBJ_TEXT;
	text->calls = &camv_text_calls;
	text->scale = 1.0;
	text->thickness = 0;
}

camv_text_t *camv_text_new(void)
{
	camv_text_t *res = malloc(sizeof(camv_text_t));
	camv_text_init(res);
	return res;
}

void camv_font_init(void)
{
	rnd_font_load_internal(embf, embf_font, sizeof(embf_font) / sizeof(embf_font[0]), embf_minx, embf_miny, embf_maxx, embf_maxy);
}
