/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <X11/IntrinsicP.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/CoreP.h>
#include <X11/cursorfont.h>
#include "Colors.h"
#include "ColorsP.h"


#ifndef ABS
#define ABS(a)           ((a)>=0?(a):-(a))
#endif
#ifndef MIN
#define MIN(a,b)         ((a)>(b)?(b):(a))
#endif

static void    create_gcs();
static void    calc_new_size();

/*
  Widget class methods
*/

static void    Initialize();
static void    Redisplay();
static void    Resize();
static void    Destroy();
static void    Activate();
static Boolean SetValues();

static char defaultTranslations[] = "\
<BtnDown>:activate()\n\
~s ~m ~a <Key>Return:PrimitiveParentActivate()\n\
<Key>osfActivate:PrimitiveParentActivate()\n\
<Key>osfCancel:PrimitiveParentCancel()\n\
<Key>osfSelect:activate()\n\
<Key>osfHelp:Help()\n\
~s ~m ~a <Key>space:activate()\n\
<Key>osfHelp:Help()";


static XtActionsRec actionsList[] = {
	{ "activate", (XtActionProc)Activate, },
};


static XtResource resources[] = {
	{XmNactivateCallback,XtCCallback,XtRCallback,sizeof(caddr_t),
	XtOffset (ColorsWidget, colors.activate),XtRCallback,(XtPointer)NULL},
	{ XmNfontList, XmCFontList, XmRFontList, sizeof (XmFontList),
	XtOffset (ColorsWidget, colors.fontlist), XmRString, "fixed"},
	{ XmNlabelString, XmCString, XmRString, sizeof (String),
	XtOffset (ColorsWidget, colors.no_colours), XmRString, "None"},
};

/*---------------------------------------------------------------*/
/* Static initialisation of the class record                     */
/*---------------------------------------------------------------*/

ColorsClassRec  colorsClassRec = {
	{
	(WidgetClass) &xmPrimitiveClassRec,  /* superclass            */
	"Colors",                            /* class_name            */
	sizeof(ColorsRec),                   /* widget_size           */
	NULL,                                /* class_initialize      */
	NULL,                                /* class_part_initialize */
	FALSE,                               /* class_inited          */
	Initialize,                          /* initialize            */
	NULL,                                /* initialize_hook       */
	XtInheritRealize,                    /* realize               */
	actionsList,                         /* actions               */
	XtNumber(actionsList),               /* num_actions           */
	resources,                           /* resources             */
	XtNumber(resources),                 /* num_resources         */
	NULLQUARK,                           /* xrm_class             */
	TRUE,                                /* compress_motion       */
	TRUE,                                /* compress_exposure     */
	TRUE,                                /* compress_enterleave   */
	TRUE,                                /* visible_interest      */
	Destroy,                             /* destroy               */
	Resize,                              /* resize                */
	Redisplay,                           /* expose                */
	SetValues,                           /* set_values            */
	NULL,                                /* set_values_hook       */
	XtInheritSetValuesAlmost,            /* set_values_almost     */
	NULL,                                /* get_values_hook       */
	NULL,                                /* accept_focus          */
	XtVersion,                           /* version               */
	NULL,                                /* callback private      */
	defaultTranslations,                 /* tm_table              */
	NULL,                                /* query_geometry        */
	NULL,                                /* display_accelerator   */
	NULL,                                /* extension             */
	},
	{
	(XtWidgetProc)_XtInherit,             /* border_highlight      */
	(XtWidgetProc)_XtInherit,             /* border_unhighligh     */
	XtInheritTranslations,                /* translations          */
	(XtActionProc)_XtInherit,             /* arm_and_activate      */
	NULL,                                 /* syn_resources         */
	0,                                    /* num_syn_resources     */
	NULL,                                 /* extension             */
	},
	{
	0,                                    /* ignore                */
	},
};

WidgetClass colorsWidgetClass = (WidgetClass) &colorsClassRec;

/*---------------------------------------------------------------*/
/* Create the two GCs needed                                     */
/*---------------------------------------------------------------*/

static void create_gcs(ColorsWidget w)
{
	int     i;
	XGCValues values;
	XtGCMask  valueMask;

	valueMask         =  GCFunction | GCForeground;
	values.function   = GXcopy;

	for(i=0;i<w->colors.count;i++)
	{
		values.foreground = w->colors.pixels[i];
		w->colors.gc[i] = XtGetGC((Widget)w,valueMask,&values);
	}

}

static void free_gcs(ColorsWidget w)
{
	int i;
	for(i=0;i<w->colors.count;i++)
		XtReleaseGC((Widget)w,w->colors.gc[i]);
}

/*--------------------------------------------------------------*/
/* Initialize: Create the GCs                                   */
/*--------------------------------------------------------------*/

