/*
  wind.c - A simple strategy for handling windows.
*/
  
#include <stdio.h>
#include <stdlib.h>

#include <X11/Xlib.h>

#include "err.h"
#include "hb.h"

#include "wind.h"
#include "area.h"

#define BORDER_WIDTH 1
#define INIT_NUM_AREAS 5

/* ---------- Function declarations ---------- */
static struct area *wind_findarea(struct wind *, int, int);

/* ------------------------------------------------------------------------ */
struct wind *
wind_create(struct wind *parent,
	    struct wind_params *wop)
{
    struct wind *ret;

    ret = calloc(sizeof(struct wind), 1);
    if (!ret) {
	do_error(ERR_NOMEM, "Can't create window.");
    }
    
    ret->window = XCreateSimpleWindow(dpy, 
				      RootWindow(dpy, DefaultScreen(dpy)),   
				      wop->x, wop->y,
				      wop->width, wop->height,
				      BORDER_WIDTH, 
				      /* Want this pixel value to be */
				      /* CopyFromParent or setable somehow. */
				      /* XXX */ 
				      WhitePixel(dpy, DefaultScreen(dpy)),
				      CopyFromParent);
    if (!ret->window) {
	do_error(ERR_NOWIND, "Can't get window.");
    }

    XSetWMName(dpy, ret->window, &gameTextProp);
    XMapWindow(dpy, ret->window);

    XSelectInput(dpy, ret->window,
		 ButtonPressMask |
		 ButtonReleaseMask |
		 KeyPressMask |
		 KeyReleaseMask |
		 StructureNotifyMask |
		 ExposureMask);

    ret->bounds.x = wop->x;
    ret->bounds.y = wop->y;
    ret->bounds.width = wop->width;
    ret->bounds.height = wop->height;
    ret->parent = wop->parent;
    ret->gc = wop->gc;
    ret->areas = calloc(sizeof(struct area *), INIT_NUM_AREAS);
    if (!ret->areas) {
	do_error(ERR_NOMEM, "Can't create areas.");
    }
    ret->num_areas = INIT_NUM_AREAS;

    switch (wop->win_type) {
      case FREE_WINDOW:
	do_error(ERR_NOOPENWINDOW, "Can't open free window");
	break;
	
      case HMINES_WINDOW:
	break;
    }

    return(ret);
}

/* ------------------------------------------------------------------------ */
void 
wind_destroy(struct wind *wind)
{
    XDestroyWindow(dpy, wind->window);
    free(wind);
}

/* ------------------------------------------------------------------------ */
void wind_mouse(struct wind *wind, XButtonEvent *bev)
{
    struct area *area;

    area = wind_findarea(wind, bev->x, bev->y);
    
    if (area) {
	if (area_mouse(area, bev)) {
	    return;
	}
    }
    wind->ops.mouse(wind, bev);
}

/* ------------------------------------------------------------------------ */
void wind_draw(struct wind *wind, XExposeEvent *eev)
{
    struct area *area = wind_findarea(wind, eev->x, eev->y); 

    /* Fix this to work with all areas, not just one. */
    /* Cause this is just wrong. */
    /* Needs to check region in the eev, as well as caching the regions to */
    /* build a larger region. */
    if (area) {
	if (area_draw(area, eev)) {
	    return;
	}
    }
    wind->ops.draw(wind, eev);
}

/* ------------------------------------------------------------------------ */
void wind_resize(struct wind *wind, XConfigureEvent *cev)
{
    struct area *area = wind_findarea(wind, cev->x, cev->y);
    if (area) {
	if (area_resize(area, cev)) {
	    return;
	}
    }
    wind->ops.resize(wind, cev);
}

/* ------------------------------------------------------------------------ */
void wind_key(struct wind *wind, XKeyEvent *kev)
{
    struct area *area = wind_findarea(wind, kev->x, kev->y);
    if (area) {
	if (area_key(area, kev)) {
	    return;
	}
    }
    wind->ops.key(wind, kev);
}

/* ------------------------------------------------------------------------ */
void wind_activate(struct wind *wind, XMapEvent *mev)
{
    int i;
    for (i = 0; i < wind->num_areas; i++) {
	if (wind->areas[i]) {
	    area_activate(wind->areas[i], mev);
	}
    }
}

/* ------------------------------------------------------------------------ */
void wind_deactivate(struct wind *wind, XUnmapEvent *uev)
{
    int i;
    for (i = 0; i < wind->num_areas; i++) {
	if (wind->areas[i]) {
	    area_activate(wind->areas[i], uev);
	}
    }
}

/* ------------------------------------------------------------------------ */
static struct area *wind_findarea(struct wind *wind, int x, int y)
{
    int i, dx, dy;
    struct area *area;

    for (i = 0; i < wind->num_areas; i++) {
	area = wind->areas[i];
	dx = x - area->bounds.x;
	if (dx >= 0 && dx < area->bounds.width) {
	    dy = y - area->bounds.y;
	    if (dy >= 0 && dy < area->bounds.height) {
		return(area);
	    }
	}
    }
    return(NULL);
}
