/************************************************************************/
/*  Color mangement on X11: Try to get around the limitations.		*/
/************************************************************************/

#   include	"appFrameConfig.h"

#   include	<stddef.h>
#   include	<stdio.h>
#   include	<stdlib.h>

#   include	<appDebugon.h>

#   ifdef	USE_GTK

#   include	"drawUtilGtk.h"

/************************************************************************/
/*									*/
/*  Allocate approximate colors.					*/
/*									*/
/************************************************************************/

/***/

static int appColorAllocSystemColor(	AllocatorColor *	acRes,
					const AllocatorColor *	acScratch,
					AppColors *		acSys )
    {
    APP_COLOR_RGB		xc;

    xc.red= acScratch->acRed;
    xc.green= acScratch->acGreen;
    xc.blue= acScratch->acBlue;

    if  ( ! gdk_color_alloc( acSys->acColormap, &xc ) )
	{ LDEB(1); return -1;	}

    acRes->acAllocated= AC_ALLOCATED;
    acRes->acRed= xc.red;
    acRes->acGreen= xc.green;
    acRes->acBlue= xc.blue;
    acRes->acColorNumber= xc.pixel;

    return 0;
    }

static int appColorRgb111(	AllocatorColor *	ac,
				ColorAllocator *	ca,
				unsigned int		r,
				unsigned int		g,
				unsigned int		b )
    {
    AllocatorColor	acScratch;
    AllocatorColor *	acRes;

    bmColorRgbDirect( &acScratch, ca, r, g, b );

    acRes= &(ca->ca222Colors[acScratch.acColorNumber]);

    if  ( acRes->acAllocated == AC_UNALLOCATED )
	{
	AppColors *	acSys= (AppColors *)ca->caSystemPrivate;

	if  ( appColorAllocSystemColor( acRes, &acScratch, acSys ) )
	    { LDEB(acScratch.acColorNumber); return -1;	}
	}

    *ac= *acRes;
    ac->acAllocated= AC_COPIED;

    return 0;
    }

static int appColorRgb222(	AllocatorColor *	ac,
				ColorAllocator *	ca,
				unsigned int		r,
				unsigned int		g,
				unsigned int		b )
    {
    AllocatorColor	acScratch;
    AllocatorColor *	acRes;

    bmColorRgbDirect( &acScratch, ca, r, g, b );

    acRes= &(ca->ca222Colors[acScratch.acColorNumber]);

    if  ( acRes->acAllocated == AC_UNALLOCATED )
	{
	AppColors *	acSys= (AppColors *)ca->caSystemPrivate;

	if  ( appColorAllocSystemColor( acRes, &acScratch, acSys ) )
	    { LDEB(acScratch.acColorNumber); return -1;	}
	}

    *ac= *acRes;
    ac->acAllocated= AC_COPIED;

    return 0;
    }

static int appColorRgb555(	AllocatorColor *	ac,
				ColorAllocator *	ca,
				unsigned int		r,
				unsigned int		g,
				unsigned int		b )
    {
    AllocatorColor	acScratch;
    AllocatorColor *	acRes;

    bmColorRgbDirect( &acScratch, ca, r, g, b );

    acRes= &(ca->caColors[acScratch.acColorNumber]);

    if  ( acRes->acAllocated == AC_UNALLOCATED )
	{
	AppColors *	acSys= (AppColors *)ca->caSystemPrivate;

	if  ( appColorAllocSystemColor( acRes, &acScratch, acSys ) )
	    {
	    if  ( bmFindNearestColorRgb( ac, ca, r, g, b ) )
		{ LDEB(1); return -1;	}

	    return 0;
	    }
	}

    *ac= *acRes;
    ac->acAllocated= AC_COPIED;

    return 0;
    }

static int appColorRgb332(	AllocatorColor *	ac,
				ColorAllocator *	ca,
				unsigned int		r,
				unsigned int		g,
				unsigned int		b )
    {
    AllocatorColor	acScratch;
    AllocatorColor *	acRes;

    bmColorRgbDirect( &acScratch, ca, r, g, b );

    acRes= &(ca->caColors[acScratch.acColorNumber]);

    if  ( acRes->acAllocated == AC_UNALLOCATED )
	{
	AppColors *	acSys= (AppColors *)ca->caSystemPrivate;

	if  ( appColorAllocSystemColor( acRes, &acScratch, acSys ) )
	    {
	    if  ( bmFindNearestColorRgb( ac, ca, r, g, b ) )
		{ LDEB(1); return -1;	}

	    return 0;
	    }
	}

    *ac= *acRes;
    ac->acAllocated= AC_COPIED;

    return 0;
    }

int appColorRgb(	APP_COLOR_RGB *		xc,
			AppColors *		acSys,
			unsigned int		r,
			unsigned int		g,
			unsigned int		b )
    {
    AllocatorColor	ac;
    ColorAllocator *	ca= &(acSys->acAllocator);

    if  ( acSys->acVisualClass == GDK_VISUAL_TRUE_COLOR		||
	  acSys->acVisualClass == GDK_VISUAL_DIRECT_COLOR	)
	{
	bmColorRgbDirect( &ac, ca, r, g, b );
	}
    else{
	if  ( ! ca->caSystemAllocator )
	    { XDEB(ca->caSystemAllocator); return -1;	}

	if  ( (*ca->caSystemAllocator)( &ac, ca, r, g, b ) )
	    { LLLDEB(r,g,b); return -1;	}
	}

    xc->red= ac.acRed;
    xc->green= ac.acGreen;
    xc->blue= ac.acBlue;
    xc->pixel= ac.acColorNumber;

    return 0;
    }