static void Initialize (ColorsWidget request, ColorsWidget new)
{
    Display *dpy   = XtDisplay(new);
	int     screen = DefaultScreen(dpy);
	Window  root   = RootWindow(dpy,screen);
	XFontStruct     *fs = (XFontStruct *) NULL;
	XGCValues values;
	XtGCMask  valueMask = 0;

	/* Check the size of the widget */

	if (request->core.width == 0)
		new->core.width = 5;

	if (request->core.height == 0)
		new->core.height = 5;

	_XmFontListGetDefaultFont(new->colors.fontlist,&fs);
	if(fs != NULL)
	{
		valueMask    |= GCFont;
		values.font  = fs->fid;
	}

	new->colors.max   = 10;
	new->colors.count = 0;
	new->colors.pixels = NULL;
	new->colors.gc     = NULL;
	new->colors.fontGC = XCreateGC(dpy,root,valueMask,&values);
	create_gcs(new);

}


/*--------------------------------------------------------------*/
/* Destroy the widget: release all memory alocated              */
/*--------------------------------------------------------------*/

static void Destroy (ColorsWidget w)
{
	free_gcs(w);
	XtFree((XtPointer)w->colors.pixels);
	XtFree((XtPointer)w->colors.gc);
	XFreeGC(XtDisplay(w),w->colors.fontGC);
}


static void Resize (ColorsWidget w)
{
}

static void draw(ColorsWidget w)
{
	int i;
	int frame  = w->primitive.highlight_thickness 
		+ w->primitive.shadow_thickness;
	int height = w->core.height - 2*frame;
	int width  = w->core.width  - 2*frame ;
	int x      = frame;
	int y      = frame;


	if(w->colors.count)
	{
		width /= w->colors.count;

		for(i=0;i<w->colors.count;i++)
		{
			XFillRectangle(XtDisplay (w), XtWindow(w),
			    w->colors.gc[i],x,y,width,height);
		x += width;
		}
	}
	else {
		XmString s = XmStringCreateSimple(w->colors.no_colours);
		XRectangle r;

		r.x      = x;
		r.y      = y;
		r.width  = width;
		r.height = height;

		XClearArea(XtDisplay(w),XtWindow(w), x,y,width,height,False);
		y += (height - XmStringHeight(w->colors.fontlist,s))/2;

		XmStringDraw (XtDisplay(w), XtWindow(w),
			w->colors.fontlist, s,
			w->colors.fontGC,
			x,y,width,
			XmALIGNMENT_CENTER,XmSTRING_DIRECTION_L_TO_R,&r);
		XmStringFree(s);
	}
}

static void Redisplay(ColorsWidget w, XEvent *event, Region region)
{
	draw(w);

	_XmDrawShadows(XtDisplay(w), XtWindow(w),
	    w->primitive.bottom_shadow_GC,
	    w->primitive.top_shadow_GC,
	    (int) w->primitive.highlight_thickness,
	    (int) w->primitive.highlight_thickness,
	    (int) (w->core.width - 
		(2*w->primitive.highlight_thickness)),
	    (int) (w->core.height - 
		(2*w->primitive.highlight_thickness)),
	    (int) w->primitive.shadow_thickness,
	    XmSHADOW_OUT);
}

/*------------------------------------------------------------------*/
/* SetValues : redraw only for font or color changes                */
/*------------------------------------------------------------------*/

static Boolean SetValues (ColorsWidget current, ColorsWidget request, 
ColorsWidget new)
{
	Boolean    redraw = FALSE;
	redraw = True;
	return (redraw);
}


static void Activate(Widget widget,XEvent *event,char **args,int nargs)
{
	XmAnyCallbackStruct cb;
	cb.reason = XmCR_ACTIVATE;
	cb.event  = event;
	XtCallCallbacks (widget,XmNactivateCallback,(XtPointer)&cb);
}

/*-----------------------------------------------------------------------*/
/* Create a new ColorsWidget                                              */
/*-----------------------------------------------------------------------*/

Widget CreateColorsWidget(Widget parent,char *name,Arg *al,int ac)
{
	return XtCreateWidget(name,colorsWidgetClass,parent,al,ac);
}

void ColorsSetPixels(Widget w,int c,Pixel *pix)
{
	ColorsWidget cw = (ColorsWidget)w;
	int i;

	if(c == cw->colors.count)
	{
		for(i=0;i<c;i++)
			if(cw->colors.pixels[i] != pix[i])
				break;
	
		if(i == c) return;
	}

	free_gcs(cw);
	XtFree((XtPointer)cw->colors.pixels);
	XtFree((XtPointer)cw->colors.gc);
	cw->colors.pixels = (Pixel*)XtCalloc(c,sizeof(Pixel));
	cw->colors.gc     = (GC*)XtCalloc(c,sizeof(GC));
	cw->colors.count = c;
	for(i=0;i<c;i++)
		cw->colors.pixels[i] = pix[i];

	create_gcs(cw);
	if(XtIsRealized(w) && XtIsManaged(w))
		draw(w);
}
