/*
        FILE:           x_interface.c
        PURPOSE:        Creation and access to an X windows interface
			to wet+sticky using Athena Widgets
        AUTHOR:         David England
        VERSION:        1.00  (13-May-91)

Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. 

Contact David England d.england@livjm.ac.uk
School of Computing and Maths Sciences,
Liverpool John Moores University 
Liverpool L3 3AF
United Kingdom
Phone +44 151 231 2271

Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 

*/

#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Intrinsic.h>

#include <X11/cursorfont.h>
#include <X11/StringDefs.h>

#include <X11/Shell.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Label.h>
#include <stdio.h>

#include "constants.h"
#include "types.h"
#include "engine.h"
#include "canvas.h"

/* Window Heirarchy - 
	Three shell widgets, one for colour output, two for attributes output
	plus a back_up pixmap for redrawing
*/

static Widget top_level;
static Widget 	    colour_shell;
static Widget            colour_box;
static Widget		        colour_canvas;
static Pixmap		        colour_pm;

static Widget      volume_shell;
static Widget            volume_box;
static Widget                  volume_canvas;
static Pixmap		        volume_pm;

static Widget      dryness_shell;
static Widget            dryness_box;
static Widget                  dryness_canvas;
static Pixmap		        dryness_pm;

static GC gc;
static GC tmp_gc;
static long mask;
static XGCValues values;

static Colormap cmap;
static XColor colours[256];
void stroke();
void stroke_motion();

Display *display;
int screen;
Screen          *screen_ptr;
Window root;

static int count=0;
static int frame_count=0;
char pix_file[64];

void StartWindow();
void StartUpWindows();

static XtEventHandler
expose_event(w, event)
Widget          w;
XEvent          *event;
{
/* Re-display the colour window if an exposure event is received */
int width, height;

	width = height = 300;

        XCopyArea(XtDisplay(colour_canvas), colour_pm, 
		XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0);

}


static void
expose_volume(w, event)
Widget          w;
XEvent          *event;
{
/* Re-display the volume window if an exposure event is received */
int width, height;

	width = height = 300;

      XCopyArea(XtDisplay(volume_canvas), volume_pm,
	      XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0);
      

}

static void
expose_dryness(w, event)
Widget          w;
XEvent          *event;
{
/* Re-display the dryness window if an exposure event is received */
int width, height;

        width = height = 300;

      XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
              XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0);


}

int 
GetHueValue(red, green, blue)
int red;
int green;
int blue;
{
	XColor colour;

	colour.red = red * 257;
	colour.green = green * 257;
	colour.blue = blue * 257;
	colour.flags = DoRed | DoGreen | DoBlue;

	if (XAllocColor(display, cmap, &colour) == 0)
		fprintf(stderr,"colour allocation failed\n");

	return (colour.pixel);	
}


void
DrawPoint(x,y,colour)
int x;
int y;
int colour;
/* Draw a point on the window and the back-up Pixmap */
{
	XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel);

	XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y);
	XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y);
}

int
DrawVolumePoint(x,y,attr)
int x;
int y;
int attr;
/* Draw a point on the window and the back-up Pixmap */
{
	/* later - use the range of the volume to affect the colour
		value
	*/

	if (XtWindow(volume_canvas) == NULL)
		return (-1);

	XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);

	XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y);
	XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y);

	return(0);
}

int
DrawDrynessPoint(x,y,attr)
int x;
int y;
int attr;
/* Draw a point on the window and the back-up Pixmap */
{
        /* later - use the range of the dryness to affect the colour
                value
        */

        if (XtWindow(dryness_canvas) == NULL)
                return (-1);

        XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);

        XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y);
        XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y);

        return(0);
}

void
ClearWindow()
{
	XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas));
}

static void
CleanWindow(win)
Drawable win;
/* Fill a window with a solid, white rectangle */
{
XGCValues values;
long mask;

	values.background = colours[0].pixel;
        values.foreground = colours[255].pixel;;
        values.fill_style = FillSolid;
        values.function   = GXclear;


         mask = GCBackground| GCForeground| GCFillStyle | GCFunction;

         tmp_gc = XtGetGC(top_level,  mask, &values);

        XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0,  0, 300, 300);

}

void SetupCmap()
{
int i;

        for (i=0;i<256;i++) {
                colours[i].red = i*257;
                colours[i].flags = DoRed | DoBlue | DoGreen;
	}

     /*   for (i=0;i<=127;i++)
                colours[i].green = i*2*257;

        for (i=128;i>0;i--)
                colours[255-i].green = (i-1)*2*257;*/

       for (i=0;i<64;i++)
                colours[i].green = i*4*257;

        for (i=64;i<128;i++)
                colours[i].green = 65536-i*4*257;
 
         for (i=128;i<192;i++)
                colours[i].green = (i-128)*2*257;
 
         for (i=192;i<255;i++)
                colours[i].green = 65536-(i-128)*2*257;


        for (i=0;i<256;i++)
                colours[i].blue = 65536 - i*257;

	colours[0].red = 65535;
	colours[0].green = 65535;
	colours[0].blue = 65535;
}

