#include "globals.h"
#include "local_proto.h"
#include <grass/raster.h>

static int active = 0;
static int replot;
static int mouse(Objects *, int, int, int);
static int use_mouse_msg(void);
static int draw_objects(Objects *);
static Objects *find(Objects *, int, int);
static int select_option(Objects *, Objects *);
static int draw_option_boxes(Objects *);
static int visible(Objects *);

#define TEXT_COLOR BLACK
#define FILL_COLOR GREY
#define OUTLINE_COLOR WHITE

/* Input: drive mouse. returns status of handler that returns != 0 */
int Input_pointer(Objects * objects)
{
    return mouse(objects, 0, 0, 0);
}

int Input_box(Objects * objects, int ax, int ay)
{
    return mouse(objects, ax, ay, 1);
}

int Input_other(int (*function) (), char *type)
{
    int stat;
    char msg[1024];

    sprintf(msg, "%s input required", type);
    Menu_msg(msg);

    stat = (*function) ();
    if (active) {
	use_mouse_msg();
    }

    Menu_msg("");
    return stat;
}

static int mouse(Objects * objects, int ax, int ay, int box)
{
    int first;
    int stat;
    int x, y, button;
    Objects *obj;

    first = !active;
    active = 1;
    if (first)
	use_mouse_msg();

    if (box) {
	x = ax + 20;
	y = ay + 20;
    }
    stat = 0;
    replot = 1;
    while (stat == 0) {
	if (replot) {
	    replot = 0;
	    draw_objects(objects);
	}
	if (box)
	    Mouse_box_anchored(ax, ay, &x, &y, &button);
	else
	    Mouse_pointer(&x, &y, &button);

	if (!(obj = find(objects, x, y)))
	    continue;

	switch (obj->type) {
	case MENU_OBJECT:
	case OTHER_OBJECT:
	    stat = (*obj->handler) (x, y, button);
	    break;
	case OPTION_OBJECT:
	    select_option(objects, obj);
	    draw_option_boxes(objects);
	    break;
	}
    }

    /* if we are first call, mark not active
     * indicate that objects above use must be replotted.
     */
    if (first)
	active = 0;
    Menu_msg("");

    return stat;
}


static int use_mouse_msg(void)
{
    Curses_write_window(PROMPT_WINDOW, 1, 1, "Use mouse now ...\n");

    return 0;
}

static int draw_objects(Objects * objects)
{
    Objects *obj;
    int top, bottom, left, right;
    int size, edge;


    /* erase the menu window */
    Erase_view(VIEW_MENU);
    R_flush();

    /* determine sizes and text indentation */
    size = VIEW_MENU->nrows - 4;
    edge = 2;

    R_text_size(size, size);

    left = VIEW_MENU->left;
    top = VIEW_MENU->top;
    bottom = VIEW_MENU->bottom;


    /* put the (boxed) text on the menu view */
    for (obj = objects; obj->type; obj++) {
	if (!visible(obj))
	    continue;
	switch (obj->type) {
	case OPTION_OBJECT:
	case MENU_OBJECT:
	    right = left + 2 * edge + Text_width(obj->label);
	    obj->left = left;
	    obj->right = right;
	    obj->top = top;
	    obj->bottom = bottom;

	    R_standard_color(FILL_COLOR);
	    R_box_abs(left, top, right, bottom);

	    R_standard_color(TEXT_COLOR);
	    Text(obj->label, top, bottom, left, right, edge);

	    R_standard_color(OUTLINE_COLOR);
	    Outline_box(top, bottom, left, right);

	    left = right;
	    break;

	case INFO_OBJECT:
	    if (*obj->label == 0)
		break;
	    if (*obj->status < 0)
		break;
	    right = left + 2 * edge + Text_width(obj->label);
	    R_standard_color(WHITE);
	    Text(obj->label, top, bottom, left, right, edge);

	    left = right;
	    break;
	}
    }
    draw_option_boxes(objects);
    R_flush();

    return 0;
}

static Objects *find(Objects * objects, int x, int y)
{
    Objects *other;

    other = NULL;
    for (; objects->type; objects++) {
	if (!visible(objects))
	    continue;
	switch (objects->type) {
	case MENU_OBJECT:
	case OPTION_OBJECT:
	    if (x >= objects->left && x <= objects->right
		&& y >= objects->top && y <= objects->bottom)
		return objects;
	    break;
	case OTHER_OBJECT:
	    other = objects;
	    break;
	}
    }
    return other;
}

static int select_option(Objects * objects, Objects * obj)
{
    while (objects->type) {
	if (objects->type == OPTION_OBJECT && *objects->status >= 0 &&
	    objects->binding == obj->binding)
	    *objects->status = 0;
	objects++;
    }
    *obj->status = 1;

    return 0;
}

static int draw_option_boxes(Objects * objects)
{
    Objects *x;

    R_standard_color(OUTLINE_COLOR);
    for (x = objects; x->type; x++) {
	if (x->type == OPTION_OBJECT && *x->status == 0)
	    Outline_box(x->top + 1, x->bottom, x->left, x->right - 1);
    }
    R_standard_color(GREEN);
    for (x = objects; x->type; x++) {
	if (x->type == OPTION_OBJECT && *x->status > 0)
	    Outline_box(x->top + 1, x->bottom, x->left, x->right - 1);
    }
    R_flush();

    return 0;
}

static int visible(Objects * object)
{
    if (object->type == OPTION_OBJECT)
	return (*object->status >= 0);
    return (*object->status > 0);
}

int Menu_msg(char *msg)
{
    int size, edge;

    size = VIEW_MENU->nrows - 4;
    edge = 2;

    Erase_view(VIEW_MENU);

    if (*msg) {
	R_text_size(size, size);
	R_standard_color(WHITE);
	Text(msg, VIEW_MENU->top, VIEW_MENU->bottom,
	     VIEW_MENU->left, VIEW_MENU->right, edge);
    }
    R_flush();
    replot = 1;

    return 0;
}

int Start_mouse_in_menu(void)
{
    Set_mouse_xy((VIEW_MENU->left + 2 * VIEW_MENU->right) / 3,
		 (VIEW_MENU->top + VIEW_MENU->bottom) / 2);

    return 0;
}