int appColorNamed(	APP_COLOR_RGB *		xc,
			AppColors *		acSys,
			const char *		name )
    {
    APP_COLOR_RGB	exact;

    if  ( ! gdk_color_parse( name, &exact ) )
	{ SDEB(name); return -1;	}

    return appColorRgb( xc, acSys,
			exact.red/257, exact.green/257, exact.blue/257 );
    }

static int appAllocateColors(	AppColors *		acSys )
    {
    GdkVisual *		vis= gdk_visual_get_system();
    GdkColormap *	cmap= gdk_colormap_get_system();

    int			count;

    ColorAllocator *	ca= &(acSys->acAllocator);

    acSys->acColormap= cmap;
    acSys->acVisualClass= vis->type;

    ca->caSystemPrivate= acSys;
    ca->caDepth= vis->depth;

    switch( acSys->acVisualClass )
	{
	case GDK_VISUAL_STATIC_GRAY:
	case GDK_VISUAL_GRAYSCALE:
	    ca->caAllocationType= CA_INDEX_ALLOC;
	    switch( ca->caDepth )
		{
		case 1: case 2: case 4: case 8:
		    break;
		default:
		    LLDEB(acSys->acVisualClass,ca->caDepth);
		}
	    break;

	case GDK_VISUAL_STATIC_COLOR:
	    ca->caAllocationType= CA_INDEX_ALLOC;
	    break;

	case GDK_VISUAL_PSEUDO_COLOR:
	    ca->caAllocationType= CA_INDEX_ALLOC;
	    break;

	case GDK_VISUAL_TRUE_COLOR:
	case GDK_VISUAL_DIRECT_COLOR:
	    ca->caAllocationType= CA_CALCULATED;

	    bmSetCalculatedShifts( ca, vis->red_mask,
					    vis->green_mask, vis->blue_mask );

	    return 0;
	}

    switch( ca->caDepth )
	{
	case 1:
	    count= 2;
	    ca->caSystemAllocator= appColorRgb111;
	    bmSetCalculatedShifts( ca, 0x0004, 0x0002, 0x0001 );
	    break;

	case 2:
	    count= 4;
	    ca->caSystemAllocator= appColorRgb111;
	    bmSetCalculatedShifts( ca, 0x0004, 0x0002, 0x0001 );
	    break;

	case 4:
	    count= 16;
	    ca->caSystemAllocator= appColorRgb222;
	    bmSetCalculatedShifts( ca, 0x0030, 0x000c, 0x0003 );
	    break;

	case 8:
	    count= 256;
	    ca->caSystemAllocator= appColorRgb332;
	    bmSetCalculatedShifts( ca, 0x00e0, 0x001c, 0x0003 );
	    break;

	case 16:
	    count= 256* 256;
	    ca->caSystemAllocator= appColorRgb555;
	    bmSetCalculatedShifts( ca, 0x7c00, 0x03e0, 0x001f );
	    break;

	case 24:
	case 32:
	    return 0;

	default:
	    LDEB(vis->depth); return -1;
	}

    if  ( bmAllocateAllocatorColors( ca, count ) )
	{ LDEB(count); return -1;	}

    return 0;
    }

# if 0
void appCleanColors(	AppColors *		acSys )
    {
    int			i;

    GdkColormap *	cmap= acSys->acColormap;
    ColorAllocator *	ca= &(acSys->acAllocator);

    for ( i= 0; i < 64; i++ )
	{
	if  ( ca->ca222Colors[i].acAllocated == AC_ALLOCATED )
	    {
	    gulong	pix= ca->ca222Colors[i].acColorNumber;

	    gdk_colors_free( cmap, &pix, 1, 0L );
	    ca->ca222Colors[i].acAllocated= AC_UNALLOCATED;
	    }
	}

    for ( i= 0; i < ca->caColorCount; i++ )
	{
	if  ( ca->caColors[i].acAllocated == AC_ALLOCATED )
	    {
	    gulong	pix= ca->caColors[i].acColorNumber;

	    gdk_colors_free( cmap, &pix, 1, 0L );
	    ca->caColors[i].acAllocated= AC_UNALLOCATED;
	    }
	}

    bmCleanColorAllocator( ca );
    }
# endif

void appInitColors(	AppColors *	acSys )
    {
    ColorAllocator *	ca= &(acSys->acAllocator);

    bmInitColorAllocator( ca );

    acSys->acColormap= (GdkColormap *)0;
    }

int appColorFindRgb(	APP_COLOR_RGB *	xc,
			AppColors *	acSys,
			unsigned int	r,
			unsigned int	g,
			unsigned int	b )
    {
    ColorAllocator *	ca= &(acSys->acAllocator);
    AllocatorColor	acRet;

    if  ( bmFindNearestColorRgb( &acRet, ca, r, g, b ) )
	{ return -1;	}

    xc->red= acRet.acRed;
    xc->green= acRet.acGreen;
    xc->blue= acRet.acBlue;
    xc->pixel= acRet.acColorNumber;

    return 0;
    }

static AppColors * APP_TheColors= (AppColors *)0;

AppColors *	guiGetColorsGtk( void )
    {
    if  ( ! APP_TheColors )
	{
	APP_TheColors= malloc( sizeof(AppColors) );
	if  ( ! APP_TheColors )
	    { XDEB(APP_TheColors); return (AppColors *)0;	}

	appInitColors( APP_TheColors );
	appAllocateColors( APP_TheColors );
	}

    return APP_TheColors;
    }

#   endif
