/*  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 <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_LIBX11
#include <X11/Xlib.h>
#endif

#include "comm.h"
#include "wrappers.h"
#include "occupy.h"
#include "map.h"
#ifdef HAVE_LIBX11
#include "xinit.h"
#endif
#ifdef HAVE_LIBCURSES
#include "curses_if.h"
#endif

int n_connect;

static void signal_end_game (void);

#if 0
#ifdef HAVE_LIBX11
static union conn_info * x_game_init ();
#endif
#ifdef HAVE_LIBCURSES
static union conn_info * c_game_init ();
#endif
#endif

static int connections_left = 0;
static union conn_info *conn_info;

static void
signal_end_game ()
{
  register int i;
  for (i = 0; i < n_connect; i++)
    {
#ifdef HAVE_LIBX11
      if (conn_info[i].common.type == CONN_X)
	{
	  x_create_end_win (&conn_info[i]);
	  continue;
	}
#endif
#ifdef HAVE_LIBCURSES
      if (conn_info[i].common.type == CONN_CURSES)
	kill_curses ();
#endif
    }
}

extern void
signal_action (Action *act)
{
  register int i, j;
  Coord top_left = {0, 0}, down_right;

  down_right.x = game_map.width;
  down_right.y = game_map.height;
  if (!act->type)	/* Do not do nothing.  */
    return;
  if (act->type & EVENT_NEWTURN)
    signal_turnchange ();
  signal_turnwinchange ();
  if ((act->type & EVENT_ATT) || (act->type & EVENT_NEWTURN))
    signal_attackchange ();

  for (i = 0; i < n_connect; i++)
    {
#ifdef HAVE_LIBX11
      if (conn_info[i].common.type == CONN_X)
	{
	  if ((act->type & (EVENT_ENCIRCLEMENT | EVENT_UNOCCUPY |
			    EVENT_DEFEAT | EVENT_REFRESH))
	      || ((act->type & EVENT_ATT) && (act->type & EVENT_NEWTURN)))
	    x_draw_map (&conn_info[i].x_info, top_left, down_right);
	  else
	    for (j = 0; j < act->count; j++)
	      x_draw_map (&conn_info[i], act->loc[j], act->loc[j]);
	  continue;
	}
#endif
#ifdef HAVE_LIBCURSES
      if (conn_info[i].common.type == CONN_CURSES)
	c_process_action (act);
#endif
    }
  if (act->count)
    free (act->loc);

  if (game_map.players_left == 1)
    signal_end_game ();
}

extern void
signal_mapchange (loc, dim)
     Coord loc, dim;
{
  register int i;
  for (i = 0; i < n_connect; i++)
    {
#ifdef HAVE_LIBX11
      if (conn_info[i].common.type == CONN_X)
	{
	  x_draw_map (&conn_info[i].x_info, loc, dim);
	  continue;
	}
#endif
#ifdef HAVE_LIBCURSES
      if (conn_info[i].common.type == CONN_CURSES)
	{
	  if (dim.x == 0 && dim.y == 0)
	    {
	      c_draw_loc (parse_coord (loc));
	      do_refresh (REFRESH_MAP);
	    }
	  else
	    do_refresh (ALL);
	}
#endif
    }
}

extern void
signal_turnchange ()
{
  register int i;
  for (i = 0; i < n_connect; i++)
    {
#ifdef HAVE_LIBX11
      if (conn_info[i].common.type == CONN_X)
	{
	  x_turnchange (&conn_info[i].x_info);
	  x_draw_turn_win (&conn_info[i].x_info);
	  continue;
	}
#endif
#ifdef HAVE_LIBCURSES
      if (conn_info[i].common.type == CONN_CURSES)
	do_refresh (STATUSLINE);
#endif
    }
}