void
SetupGreyMap()
{
int i;

	 for (i=0;i<256;i++) {
                colours[i].red = i*257;
                colours[255 - i].flags = DoRed | DoBlue | DoGreen;
	}


         for (i=0;i<256;i++)
                colours[i].green =  i*257;

         for (i=0;i<256;i++)
                colours[i].blue =  i*257;

	colours[255].red = 255*257;
	colours[255].green = 255*257;
	colours[255].blue = 255*257;

}


main(argc, argv)
int argc;
char **argv;
/* Create colour window heirarchy and add event handlers */
{
	
    static Arg args[]={
        {XtNwidth, (XtArgVal) 0},
        {XtNheight, (XtArgVal)0} };	

int width;
int height;
	int i;

	
	width = 300;
	height = 300;

	args[0].value = (XtArgVal)width;

	args[1].value = (XtArgVal)height;

	top_level =  XtInitialize("wet+sticky", "Wet+Sticky", NULL,
                                                 0, &argc, argv);


	display = XtDisplay(top_level);
        screen = DefaultScreen(display);
	screen_ptr = ScreenOfDisplay(display, DefaultScreen(display));

	root = RootWindow(display, screen);

	colour_shell = XtCreateApplicationShell("colour_frame", 
			topLevelShellWidgetClass, NULL, 0);



        colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass,
                                                colour_shell, NULL, 0);


        colour_canvas = XtCreateManagedWidget("", labelWidgetClass,
                                        colour_box, args, XtNumber(args));


	XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0);

	XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0);

	XtAddEventHandler(colour_canvas, Button1MotionMask, 
		False, stroke_motion, 0);

	XtRealizeWidget(colour_shell);

	cmap = XCreateColormap( display, XtWindow(colour_shell),
                        XDefaultVisualOfScreen(screen_ptr), AllocAll);

        for (i=0; i <= 255; i++)
                colours[i].pixel = i;

        XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256);

        /*SetupCmap();*/

	SetupGreyMap();

        XStoreColors(display, cmap, colours, 256);

        i=0;
        while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr),
                 True, NULL, 0, &colours[i].pixel, 1 ) ) {
                        colours[i].pixel = i;
                        i++;
          }

	XSetWindowColormap(display, XtWindow(colour_shell), cmap);

        XInstallColormap(display, cmap);

	mask = GCBackground| GCForeground|  GCFunction; 

	values.function = GXcopy;
	values.background = colours[0].pixel;
	values.foreground = colours[255].pixel;


	gc = XtGetGC(colour_canvas, mask, &values);

	colour_pm = XCreatePixmap(XtDisplay(top_level), 
			XtWindow(colour_shell), width, height,
                            XDefaultDepth(XtDisplay(top_level), 0));

	CleanWindow(colour_pm);

	StartWindow (CANVAS_WIDTH, CANVAS_HEIGHT);

	StartUpWindows();
}


void StartWindow(width, height)
int width;
int height;
/* Create Volume heirarchy and add event handlers */
{
	static Arg args[]={
	{XtNwidth, (XtArgVal) 0},
	{XtNheight, (XtArgVal)0} };

	args[0].value = (XtArgVal)width;

	args[1].value = (XtArgVal)height;

	volume_shell = XtCreateApplicationShell("volume_frame",
			topLevelShellWidgetClass, NULL, 0);

	volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass,
				volume_shell, NULL, 0);
											
	volume_canvas = XtCreateManagedWidget("", labelWidgetClass,
				volume_box, args, XtNumber(args));

	XtAddEventHandler(volume_canvas, ExposureMask, False, 
				expose_volume, 0);

	XtRealizeWidget(volume_shell);

	XSetWindowColormap(display, XtWindow(volume_shell), cmap);

	volume_pm = XCreatePixmap(XtDisplay(top_level), 
			XtWindow(colour_shell), width, height,
                            XDefaultDepth(XtDisplay(top_level), 0));

	CleanWindow(volume_pm);


}

void StartDrynessWindow(width, height)
int width;
int height;
/* Create dryness heirarchy and add event handlers */
{
	static Arg args[]={
	{XtNwidth, (XtArgVal) 0},
	{XtNheight, (XtArgVal)0} };

	args[0].value = (XtArgVal)width;

	args[1].value = (XtArgVal)height;

	dryness_shell = XtCreateApplicationShell("dryness_frame",
			topLevelShellWidgetClass, NULL, 0);

	dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass,
				dryness_shell, NULL, 0);
											dryness_canvas 
