/*
 * hearts - human interface to hearts program
 *
 * All smarts are in heartsd, which is invoked by initial caller of hearts.
 *
 * Private messages, last-play, auto-play added by:
 *      Mike Yang of Silicon Graphics (mikey@sgi.com)
 *
 * By Bob Ankeney or Generic Computer Products
 * Bug reports to:
 * ...!tektronix!reed!bob
 *
 *
 * Commands to hearts client (r = rank, s = suit):
 *
 * Ars		Add card to hand.
 * Rrs		Remove card from hand.
 * En		Erase window n.
 * G		Get a card.
 * Pnrs<name>	Play card from player n, whose name is <name>.
 * Snpptt<name>	Score points (pp) and total points (tt) for player n.
 * Mn<text>	Message <text> is placed in window n.
 * X		Go away.
 * Z		Game over, socket closing.
 *
 * Messages from client:
 *
 * Prs		Pass/Play card from hand.
 * M<text>		Send message <text> to all players.
 *
 */

#include <sys/errno.h>
#include "misc.h"
#include "defs.h"
#include "local.h"
#include "client.h"
#ifdef SYSV
#include <sys/termio.h>
#endif

int	dist_socket, dealer_socket;
char    game_over, first_game;
char	host[256];

char	*snames[] = {
	    "",
	    "clubs",
	    "diamonds",
	    "hearts",
	    "spades"
	},
	rnames[] = " 23456789TJQKA";

get_going()
{
	int	dealer_port;
	char	*name, *getenv();
	/*
	 * Connect to distributor.  If not available, start it.
	 */
	if ((dist_socket = connect_to(host, PORT)) == 0) {
		start_distributor();
		if ((dist_socket = connect_to(host, PORT)) == 0)
			death("Can't invoke distributor!");
	}
	/*
	 * Get dealer port and connect to it.
	 * If port returned == 0, restart game with old dealer.
	 */
	if (dealer_port = select_game()) {
		if (!first_game) {
		        (void) close(dealer_socket);
			close_socket(dealer_socket);
		}
		if ((dealer_socket = connect_to(host, dealer_port)) == 0)
			death("Can't connect to dealer!\n");
		if ((name = getenv("HEARTS")) == NULL)	/* get user name */
			if ((name = getenv("NAME")) == NULL)
				name = getenv("USER");
		init_socket();
		write_socket(dealer_socket, name);	/* tell dealer */
	}
	start_game();
}

do_command(buf)
char	*buf;
{
	char	rch, sch;
	int	player, suit, pts, total_pts, window_num;

	switch (buf[0]) {
	case 'A' :		/* Add card to hand */
	        enter_card(get_rank(buf[1]), get_suit(buf[2]));
		break;

	case 'R' :		/* Remove card from hand */
	        remove_card(get_rank(buf[1]), get_suit(buf[2]));
		break;

	case 'E' :		/* Erase window */
	        erase_window(buf[1] - '0');
		break;

	case 'G' :		/* Get card */
		read_card();
		break;

	case 'P' :		/* Play card from player */
		(void) sscanf(buf+1, "%1d %c %c", &player, &rch, &sch);
		play_card(player, rch, sch, buf+4);
		break;

	case 'S' :		/* Score points for player */
		(void) sscanf(buf+1, "%1d %3d %3d", &player, &pts, &total_pts);
		score_points(player, pts, total_pts, buf+8);
		break;

	case 'M' :		/* Print message in window */
	        display_message(buf[1] - '0', buf+2);
		break;

	case 'X' :		/* Game over */
	        game_is_over();
		game_over = TRUE;
		first_game = FALSE;
		break;

	case 'Z' :		/* Game over, socket closing */
	        game_is_over();
		game_over = TRUE;
	        first_game = TRUE;
		(void) close(dealer_socket);
		close_socket(dealer_socket);
	}
}

/*
 * Filter out nasties from message in buffer
 */

