/*  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 <stdio.h>
#include <time.h>
#include <getopt.h>
#include <dirent.h>

#include "wrappers.h"
#include "comm.h"
#include "map.h"
#include "occupy.h"
#include "fill.h"
#include "mapgen.h"

static enum conn_type get_type (const char);
static int parse_numbers (const char **, const int, int *);
static void parse_players (int, char **, enum conn_type **, const char ***,
			   int **, const int, int);
static void help_msg (void);
static void version_msg (void);
static const char **display_name = NULL;
static const char *display_name_local;
static enum player_type *connection_types;

static enum conn_type
get_type (type)
     const char type;
{
#ifdef HAVE_LIBX11
  if (type == ':')
    return CONN_X;
#endif
  die ("invalid player type");
}

static int
parse_numbers (string, this_connect, num_players)
     const char **string;
     const int this_connect;
     int *num_players;
{
  int value, this_mask = 0, observer = 0;
  const char *ptr = *string;
  char *endptr;
  do
    {
      value = strtol (ptr, &endptr, 10);
      if (ptr == endptr)
	{
	  if (*ptr == ',')
	    {
	      ptr++;
	      continue;
	    }
	  else if (this_mask || observer)
	    {
	      *string = ptr+1;
	      return this_mask;
	    }
	  else
	    die ("invalid player string");
	}
      ptr = endptr;
      if (value <= game_map.players && value > 0)
	{
	  this_mask |= 1<<(value-1);
	  (*num_players)++;
	}
      else if (value == 0)
	observer = 1;
      else
	die ("invalid player number");
    } while (*ptr != '\0');
  die ("invalid player string: %s", string);
}

static void
parse_players (argc, argv, type, name, connect_mask, use_curses, players)
     int argc;
     char *argv[];
     enum conn_type **type;
     const char ***name;
     int **connect_mask;
     const int use_curses, players;
{
  int players_marked = 0, local_player, this_connect = 0;
  int p_missing, p_present = 0;
  const char *ptr;
  *name = my_malloc (sizeof (char *) * argc);
  *type = my_malloc (sizeof (enum conn_type) * argc);
  n_connect = 0;
  /* Enough in all cases.  */
  *connect_mask = my_malloc (sizeof (int) * (argc+1));

  if (players)
    p_missing = game_map.players - players;
  else
    p_missing = 0;

#if HAVE_LIBX11
  while (++optind < argc)
    {
      int this_display_mask;
      ptr = argv[optind];
      this_display_mask = parse_numbers (&ptr, this_connect, &p_present);

      if (this_display_mask & players_marked)
	die ("player set multiple times");

      players_marked |= this_display_mask;
      (*name)[this_connect] = ptr;
      (*type)[this_connect++] = get_type (*(ptr-1));
      (*connect_mask)[n_connect++] = this_display_mask;
    }
#endif

  /* All players, which aren't explicitly set, are local players.  */
  local_player = ~players_marked & ((1<<game_map.players)-1);
  /* Erase extraneous players.  */
  if (p_missing)
    {
      int missing_mask = local_player, disable_mask = 0, pl = 0;
      while (missing_mask && p_missing-- > 0)
	{
	  while (!(missing_mask & 1))
	    {
	      missing_mask >>= 1;
	      pl++;
	    }
	  disable_mask |= 1<<pl++;
	}
      if (disable_mask)
	{
	  Action act;
	  defeat_players (disable_mask, &act);
	  local_player ^= disable_mask;
	}
    }

  /* Allow curses even if there are no players playing on console.  */
  if (use_curses)
    (*type)[n_connect] = CONN_CURSES;
  else if (local_player)
    {
      (*type)[n_connect] = CONN_X;
      (*name)[n_connect] = "";
    }
  else
    return;
  (*connect_mask)[n_connect++] = local_player;
}

static void
help_msg ()
{
#if defined HAVE_LIBX11
  puts ("Usage: motti map | generate [options] [player, ...]");
#else
  puts ("Usage: motti map | generate [options]");
#endif
  puts ("First argument is either a map name or the string \'generate\'.\n");
#if defined HAVE_LIBCURSES && defined HAVE_LIBX11
  puts ("  -c, --curses                 use curses interface");
#endif
  puts ("  -o, --output=FILE            if given, save generated map here");
  puts ("  -p, --players=PLAYERS        number of players");
  puts ("      --help                   display this help and exit");
  puts ("      --version                output version information and exit\n");
  puts ("Options usable if 'generate' given:");
  puts ("  -d, --distance-min=FLOAT     minimum distance of capitals from each other");
  puts ("  -g, --granularity=FLOAT      plasma granularity");
  puts ("  -h, --heigth=ROWS            map heigth");
  puts ("  -m, --plasma-min=FLOAT       minimum value for plasma template value range");
  puts ("  -M, --plasma-max=FLOAT       maximum value for plasma template value range");
  puts ("  -r, --randomness=FLOAT       amount of randomness added to each cell");
  puts ("  -t, --threshold=FLOAT        threshold for a cell to be land, not water");
  puts ("  -w, --width=COLS             map width");
#ifdef HAVE_LIBX11
  puts ("Player specified with format 1,2,...,n:display");
#endif	/* have_libx11 */
  puts ("\nReport bugs to <bug-motti@gnu.org>");
  exit (0);
}