= XtCreateManagedWidget("", labelWidgetClass,
				dryness_box, args, XtNumber(args));

	XtAddEventHandler(dryness_canvas, ExposureMask, False, 
				expose_dryness, 0);

	XtRealizeWidget(dryness_shell);

	XSetWindowColormap(display, XtWindow(dryness_shell), cmap);

	dryness_pm = XCreatePixmap(XtDisplay(top_level), 
			XtWindow(colour_shell), width, height,
                            XDefaultDepth(XtDisplay(top_level), 0));

	CleanWindow(dryness_pm);

}

static void
draw_labels()
{
	XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel);

	XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10, 
			"Colour", strlen("Colour"));
	XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10, 
			"Colour", strlen("Colour")); 

	XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel);

	XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10, 
			"Volume", strlen("Volume")); 
	XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10, 
			"Volume", strlen("Volume"));

        XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel);

	XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10, 
			"Bump Map", strlen("Bump Map"));
	XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10, 
			"Bump Map", strlen("Bump Map"));
}

void paint_cell(cell, x, y)
CELL_PTR cell;
int x, y;

{
    int colour, volColour, dryness;
    POINT p;

    p.x = x;
    p.y = y;

    /*  The current display simply maps hue onto the indices of the colour
        table.  This involves some scaling since hues are in the range [0,360)
        with the colour table being [0,256).  */

    colour = (int) (cell->contents.colour.hue * 
			((float) MAX_COLOUR_INDEX / 360.0));

    /*DrawPoint(x,y,colour);   */

    /*  volColour is an index into the colour table in the range [0,255].
        It is used to give a false colour image of the canvas's volume.  */

    /*if (x < SCALE_WIDTH) return;    Don't draw over colour scale.  */

    volColour = MIN(cell->volume * 2, 255);
    volColour = MAX(volColour, 0);        
				/* Make unfilled cells have a zero vol.  */

    /*DrawVolumePoint(x,y,volColour);*/

    /*  Dryness will be in the range [0,255].  */
    dryness = (cell->contents.liquid_content * 255) / 100;

    /*DrawDrynessPoint(x,y,dryness);*/
}



void draw_false_colour_scale()
/*  This routine places a scale along the top of the volume window
    showing the colours being used.   Low is at the left edge. 
    The colour palette has indices 0..255.    */
{
    int x, y;

    /*for (x=0; x < 255; x++) 
       for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/
}


void draw_full_canvas()
{
   int x, y;
   CELL_PTR cell;
   POINT p;
 
  if (DEBUG) {
     printf ("Starting to paint full canvas...");
     fflush(stdout);
   }

   for (x=0; x < CANVAS_WIDTH; x++) {
     for (y=0; y < CANVAS_HEIGHT; y++) {
        p.x = x;
        p.y = y;
        /*cell = get_cell(p);*/
        paint_cell(cell, x, y);
     }
  }
  draw_false_colour_scale();
  if (DEBUG) printf ("done.\n");
}

void
bump_map()
{
	POINT p;
	CELL_PTR cell;
	int x, y;
	int colour;


   for (x=0; x < CANVAS_WIDTH; x++) {
     for (y=0; y < CANVAS_HEIGHT; y++) {
        p.x = x;
        p.y = y;
        /*cell = get_cell(p);*/
	/*colour = (int) new_intensity_value(p);*/

/*	colour = (int) (cell->contents.colour.hue *
                        ((float) MAX_COLOUR_INDEX / 360.0));*/
	DrawDrynessPoint(x,y,colour);
     }
  }

}


void evolve_paint()
{
      
}



void StartUpWindows()
{
/* Start the X windows event loop and paint processing */
XEvent event;



	for (;;) {
	   if (XtPending()) {
		XtNextEvent(&event);
		XtDispatchEvent(&event);
	   }
	   else {
		/* Evolve paint and re-display*/
		evolve_paint();
	        }
		
	   } /* End for loop */


}

void
stroke(w, client_data, event)
Widget w;
caddr_t client_data;
XEvent *event;
{
/*	brush_stroke(event->xbutton.x, event->xbutton.y);*/


	/*if ((XEvent *)event != (XEvent *)NULL)
	else
		printf("Null event\n"); */

/*	DrawPoint(event->xbutton.x, event->xbutton.y, 128);
        DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128);
        DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/

	
        XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);

        XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
			 event->xmotion.x, event->xmotion.y ,1, 1);

        XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
			 event->xmotion.x, event->xmotion.y ,1, 1);

        /*XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
			 event->xmotion.x, event->xmotion.y ,1, 1);*/

	/*brush_stroke(event->xbutton.x, event->xbutton.y);*/
}


void
stroke_motion(w, client_data, event)
Widget w;
caddr_t client_data;
XEvent *event;
{


        /*if ((XEvent *)event != (XEvent *)NULL)
        else
                printf("Null event\n"); */


        XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);

        XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
			 event->xmotion.x, event->xmotion.y ,1, 1);
        XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
			 event->xmotion.x, event->xmotion.y ,1, 1);

        XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
			 event->xmotion.x, event->xmotion.y ,1, 1);

      /*brush_stroke(event->xbutton.x, event->xbutton.y);*/
}

