/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer
 *  Copyright (C) 2019,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_line.h"
#include "obj_any.h"
#include "geo.h"
#include <gengeo2d/cline.h>

#include <librnd/hid/hid_inlines.h>

static void camv_line_free_fields(camv_any_obj_t *obj)
{
	/* no dynamic allocation */
}

static void camv_line_draw(camv_any_obj_t *obj, rnd_hid_gc_t gc, rnd_xform_mx_t *mx)
{
	rnd_coord_t x1, y1, x2, y2;

	if (mx != NULL) {
		x1 = rnd_xform_x((*mx), obj->line.x1, obj->line.y1); y1 = rnd_xform_y((*mx), obj->line.x1, obj->line.y1);
		x2 = rnd_xform_x((*mx), obj->line.x2, obj->line.y2); y2 = rnd_xform_y((*mx), obj->line.x2, obj->line.y2);
	}
	else {
		x1 = obj->line.x1; y1 = obj->line.y1;
		x2 = obj->line.x2; y2 = obj->line.y2;
	}

	rnd_hid_set_line_cap(gc, rnd_cap_round);
	rnd_hid_set_line_width(gc, obj->line.thick);
	rnd_render->draw_line(gc, x1, y1, x2, y2);
}

static void camv_line_bbox(camv_any_obj_t *obj)
{
	rnd_coord_t th = obj->line.thick/2;
	obj->line.bbox.x1 = MIN(obj->line.x1, obj->line.x2) - th;
	obj->line.bbox.x2 = MAX(obj->line.x1, obj->line.x2) + th;
	obj->line.bbox.y1 = MIN(obj->line.y1, obj->line.y2) - th;
	obj->line.bbox.y2 = MAX(obj->line.y1, obj->line.y2) + th;
	obj->line.bbox_valid = 1;
}

static void camv_line_copy(camv_any_obj_t *dst, const camv_any_obj_t *src)
{
	memcpy(&dst->line, &src->line, sizeof(camv_line_t));
}

static void camv_line_move(camv_any_obj_t *o, rnd_coord_t dx, rnd_coord_t dy)
{
	o->line.x1 += dx;
	o->line.x2 += dx;
	o->line.y1 += dy;
	o->line.y2 += dy;
	if (o->line.bbox_valid) {
		o->line.bbox.x1 += dx; o->line.bbox.y1 += dy;
		o->line.bbox.x2 += dx; o->line.bbox.y2 += dy;
	}
}

static camv_any_obj_t *camv_line_alloc(void) { return (camv_any_obj_t *)camv_line_new(); }

static int camv_line_isc_box(const camv_any_obj_t *o, const camv_rtree_box_t *box)
{
	g2d_cline_t sl;
	g2d_box_t bx;

TODO("geo: use sline instead of cline");
	bx.p1.x = box->x1 - o->line.thick/2; bx.p1.y = box->y1 - o->line.thick/2;
	bx.p2.x = box->x2 + o->line.thick/2; bx.p2.y = box->y2 + o->line.thick/2;

	sl.p1.x = o->line.x1; sl.p1.y = o->line.y1;
	sl.p2.x = o->line.x2; sl.p2.y = o->line.y2;
/*	sl.thickness = o->line.thickness */

	return g2d_isc_cline_box(&sl, &bx);
}


static const camv_objcalls_t camv_line_calls = {
	camv_line_alloc,
	camv_line_free_fields,
	camv_line_draw,
	camv_line_bbox,
	camv_line_copy,
	camv_line_move,
	camv_line_isc_box
};

void camv_line_init(camv_line_t *line)
{
	memset(line, 0, sizeof(camv_line_t));
	line->type = CAMV_OBJ_LINE;
	line->calls = &camv_line_calls;
}

camv_line_t *camv_line_new(void)
{
	camv_line_t *res = malloc(sizeof(camv_line_t));
	camv_line_init(res);
	return res;
}

