/***************************** 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 <math.h>
#include <malloc.h>
#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/CoreP.h>
#include <X11/CompositeP.h>
#include <X11/ConstrainP.h>
#include <Xm/XmP.h>
#include <Xm/DrawingAP.h>
#include "Layout.h"
#include "LayoutP.h"

#ifndef MAX
#define   MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define   MIN(a,b) ((a) < (b) ? (a) : (b))
#endif

static void             Initialize();
static void             ConstraintInitialize();
static Boolean          ConstraintSetValues();
static void             Destroy();
static void             Resize();
static Boolean          SetValues();
static XtGeometryResult GeometryManager();
static void             ChangeManaged();
static void             new_layout();
static void             Redisplay();


static CompositeClassExtensionRec compext = {
	NULL,                               /* next_extension */
	NULLQUARK,                          /* record type */
	XtCompositeExtensionVersion,        /* version */
	sizeof(CompositeClassExtensionRec), /* record size */
	TRUE                                /* accepts_objects */
};


LayoutClassRec layoutClassRec = {
	{
	/* core_class fields  */
	(WidgetClass) &xmManagerClassRec,/* superclass         */
	"Layout",                           /* class_name         */
	sizeof(LayoutRec),                /* widget_size        */
	NULL,                             /* class_init         */
	NULL,                             /* class_part_init    */
	FALSE,                            /* class_inited       */
	Initialize,                       /* initialize         */
	NULL,                             /* initialize_hook    */
	XtInheritRealize,                 /* realize            */
	NULL,                            /* actions            */
	0,                                /* num_actions        */
	NULL,                             /* resources          */
	0,                                /* num_resources      */
	NULLQUARK,                        /* xrm_class          */
	TRUE,                             /* compress_motion    */
	XtExposeCompressMaximal,          /* 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   */
	XtInheritTranslations,            /* tm_table           */
	NULL,                             /* query_geometry     */
	XtInheritDisplayAccelerator,      /* display_accelerator*/
	NULL,                             /* extension          */
	},
	{
	/* composite_class fields */
	GeometryManager,                 /* geometry_manager    */
	ChangeManaged,                   /* change_managed      */
	XtInheritInsertChild,                     /* insert_child        */
	XtInheritDeleteChild,                      /* delete_child        */
	NULL/*&compext*/,                        /* extension           */
	},
	{ 
	/* constraint_class fields */
	NULL,          /* subresources        */
	0,/* subresource_count   */
	sizeof(LayoutConstraintsRec),       /* constraint_size     */
	ConstraintInitialize,             /* initialize          */
	NULL,                /* destroy             */
	ConstraintSetValues,              /* set_values          */
	NULL,                             /* extension           */
	},
	{
	XtInheritTranslations,   /* default translations */
	NULL,                    /* syn_resources          */
	0,               /* num_syn_resources      */
	NULL,                        /* syn_cont_resources     */
	0,                           /* num_syn_cont_resources */
	XmInheritParentProcess,  /* parent_process */
	NULL,                        /* extension              */

	},
	{
	/* Layout class fields */
	0,                               /* ignore              */
	}
};



WidgetClass layoutWidgetClass = (WidgetClass) &layoutClassRec;


/*========================================================================*/


static void Initialize(LayoutWidget request, LayoutWidget new)
{
	if (request->core.width <= 0)
		new->core.width = 5;
	if (request->core.height <= 0)
		new->core.height = 5;
}

static void Destroy(LayoutWidget widget)
{
}

void validate(Widget w)
{
	LayoutConstraints layout_c = LAYOUT_CONSTRAINT(w);

	if(layout_c->layout.left < 0)   layout_c->layout.left = 0;
	if(layout_c->layout.top  < 0)   layout_c->layout.top = 0;
	if(layout_c->layout.bottom > 1) layout_c->layout.bottom = 1;
	if(layout_c->layout.right  > 1) layout_c->layout.right = 1;

	if(layout_c->layout.left > layout_c->layout.right)
	{
		double a = layout_c->layout.right;
		layout_c->layout.right = layout_c->layout.left;
		layout_c->layout.left = a;
	}

	if(layout_c->layout.top > layout_c->layout.bottom)
	{
		double a = layout_c->layout.bottom;
		layout_c->layout.bottom = layout_c->layout.top;
		layout_c->layout.top = a;
	}
}

static void ConstraintInitialize(Widget request, Widget new)
{
	LayoutConstraints layout_c = LAYOUT_CONSTRAINT(new);

	layout_c->layout.left = 0;
	layout_c->layout.top = 0;
	layout_c->layout.bottom = 1;
	layout_c->layout.right = 1;

}

static Boolean SetValues(LayoutWidget current, LayoutWidget request, LayoutWidget new)
{
	return True;
}

static Boolean ConstraintSetValues(Widget current, Widget request, Widget new)
{
	LayoutWidget tw = (LayoutWidget)XtParent(current);

	ConstraintInitialize(request,new);

	if(XtIsRealized(tw))
		new_layout(tw);

	return (False);
}

static void ConstraintDestroy(Widget w)
{
}

static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry* request, XtWidgetGeometry* reply)
{
	/* printf("LayoutWidget::GeometryManager %s\n",XtName(w)); */
	/* No geometry requests allowed */
	return XtGeometryNo;
}

static void ChangeManaged(LayoutWidget tw)
{
	/* printf("LayoutWidget::ChangeManaged %s\n",XtName(tw)); */
	new_layout(tw);
}

static void Redisplay (LayoutWidget w, XEvent* event, Region region)
{
	_XmRedisplayGadgets((Widget)w,event,region);
}


#define RND(a) ((int)((a)+0.5))

#define X(a) RND(W*(a))
#define Y(a) RND(H*(a))

static void place(LayoutWidget tw,Widget w)
{
	Dimension H = tw->core.height;
	Dimension W  = tw->core.width;
	LayoutConstraints layout_c = LAYOUT_CONSTRAINT(w);


	double width  = layout_c->layout.right  - layout_c->layout.left; 
	double height = layout_c->layout.bottom - layout_c->layout.top; 

	_XmConfigureObject(w,X(layout_c->layout.left),
						 Y(layout_c->layout.top),
						 X(width),
						 Y(height),
						 0);
}

static void new_layout(LayoutWidget tw)
{
	int i;
	for(i=0;i<tw->composite.num_children;i++)
		place(tw,tw->composite.children[i]);
}

static void Resize(LayoutWidget tw)
{
	/* printf("LayoutWidget::Resize %s\n",XtName(tw)); */
	new_layout(tw);
}

Widget CreateLayoutWidget(Widget par,const char* nam,Arg* al,int ac)
{
	return XtCreateWidget(nam,layoutWidgetClass,par,al, ac);
}

void LayoutSetPosition(Widget w,double top,double left,double bottom,double right)
{
	LayoutConstraints layout_c = LAYOUT_CONSTRAINT(w);

	layout_c->layout.left = left;
	layout_c->layout.top = top;
	layout_c->layout.bottom = bottom;
	layout_c->layout.right = right;

	validate(w);
	place((LayoutWidget)XtParent(w),w);
}
