/*  Motti -- a strategy game
    Copyright (C) 1999 Free Software Foundation

    This program 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.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include <config.h>

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

#include "xinit.h"
#include "xwin.h"
#include "map.h"
#include "occupy.h"

static void set_input_state (struct x_info_struct *);
static void resolve_map_mouse (struct x_info_struct *, const XEvent);

static void
set_input_state (x_info)
     struct x_info_struct *x_info;
{
  if (x_info->active)
    {
      XSelectInput (x_info->display, x_info->but_win[ATT], ButtonPressMask);
      XSelectInput (x_info->display, x_info->but_win[DEF], ButtonPressMask);
      XSelectInput (x_info->display, x_info->but_win[GUE], ButtonPressMask);
      XSelectInput (x_info->display, x_info->map_win, ExposureMask |
		    ButtonPressMask);
      if (x_info->uses_def_mode)
	XSetWindowBorderWidth (x_info->display, x_info->but_win[DEF],
			       x_info->db_tab.sel_width);
    }
  else /* Passive, just display events.  */
    {
      XSelectInput (x_info->display, x_info->but_win[ATT], 0);
      XSelectInput (x_info->display, x_info->but_win[DEF], 0);
      XSelectInput (x_info->display, x_info->but_win[GUE], 0);
      XSelectInput (x_info->display, x_info->map_win, ExposureMask);
      XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[ATT],
				  x_info->d_att_pix[6-game_map.n_att]);
      XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[DEF],
				  x_info->d_def_pix);
      XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[GUE],
				  x_info->d_gue_pix);
      if (x_info->uses_def_mode)
	{
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[ATT], 1);
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[DEF], 1);
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[GUE], 1);
	}

      XClearWindow (x_info->display, x_info->but_win[DEF]);
      XClearWindow (x_info->display, x_info->but_win[GUE]);
    }
}

static void
resolve_map_mouse (x_info, report)
     struct x_info_struct *x_info;
     const XEvent report;
{
  enum mouse_action button_action;

  switch (report.xbutton.button)
    {
    case Button1:
      button_action = x_info->db_tab.mouse[0];
      break;
    case Button2:
      button_action = x_info->db_tab.mouse[1];
      break;
    case Button3:
      button_action = x_info->db_tab.mouse[2];
      break;
    case Button4:
      button_action = x_info->db_tab.mouse[3];
      break;
    case Button5:
      button_action = x_info->db_tab.mouse[4];
      break;
    }
  switch (button_action)
    {
      Action map_events;
      Coord coord;
    case mark:
      coord = win_pos2map_coord (x_info, report.xbutton.x, report.xbutton.y);
      if (toggle_cross (coord))
	{
	  signal_mapchange (coord, coord);
	  signal_turnwinchange ();
	}
      break;
    case sel:
      select_next ();
      break;
    case act:
      action (game_map.sel_mode, &map_events);
      signal_action (&map_events);
      break;
    case last_place:
      /* Yet unimplemented.  */
    case attack:
      action (MODE_ATT, &map_events);
      signal_action (&map_events);
      break;
    case defend:
      action (MODE_DEF, &map_events);
      signal_action (&map_events);
      break;
    case guerilla:
      action (MODE_GUE, &map_events);
      signal_action (&map_events);
      break;
    case reset:
      clear_crosses ();
      map_events.type = EVENT_REFRESH;
      map_events.loc = NULL;
      map_events.count = 0;
      signal_action (&map_events);
      break;
      /* Smart action: do guerilla if possible, then defend and then attack.
       */
    case smart:
      if (game_map.modes & MODE_GUE)
	action (MODE_GUE, &map_events);
      else if (game_map.modes & MODE_DEF)
	action (MODE_DEF, &map_events);
      else
	action (MODE_ATT, &map_events);
      signal_action (&map_events);
      break;
      /* Half smart: do guerilla if possible, then defend.  Better for trigger
	 happy people with 3-button mouse than smart.  */
    case halfsmart:
      if (game_map.modes & MODE_GUE)
	action (MODE_GUE, &map_events);
      else if (game_map.modes & MODE_DEF)
	action (MODE_DEF, &map_events);
      else
	break;
      signal_action (&map_events);
      break;
    }
}

extern void
x_turnchange (x_info)
     struct x_info_struct *x_info;
{
  x_info->active = 1<<(game_map.turn-1) & x_info->conn_mask ? 1 : 0;
  if (x_info->last_active != x_info->active)
    {
      set_input_state (x_info);
      x_info->last_active = x_info->active;
      if (x_info->active)
	{
	  x_info->last_modes = 0;	/* Draw all windows, since they were
					   all previously disabled.  */
	  x_update_buttons (x_info);
	}
    }
}

extern void
x_event_handler (x_info)
     struct x_info_struct *x_info;
{
  do
    {
      XEvent report;

      XNextEvent (x_info->display, &report);

      switch (report.type)
	{
	  Action map_events;

	case Expose:
	  if (report.xexpose.window == x_info->map_win)
	    {
	      Coord loc, dim;
	      translate_box (x_info, report.xexpose.x, report.xexpose.y,
			     report.xexpose.width, report.xexpose.height,
			     &loc, &dim);
	      x_draw_map (x_info, loc, dim);
	    }
	  else if (report.xexpose.window == x_info->turn_win)
	    x_draw_turn_win (x_info);
	  else if (report.xexpose.window == x_info->endgame_win)
	    x_draw_end_win (x_info);
	  break;

	case ButtonPress:
	  if (!report.xbutton.same_screen) break;
	  if (report.xbutton.window == x_info->but_win[ATT])
	    {
	      action (MODE_ATT, &map_events);
	      signal_action (&map_events);
	    }
	  else if (report.xbutton.window == x_info->but_win[DEF])
	    {
	      action (MODE_DEF, &map_events);
	      signal_action (&map_events);
	    }
	  else if (report.xbutton.window == x_info->but_win[GUE])
	    {
	      action (MODE_GUE, &map_events);
	      signal_action (&map_events);
	    }
	  else if (report.xbutton.window == x_info->map_win)
	    resolve_map_mouse (x_info, report);

	  x_update_buttons (x_info);
	  break;
	case ButtonRelease:	/* This happens only from endgame window.  */
	case ClientMessage:	/* Window closed, die gracefully.  */
	  XCloseDisplay (x_info->display);
	  connection_terminated (x_info);
	}
      /* Xlib queues events, so there may already be events queued, which the
	 select call can't detect.  */
    } while (XEventsQueued (x_info->display, QueuedAlready));
}
