/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2018 Tibor 'Igor2' Palinkas
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.*
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html
 *    mailing list: http://www.repo.hu/projects/sch-rnd/contact.html
 */


#ifndef CSCH_CONCRETE_PEN_H
#define CSCH_CONCRETE_PEN_H
#include "libcschem/concrete.h"
#include <librnd/core/color.h>

/* type=CSCH_CTYPE_PEN */

typedef enum csch_pen_shape_e {
	CSCH_PSHP_ROUND,
	CSCH_PSHP_SQUARE
} csch_pen_shape_t;

struct csch_cpen_s {
	csch_chdr_t hdr;

	csch_comm_str_t name;

	/* tip properties */
	csch_pen_shape_t shape;
	csch_coord_t size; /* diameter or edge length */
	rnd_color_t color;
	unsigned short dash;
	csch_coord_t dash_period;

	/* font properties */
	csch_coord_t font_height;
	char *font_family;
	char *font_style;

	/* cache for the lib and io code */
	unsigned copied_from_default:1;   /* set to 1 when a pen is copied from default sheet; reset on any change */

	/* fields that can be used by the application */
	void *font_handle;
	unsigned font_handle_valid:1;
};

/* the application is called back... (the application needs to load this) */
extern void (*csch_cb_pen_invalidate_font)(csch_sheet_t *sheet, csch_cpen_t *pen); /* remove font cache */

const char *csch_pen_shape_name(csch_pen_shape_t shape);


csch_cpen_t *csch_pen_alloc(csch_sheet_t *sheet, csch_cgrp_t *parent, const char *name);
csch_cpen_t *csch_pen_dup(csch_sheet_t *sheet, csch_cgrp_t *parent, const csch_cpen_t *src);
csch_cpen_t *csch_pen_dup2(csch_sheet_t *sheet, csch_cgrp_t *parent, const csch_cpen_t *src, const char *new_name);
void csch_pen_free(csch_cpen_t *pen);
csch_cpen_t *csch_pen_get(csch_sheet_t *sheet, csch_cgrp_t *grp, const char *name);
void csch_pen_modify_tip(csch_sheet_t *sheet, csch_cpen_t *pen, csch_pen_shape_t *shape, csch_coord_t *size, rnd_color_t *color, char **name, unsigned short *dash, csch_coord_t *dash_period, int undoable);
void csch_pen_modify_font(csch_sheet_t *sheet, csch_cpen_t *pen, csch_coord_t *font_height, char **font_family, char **font_style, int undoable);

unsigned csch_pen_hash(const csch_cpen_t *pen, csch_hash_ignore_t ignore);
int csch_pen_keyeq(const csch_cpen_t *p1, const csch_cpen_t *p2, csch_hash_ignore_t ignore);


extern csch_cpen_t csch_pen_default_unknown;

/* Look up pen by name from within grp or NULL */
csch_cpen_t *csch_pen_resolve(csch_cgrp_t *grp, const char *pen_name);


/* Return the object pen falling back to the "unknown pen" when not available */
RND_INLINE csch_cpen_t *csch_stroke_(csch_chdr_t *hdr)
{
	if (hdr->stroke == NULL) {
		csch_cgrp_t *grp = hdr->parent;
		while((hdr->stroke == NULL) && (grp != NULL) && csch_obj_is_grp(&grp->hdr)) {
			hdr->stroke = csch_pen_get(hdr->sheet, grp, hdr->stroke_name.str);
			grp = grp->hdr.parent;
		}
	}
	if (hdr->stroke == NULL)
		return &csch_pen_default_unknown;
	return hdr->stroke;
}
#define csch_stroke(sheet, obj) csch_stroke_(&(obj->hdr))

/* same as csch_stroke_() but with an option to use fallback pens from a group */
RND_INLINE csch_cpen_t *csch_stroke_fallback_(csch_chdr_t *hdr, csch_cgrp_t *fallback)
{
	csch_cpen_t *res = csch_stroke_(hdr);
	if ((res == &csch_pen_default_unknown) && (fallback != NULL)) {
		csch_cpen_t *fb = csch_pen_get(hdr->sheet, fallback, hdr->stroke_name.str);
		if (fb != NULL)
			return fb;
	}
	return res;
}
#define csch_stroke_fallback(sheet, obj, fb) csch_stroke_fallback_(&(obj->hdr), fb)

/* Return the object pen falling back to the "unknown pen" when not available */
RND_INLINE csch_cpen_t *csch_fill_(csch_chdr_t *hdr)
{
	if (hdr->fill == NULL) {
		csch_cgrp_t *grp = hdr->parent;
		while((hdr->fill == NULL) && (grp != NULL) && csch_obj_is_grp(&grp->hdr)) {
			hdr->fill = csch_pen_get(hdr->sheet, grp, hdr->fill_name.str);
			grp = grp->hdr.parent;
		}
	}
	if (hdr->fill == NULL)
		return &csch_pen_default_unknown;
	return hdr->fill;
}
#define csch_fill(sheet, obj) csch_fill_(&(obj->hdr))


/* same as csch_stroke_() but with an option to use fallback pens from a group */
RND_INLINE csch_cpen_t *csch_fill_fallback_(csch_chdr_t *hdr, csch_cgrp_t *fallback)
{
	csch_cpen_t *res = csch_fill_(hdr);
	if ((res == &csch_pen_default_unknown) && (fallback != NULL)) {
		csch_cpen_t *fb = csch_pen_get(hdr->sheet, fallback, hdr->fill_name.str);
		if (fb != NULL)
			return fb;
	}
	return res;
}
#define csch_fill_fallback(sheet, obj, fb) csch_fill_fallback_(&(obj->hdr), fb)

/* If tip is non-zero: remove cached ->pen pointers that depend on the given
   pen from all object headers that could have it, recursively down from pen's
   parent group.
   If remov is non-zero: the pen is also removed from the pen-name-hash (pen
   is being removed or renamed).
   If remov is non-zero: all text objects using this pen are font-invalidated */
void csch_pen_invalidate(csch_cpen_t *pen, int tip, int font, int remov);

/* Update all objects that has a specific pen as stroke; this recalculates obj
   bbox assuming the pen change may have changed the object's size */
void csch_pen_update_objs_for(csch_sheet_t *sheet, csch_cgrp_t *parent, csch_cpen_t *pen);

#endif
