#include "apricot.h"
#include "Drawable.h"
#include "Drawable_private.h"

#ifdef __cplusplus
extern "C" {
#endif

void
Drawable_clear_font_abc_caches( Handle self)
{
	PList u;
	if (( u = var-> font_abc_glyphs)) {
		int i;
		for ( i = 0; i < u-> count; i += 2)
			free(( void*) u-> items[ i + 1]);
		plist_destroy( u);
		var-> font_abc_glyphs = NULL;
	}
	if (( u = var-> font_abc_unicode)) {
		int i;
		for ( i = 0; i < u-> count; i += 2)
			free(( void*) u-> items[ i + 1]);
		plist_destroy( u);
		var-> font_abc_unicode = NULL;
	}
	if ( var-> font_abc_ascii) {
		free( var-> font_abc_ascii);
		var-> font_abc_ascii = NULL;
	}
	if ( var-> font_abc_glyphs_ranges ) {
		free(var-> font_abc_glyphs_ranges);
		var-> font_abc_glyphs_ranges = NULL;
		var-> font_abc_glyphs_n_ranges = 0;
	}
}


Font *
Drawable_font_match( char * dummy, Font * source, Font * dest, Bool pick)
{
	if ( pick)
		apc_font_pick( NULL_HANDLE, source, dest);
	else
		Drawable_font_add( NULL_HANDLE, source, dest);
	return dest;
}

Bool
Drawable_font_add( Handle self, Font * source, Font * dest)
{
#define SRC(x)  (!source->undef.x)
#define DST(x)  (!dest->undef.x)
#define COPY(x) if (SRC(x)) { dest->x = source->x; dest->undef.x = 0; }

	/* assigning values */
	if ( dest != source) {
		COPY(height);
		COPY(width);
		COPY(direction);
		COPY(style);
		COPY(pitch);
		COPY(size);
		COPY(vector);
		if (SRC(name)) {
			strcpy( dest-> name, source-> name);
			dest->is_utf8.name = source->is_utf8.name;
			dest->undef.name = 0;
		}
		if ( SRC(encoding)) {
			strcpy( dest-> encoding, source-> encoding);
			dest->is_utf8.encoding = source->is_utf8.encoding;
			dest->undef.encoding = 0;
		}
	}

	/* resolving ambiguities */
	if ( SRC(height))
		dest->undef.size   = 1;
	else if (SRC(size))
		dest->undef.height = 1;
	if ( DST(size) && DST(height))
		dest->undef.size   = 1;

	if ( !SRC(width) && (DST(pitch) || DST(height) || DST(name) || DST(size) || DST(direction) || DST(style)))
		dest->undef.width  = 1;
	if ( !SRC(pitch) && (DST(name) || DST(size) || DST(direction) || DST(style)))
		dest->undef.pitch  = 1;

	/* syncing undef flags with values that are treated as undefs in the apc */
	/* size,height,style,direction, and encoding don't have speclly treated values */
	if ( dest-> pitch == fpDefault)
		dest->undef.pitch  = 1;
	if ( dest-> vector == fvDefault)
		dest->undef.vector = 1;
	if ( dest-> width == 0)
		dest->undef.width  = 1;
	if ( dest-> name[0] == 0 || strcmp(dest->name, "Default") == 0 ) {
		dest->undef.name   = 1;
	}

	/* ... and in the other direction */
	if ( !DST(size))
		dest->size         = 0;
	if ( !DST(height))
		dest->height       = 0;
	if ( !DST(direction))
		dest->direction    = 0;
	if ( !DST(style))
		dest->style        = 0;
	if ( !DST(pitch))
		dest->pitch        = fpDefault;
	if ( !DST(vector))
		dest->vector       = fvDefault;
	if ( !DST(width))
		dest->width        = 0;
	if ( !DST(name)) {
		strcpy( dest-> name, "Default");
		dest->is_utf8.name = false;
	}
	if ( !DST(encoding))
		dest->encoding[0]  = 0;

	/* validating the good entries */
#define CLAMP(x) if ( DST(x) && dest->x <= 0) dest->x = 1; else if ( dest->x > 16383 ) dest->x = 16383
	CLAMP(size);
	CLAMP(height);
	CLAMP(width);
#undef CLAMP

	if (DST(size))
		dest-> size = FONT_SIZE_ROUND(dest->size);

	return dest->undef.height;
#undef SRC
#undef DST
#undef COPY
}

SV *
Drawable_get_font_abcdef( Handle self, int first, int last, int flags, PFontABC (*func)(Handle, int, int, int))
{
	int i;
	AV * av;
	PFontABC abc;

	if ( first < 0) first = 0;
	if ( last  < 0) last  = 255;

	if ( flags & toGlyphs )
		flags &= ~toUTF8;
	else if ( !(flags & toUTF8)) {
		if ( first > 255) first = 255;
		if ( last  > 255) last  = 255;
	}

	if ( first > last)
		abc = NULL;
	else {
		dmARGS;
		dmENTER( newRV_noinc(( SV *) newAV()));
		abc = func( self, first, last, flags );
		dmLEAVE;
	}

	av = newAV();
	if ( abc != NULL) {
		for ( i = 0; i <= last - first; i++) {
			av_push( av, newSVnv( abc[ i]. a));
			av_push( av, newSVnv( abc[ i]. b));
			av_push( av, newSVnv( abc[ i]. c));
		}
		free( abc);
	}
	return newRV_noinc(( SV *) av);
}

SV *
Drawable_get_font_abc( Handle self, int first, int last, int flags)
{
	dmCHECK(NULL_SV);
	return Drawable_get_font_abcdef( self, first, last, flags, apc_gp_get_font_abc);
}

SV *
Drawable_get_font_def( Handle self, int first, int last, int flags)
{
	dmCHECK(NULL_SV);
	return Drawable_get_font_abcdef( self, first, last, flags, apc_gp_get_font_def);
}

SV *
Drawable_get_font_languages( Handle self)
{
	char *buf, *p;
	AV * av = newAV();
	dmARGS;

	dmCHECK(NULL_SV);
	dmENTER( newRV_noinc(( SV *) av));
	p = buf = apc_gp_get_font_languages( self);
	dmLEAVE;
	if (p) {
		while (*p) {
			int len = strlen(p);
			av_push(av, newSVpv(p, len));
			p += len + 1;
		}
		free(buf);
	}
	return newRV_noinc(( SV *) av);
}

SV *
Drawable_get_font_ranges( Handle self)
{
	int count = 0;
	unsigned long * ret;
	AV * av = newAV();
	dmARGS;

	dmCHECK(NULL_SV);
	dmENTER( newRV_noinc(( SV *) av));
	ret = apc_gp_get_font_ranges( self, &count);
	dmLEAVE;
	if ( ret) {
		int i;
		for ( i = 0; i < count; i++)
			av_push( av, newSViv( ret[i]));
		free( ret);
	}
	return newRV_noinc(( SV *) av);
}

Font
Drawable_get_font( Handle self)
{
	return var-> font;
}

void
Drawable_set_font( Handle self, Font font)
{
	Drawable_clear_font_abc_caches( self);
	apc_font_pick( self, &font, &var-> font);
	apc_gp_set_font( self, &var-> font);
	opt_clear(optFontTrigCache);
}


#ifdef __cplusplus
}
#endif