mikey_strcmp(s,t)
char s[], t[];
{
  int i;

  i = 0;
  while ((s[i] == t[i]) || (s[i] >= 'A' && s[i] <= 'Z' &&
			    (s[i] - 'A' + 'a') == t[i]))
    if (t[i++] == '\0')
      return(TRUE);
  return((t[i] == '\0'));
}

block(buf, what)
char *buf, *what;
{
  int i;

  for (i=0;i<=strlen(what);i++)
    *buf++ = *what++;
}

mikey_filter(buf)
char *buf;
{
  int i;

  for (i=1;i<strlen(buf);i++) {
    if (mikey_strcmp(buf+i,"asshole"))
      block(buf+i,"a--hole");
    if (mikey_strcmp(buf+i,"tit"))
      block(buf+i,"t-t");
    if (mikey_strcmp(buf+i,"shit"))
      block(buf+i,"s--t");
    if (mikey_strcmp(buf+i,"damn"))
      block(buf+i,"d--n");
    if (mikey_strcmp(buf+i,"fuck"))
      block(buf+i,"f--k");
  }
}

/**********************************************************************/

do_socket()
{
  char buf[64];

  if (!read_socket(dealer_socket, buf))
    death("Dealer died!!");
  do_command(buf);
}

send_message(msg)
char *msg;
{
  char buf[64];

  strcpy(buf, "M");
  if (strlen(msg) <= 62) {
    strcat(buf, msg);
  } else {
    strncat(buf, msg, 62);
  }
  mikey_filter(buf);
  write_socket(dealer_socket, buf);
}

send_private_message(who, msg)
int who;
char *msg;
{
  char buf[64];

  sprintf(buf, ";%d", who);
  if (strlen(msg) <= 61) {
    strcat(buf, msg);
  } else {
    strncat(buf, msg, 61);
  }
  mikey_filter(buf);
  write_socket(dealer_socket, buf);
}

toggle_private_messages()
{
  char buf[2];

  buf[0] = '~';
  buf[1] = '\0';
  write_socket(dealer_socket, buf);
}

send_card(rank, suit)
int rank, suit;
{
  char buf[64];

  sprintf(buf, "P%c%c", rank, suit);
  write_socket(dealer_socket, buf);
}

send_auto()
{
  char buf[64];

  sprintf(buf, "P?%c", HEARTS);
  write_socket(dealer_socket, buf);
}

close_windows()
{
	(void) signal(SIGINT, SIG_IGN);
	terminate();
}

death(buf)
char	*buf;
{
	close_windows();
	printf("%s\n", buf);
	exit(1);
}

wimp_out()
{
	close_windows();
	exit(0);
}

get_rank(rch)
int rch;
{
	int	i;

	for (i = 1; i <= MAX_RANK; i++)
		if (rch == rnames[i])
			return(i);
	return(0);
}

get_suit(sch)
int sch;
{
	int	i;

	for (i = 1; i <= MAX_SUIT; i++)
		if (sch == *snames[i])
			return(i);
	return(0);
}

start_new_game()
{
  write_socket(dist_socket, "n");
}

join_game(i)
int i;
{
  char buf[64];

  (void) sprintf(buf, "j%d", i);
  write_socket(dist_socket, buf);
}

do_dist()
{
  int i;
  char buf[64];

  if (read_socket(dist_socket, buf) == 0)
    dist_died(3);
  i = update_table(buf);
  show_tables(cur_screen_table);
}

main(argc, argv)
int	argc;
char	**argv;
{
/* Call init first, in case the client wants to parse arguments */
	init(&argc, argv);

	if (argc > 2) {
		fprintf(stderr, "usage: %s [hostname]\n", *argv);
		exit(1);
	}
	if (argc == 2)
		(void) strcpy (host, *++argv);
	else
		(void) gethostname(host, sizeof(host));	/* host is this machine */

	first_game = TRUE;

	(void) signal(SIGINT, wimp_out);

	for (;;) {
		game_over = FALSE;
		get_going();
		do {
			scan();
		}
		while (!game_over);
	}
}