extern void
signal_turnwinchange ()
{
  register int i;
  for (i = 0; i < n_connect; i++)
    {
#ifdef HAVE_LIBX11
      if (conn_info[i].common.type == CONN_X)
	{
	  x_draw_turn_win (&conn_info[i].x_info);
	  continue;
	}
#endif
#ifdef HAVE_LIBCURSES
      if (conn_info[i].common.type == CONN_CURSES)
	do_refresh (STATUSLINE);
#endif
    }
}

extern void
signal_attackchange ()
{
  register int i;
  for (i = 0; i < n_connect; i++)
    {
#ifdef HAVE_LIBX11
      if (conn_info[i].common.type == CONN_X)
	{
	  conn_info[i].x_info.last_modes ^=
	    (conn_info[i].x_info.last_modes & MODE_ATT);
	  x_update_buttons (&conn_info[i].x_info);
	  continue;
	}
#endif
#if 0
#ifdef HAVE_LIBCURSES
      if (conn_info[i].common.type == CONN_CURSES)
	do_refresh (STATUSLINE);
#endif
#endif
    }
}

extern void
connection_terminated (info)
     union conn_info *info;
{
  Action act;
  info->common.type = CONN_NONE;
  if (--connections_left == 0)
    exit (0);
  defeat_players (info->common.conn_mask, &act);
  signal_action (&act);
}

extern void
init_game (conn_type, conn_name, connect_mask)
     const enum conn_type *conn_type;
     const char **conn_name;
     const int *connect_mask;
{
  register int i;
  int xrminit_called = 0, maxfd = -1;
  conn_info = my_malloc (sizeof (union conn_info) * n_connect);

  for (i = 0; i < n_connect; i++, connections_left++)
    {
      conn_info[i].common.conn_mask = connect_mask[i];
#ifdef HAVE_LIBX11
      if (conn_type[i] == CONN_X)
	{
	  conn_info[i].x_info.type = CONN_X;
	  if (!xrminit_called)
	    {
	      XrmInitialize ();
	      xrminit_called = 1;
	    }

	  /* The init function returns false if opening a display failed and
	     only one connection is requested and no display name is set
	     explicitly.  */
	  if (x_game_init (conn_name[i], &conn_info[i].x_info))
	    continue;
	}
#endif
#ifdef HAVE_LIBCURSES
      conn_info[i].common.type = CONN_CURSES;
      curses_game_init (&conn_info[i]);
#endif
    }

  for (i = 0; i < n_connect; i++)
    {
#ifdef HAVE_LIBX11
      if (conn_info[i].common.type == CONN_X)
	x_turnchange (&conn_info[i].x_info);
#endif
      if (conn_info[i].common.fd > maxfd)
	maxfd = conn_info[i].common.fd;
    }
  maxfd++;

  while (1)
    {
      fd_set readset;

      FD_ZERO (&readset);
      for (i = 0; i < n_connect; i++)
	if (conn_info[i].common.type != CONN_NONE)
	  {
	    FD_SET (conn_info[i].common.fd, &readset);
#ifdef HAVE_LIBX11
	    if (conn_info[i].common.type == CONN_X)
	      XFlush (conn_info[i].x_info.display);
#endif
	  }

      select (maxfd, &readset, NULL, NULL, NULL);

      for (i = 0; i < n_connect; i++)
	if (conn_info[i].common.type != CONN_NONE
	    && FD_ISSET (conn_info[i].common.fd, &readset))
	  {
	    Action act;
#ifdef HAVE_LIBX11
	    if (conn_info[i].common.type == CONN_X)
	      {
		x_event_handler (&conn_info[i].x_info);
		continue;
	      }
#endif
#ifdef HAVE_LIBCURSES
	    if (conn_info[i].common.type == CONN_CURSES)
	      {
		c_read_key (&conn_info[i]);
		continue;
	      }
#endif
	    /* No connection here, just skip the player.  */
	    action (MODE_DEF, &act);
	    signal_action (&act);
	  }
    }
}
