/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  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_TEXT_H
#define CSCH_CONCRETE_TEXT_H
#include "libcschem/concrete.h"
#include GENGEO2D_TYPECFG
#include "gengeo2d/prim.h"

/* type=CSCH_CTYPE_TEXT */

typedef enum {
	CSCH_HALIGN_START,
	CSCH_HALIGN_CENTER,
	CSCH_HALIGN_END,
	CSCH_HALIGN_WORD_JUST,
	CSCH_HALIGN_JUST,
	CSCH_HALIGN_invalid
} csch_halign_t;

const char *csch_halign2str(csch_halign_t halign);
csch_halign_t csch_str2halign(const char *s);
extern const char *csch_halign_names[]; /* NULL terminated */

typedef struct csch_text_s {
	csch_chdr_t hdr;
	g2d_vect_t spec1, spec2;  /* x1,y1 and x2,y2 as specified */
	double spec_rot;          /* rotation, as specified */
	double inst_rot;          /* instance rotation (with all transformations) */
	csch_halign_t halign;
	char *text;               /* DO NOT USE: in case of dyntext this is only the template, see rtext below; call csch_text_get_rtext() instead */
	unsigned has_bbox:1;      /* x2 and y2 are specified; when 0, spec2 is calculated and not saved */
	unsigned dyntext:1;
	unsigned spec_mirx:1;
	unsigned spec_miry:1;

	unsigned inst_mirx:1;
	unsigned inst_miry:1;
	double inst_raw_rot;

	/* cached */
	unsigned bbox_calced:1;    /* when has_bbox==0, we need to get the app calculate spec2 - when this is 1, it is already calculated */
	unsigned bbox_calcing:1;   /* the above calculation is taking palce, lock recursion */
	g2d_vect_t inst1,  inst2;  /* instance: as transformed from the spec */
	g2d_vect_t inst15, inst25; /* instance: the other two corners; order: inst1, inst15, inst2, inst25 */
	g2d_vect_t spec15, spec25;
	char *rtext;               /* rendered text; in case of dyntext it differs from ->text, this one is the substituted version */

	/* the application may use these fields to store a rendered font info */
	void *pixmap;
	long pix_sx, pix_sy;
	csch_coord_t crd_sx, crd_sy, net_sx, net_sy, off_x, off_y, extra_spc, extra_glyph;
	double scale;

	/* the application may use these fields to store temporary data e.g. while loading a file */
	union {
		long l;
		void *p;
	} tmp[4];
} csch_text_t;

#include <libcschem/cnc_text_dyn.h>

/* the application is called back... (the application needs to load this) */
extern void (*csch_cb_text_invalidate_font)(csch_sheet_t *sheet, csch_text_t *text); /* remove font pixmap/cache */
extern void (*csch_cb_text_calc_bbox)(csch_sheet_t *sheet, csch_text_t *text); /* calculate bounding box for a text that doesn't have ->has_bbox set */

csch_text_t *csch_text_alloc(csch_sheet_t *sheet, csch_cgrp_t *parent, csch_oid_t oid);
csch_text_t *csch_text_dup(csch_sheet_t *sheet, csch_cgrp_t *parent, const csch_text_t *src, int keep_id, int inst2spec);
void csch_text_free(csch_text_t *text);
csch_text_t *csch_text_get(csch_sheet_t *sheet, csch_cgrp_t *grp, csch_oid_t oid);
void csch_text_update(csch_sheet_t *sheet, csch_text_t *text, int do_xform);

/* if text is not NULL, it's strdup'd */
void csch_text_modify(csch_sheet_t *sheet, csch_text_t *texto,
	csch_coord_t *x1, csch_coord_t *y1, csch_coord_t *x2, csch_coord_t *y2,
	double *rot, int *mirx, int *miry, csch_halign_t *halign, const char **text,
	int *has_bbox, int *dyntext, int undoable, int relative);

unsigned csch_text_hash(const csch_text_t *text, csch_hash_ignore_t ignore);
int csch_text_keyeq(const csch_text_t *t1, const csch_text_t *t2, csch_hash_ignore_t ignore);

/* non-standard calls */

/* Force application to re-render the text (drop render cache) */
void csch_text_invalidate_font(csch_text_t *text);

/* Invalidate and redraw all text objects; if dynonly is 1, do this only
   on text objects marked as dyntext but also make sure their render-text are
   re-generated too */
void csch_text_invalidate_all_grp(csch_cgrp_t *grp, int dynonly);
void csch_text_invalidate_all_sheet(csch_sheet_t *sheet, int dynonly);
void csch_text_invalidate_all_project(csch_project_t *prj, int dynonly);

/* Return rendered text; never returns NULL. */
RND_INLINE const char *csch_text_get_rtext(csch_text_t *text);

/* Return the number of non-7-bit-ASCII-printable characters in rendered
   txt string */
int csch_text_invalid_chars(csch_text_t *txt);


/*** Implementation ***/
RND_INLINE const char *csch_text_get_rtext(csch_text_t *text)
{
	if (text->rtext == NULL)
		csch_text_dyntext_render(text);

	if (text->rtext == NULL)
		return "";

	return text->rtext;
}

#endif