static void
version_msg ()
{
  puts (VERSION_STR);
  puts ("Copyright (C) 2000 Free Software Foundation, Inc.");
  puts ("Motti comes with NO WARRANTY,");
  puts ("to the extent permitted by law.");
  puts ("You may redistribute copies of motti");
  puts ("under the terms of the GNU General Public License.");
  puts ("For more information about these matters,");
  puts ("see the files named COPYING.");
  exit (0);
}

static void
list_maps ()
{
  DIR *dir;
  struct dirent *dp;
  fprintf (stderr, "motti: no map file specified, maps available at %s:\n", MAPPATH);
  dir = opendir (MAPPATH);
  if (!dir)
    fprintf (stderr, "motti: can't read directory %s\n", MAPPATH);
  else
    while (dp = readdir (dir))
      if (*dp->d_name != '.')
	printf ("%s\n", dp->d_name);
  fprintf (stderr, "motti: use 'motti generate' to create a map\n");
  exit (0);
}

int
main (argc, argv)
     int argc;
     char *argv[];
{
  char *status_msg, *save_file = NULL;
  int use_curses = 0, players = 0, width = 20, height = 15;
  double distance_min = 8.0, threshold = .15, plasma_min = .0, plasma_max = .3;
  double granularity = .03, randomness = .2;
  int *connect_mask;
  enum conn_type *connection_type;
  const char **connection_name;

  while (1)
    {
      int c;
      const struct option long_options[] =
      {
#if defined HAVE_LIBCURSES && defined HAVE_LIBX11
	{"curses", 0, 0, 'c'},
#endif
	{"players", 1, 0, 'p'},
	{"width", 1, 0, 'w'},
	{"height", 1, 0, 'h'},
	{"distance-min", 1, 0, 'd'},
	{"threshold", 1, 0, 't'},
	{"plasma-min", 1, 0, 'm'},
	{"plasma-max", 1, 0, 'M'},
	{"granularity", 1, 0, 'g'},
	{"randomness", 1, 0, 'r'},
	{"output", 1, 0, 'o'},
	{"help", 0, 0, 1000},
	{"version", 0, 0, 1001},
	{0, 0, 0, 0}
      };

      c = getopt_long (argc, argv, "cp:w:h:d:t:m:M:g:r:o:",
		       long_options, (int *) NULL);
      if (c == -1)
	break;

      switch (c)
	{
#if defined HAVE_LIBCURSES && defined HAVE_LIBX11
	case 'c':
	  use_curses = 1;
	  break;
#endif
	case 'p':
	  players = atoi (optarg);
	  if (players < 2)
	    players = 2;
	  else if (players > MAXPLAYERS)
	    players = MAXPLAYERS;
	  break;
	  /* All of these have some sort of a sanity check in the map
	     generator.  */
	case 'w':
	  width = atoi (optarg);
	  break;
	case 'h':
	  height = atoi (optarg);
	  break;
	case 'd':
	  distance_min = atof (optarg);
	  break;
	case 't':
	  threshold = atof (optarg);
	  break;
	case 'm':
	  plasma_min = atof (optarg);
	  break;
	case 'M':
	  plasma_max = atof (optarg);
	  break;
	case 'g':
	  granularity = atof (optarg);
	  break;
	case 'r':
	  randomness = atof (optarg);
	  break;
	case 'o':
	  save_file = optarg;
	  break;
	case 1000:
	default:
	  help_msg ();
	case 1001:
	  version_msg ();
	}
    }

  puts (VERSION_STR);
  puts ("Copyright 2000 Free Software Foundation, Inc.");
  puts ("This is free software with ABSOLUTELY NO WARRANTY.");
  puts ("For details read file 'COPYING'.");

  srand (time ((time_t *) NULL));
  init_fill ();

  if (argc == optind)
    list_maps ();
  if (strncmp (argv[optind], "generate", 8) != 0)
    load_map (argv[optind]);
  else
    {
      if (players == 0)
	players = 2;
      create_map (players, width, height, distance_min, threshold,
		  plasma_min, plasma_max, granularity, randomness);
    }

  init_occupy ();
  parse_players (argc, argv, &connection_type, &connection_name,
		 &connect_mask, use_curses, players);

#ifdef HAVE_LIBX11
  global_argc = argc;
  global_argv = argv;
#endif

  if (save_file)
    save_map (save_file);

  init_game (connection_type, connection_name, connect_mask);
  return 0;	/* Never executed.  */
}
