/*
 *  gencmds.c		
 */

/*
   Command interface routines general to ntserv/daemon/robot code.  This
   is a replacement for the spagetti compile method used previously in
   commands.c .  Instead of compiling this file several times with modified
   defines, the generalized routines found here can be linked into other
   executables.
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "gencmds.h"

char *
addr_mess(who, type)
     int who, type;
{
    static char addrbuf[10];
    char* team_names[MAXTEAM+1] = { "", "FED", "ROM", "", "KLI",
                                 "", "", "", "ORI" };

    if (type == MALL) 
      sprintf(addrbuf,"%s->ALL", myname);
    else if (type == MTEAM)
      sprintf(addrbuf,"%s->%3s", myname, team_names[who]);
    else /* Assume MINDIV */
      sprintf(addrbuf, "%s->%2s", myname, players[who].p_mapchars);

    return (addrbuf);
}

/* Check a command list to see if a message is a command */
int
check_2_command(mess, cmds, prereqs)
     struct message *mess;
     struct command_handler_2 *cmds;
     int prereqs;
{
  int i, j, len;
  char *comm;
  FILE *glog;

  if (!(mess->m_flags & MINDIV)) return 0;	/* double-check */

  len = strlen(mess->m_data);

  /* Check if a null command ( First 8 characters are XXX->XXX ) */
  if (len <= 8)
    return 0;

  for (i = 8; i < len && isspace(mess->m_data[i]); i++) ; /* skip header/space */

  comm = strdup(&mess->m_data[i]);

  len = strlen(comm);

  /* Convert first word in msg to uppercase */
  for (i=0; (i < len && !isspace(comm[i])); i++)
  {
    comm[i] = toupper(comm[i]);
  }

  for (i=0; cmds[i].command != NULL; i++)
  {
    /* Dont check dummy descriptions.. */
    if (cmds[i].tag & C_DESC)
      continue;
    if ((cmds[i].tag & C_PR_MASK) & ~(prereqs))
      /* Dont meet the prereqs */
      continue;
    if (strncmp(cmds[i].command, comm, strlen(cmds[i].command)) == 0)
    {

      /* Record vote in GodLog if C_GLOG is set */
      if (cmds[i].tag & C_GLOG )
      {
	if (!(glog = fopen(GodLog,"a")) )       /* Log votes for God to see */
	  perror(GodLog);
	else
	{
	  time_t    t = time(NULL);
	  char      tbuf[40];
	  struct tm *tmv = localtime(&t);

#ifdef STRFTIME
	  sprintf(tbuf, "%02d/%02d %d/%d", tmv->tm_hour,tmv->tm_min,
		  tmv->tm_mday,tmv->tm_mon);
#else
	  strftime(tbuf, 39, "%R %D", tmv);
#endif
	  fprintf(glog, "VOTE: %s %s@%s \"%s\"\n", tbuf,
		  players[mess->m_from].p_login, 
		  players[mess->m_from].p_monitor, comm);
	  fclose(glog);
	}
      }

/* assume C_NAME */
#ifdef nodef
      if (!(cmds[i].tag & C_NAME))
      {
	for (j=i; j < strlen(upper); j++)
	  upper[j] = toupper(upper[j]);
      }
#endif

#ifdef VOTING
      if (cmds[i].tag & (C_VC_ALL | C_VC_TEAM))
      {
	if (do_vote(comm, mess, cmds, i))
	{
	  if ( cmds[i].tag & C_GLOG )
	    if (!(glog = fopen(GodLog,"a")) )       /* Log pass for God to see */
	      perror(GodLog);
	    else
	    {
	      fprintf(glog, "VOTE: The motion %s passes\n", comm);
	      fclose(glog);
	    }
	}
      }
      else
#endif
      {
	if (cmds[i].tag & C_PLAYER)
	{
	  int who;

	  /* This is really not that usefull - If the calling
	     function needs a player field, it should check it
	     on it's own.  I include it here for compatibility */
	  who = getplayer(mess->m_from, comm);
	  if (who >= 0)
	    (*cmds[i].handler)(comm, mess, who, cmds, i, prereqs);
	  else
	  {
	    free(comm);
	    return 0;
	  }
	}
	else
	  (*cmds[i].handler)(comm, mess, cmds, i, prereqs);
      }
      free(comm);
      return 1;
    }
  }
  free(comm);
  return 0;
}

int
getplayer(from, line)
     int from;
     char *line;
{
  char id;
  char temp[MSG_LEN];
  int what;
  int numargs;

  numargs = sscanf(line,"%s %c", temp, &id);
  id = toupper(id);

  if (numargs==1)
    what = from;
  else if ((id >= '0') && (id <='9'))
    what = id - '0';
  else if ((id >= 'A') && (id <= ('A' + MAXPLAYER - 10)))
    what = id - 'A' + 10;
  else
  {
    pmessage(from, MINDIV, addr_mess(from, MINDIV),
	     " Invalid player number.");
    return -1;
  }
  if (players[what].p_status == PFREE)
  {
    pmessage(from, MINDIV, addr_mess(from, MINDIV),
	     " Player not in the game.");
    return -1;
  }
  return what;
}

#ifdef VOTING
int
do_vote(comm, mess, votes, num)
     char *comm;
     struct message *mess;
     struct command_handler_2 *votes;
     int num;
{
  int what = 0;
  int player = -1;
  register int i;
  register struct player *j;
  int pcount=0;  /* Total players in game */
  int vcount=0;  /* Number who've voted recently */
  int mflag = 0;
  int sendto = 0;
  int who;

  who = mess->m_from;

#ifdef OBSERVERS
  if (players[who].p_status == POBSERV)
  {
    bounce(who, "Sorry, Observers can't vote");
    return 0;
  }
#endif

  if (votes[num].tag & C_PLAYER)
  {
    if ((what = getplayer(who, comm)) < 0)
      return 0;
    player = what;
  }

  what += votes[num].start;

  if (what >= PV_TOTAL) return 0;

  j = &players[who];
  if ((j->voting[what] != 0) && (votes[num].frequency != 0))
  {
    if (j->voting[what] < time(NULL) + votes[num].frequency)
    {
      bounce(who,"Sorry, you can only use %s every %1.1f minutes",
	     votes[num].command, votes[num].frequency / 60.0);
      return 0;
    }
  }
  j->voting[what] = time(NULL);  /* Enter newest vote */

  if (votes[num].tag & C_VC_TEAM)
  {
    sendto = players[who].p_team;
    mflag = MTEAM;
  }
  else if (votes[num].tag & C_VC_ALL)
  {
    sendto = 0;
    mflag = MALL;
  }
  else
  {
    ERROR(1,("Unrecognized message flag in do_vote() for %s\n",
	     comm));
    return 0;
  }

  for (i=0, j = &players[i]; i < MAXPLAYER; i++, j++)
  {
    /*Skip free slots and robots */
    if ( (j->p_status == PFREE) || (j->p_flags & PFROBOT))
      continue;

    /*Also skip players that are not on the same team if team flag is set*/
    if ((votes[num].tag & C_VC_TEAM) && (j->p_team != players[who].p_team))
      continue; 

#ifdef OBSERVERS
    /* Also skip observers */
    if (j->p_status == POBSERV)
      continue;
#endif

    pcount++;

    /* Did a player vote expire? */
    if ((j->voting[what] > 0)
	&& ((votes[num].expiretime == 0)
	    || (j->voting[what] + votes[num].expiretime > time(NULL))))
      vcount++;
  }
  pmessage(sendto, mflag, addr_mess(sendto,mflag),
	   "%s has voted to %s. %d player%s (of %d) %s voted.",
	   players[who].p_mapchars, comm, vcount, vcount==1 ? "":"s",
	   pcount, vcount==1 ? "has":"have");

  /* The Votes Passes */
  if ( (vcount >= votes[num].minpass)
      && ( ((pcount < (2*vcount)) && (votes[num].tag & C_VC_ALL))
	  || ((votes[num].tag & C_VC_TEAM) && (pcount-1 <= vcount)) ))
  {
    pmessage(sendto, mflag, addr_mess(sendto,mflag), 
	     "The motion %s passes", comm);

    /* Reset the Votes for this item since it passed */
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) 
      j->voting[what] = -1;

    if (votes[num].tag & C_PLAYER)
      (*votes[num].handler)(who, player, mflag, sendto);
    else
      (*votes[num].handler)(who, mflag, sendto);

    return 1;
  }
  else
  {
    if (votes[num].tag & C_VC_TEAM) 
      i = pcount - vcount - 1;
    else
      i = pcount/2 + 1 - vcount;

    if (i < (votes[num].minpass - vcount))
      i = votes[num].minpass - vcount;

    pmessage(sendto, mflag, addr_mess(sendto, mflag),
	     "Still need %d more vote%s %s", i, (i==1 ? " ":"s"), comm);
    return 0;
  }
}
#endif /* VOTING */

/* ARGSUSED */
int
do_help(comm, mess, cmds, cmdnum, prereqs)
     char *comm;
     struct message *mess;
     struct command_handler_2 *cmds;
     int cmdnum;
{
  int who;
  int i;
  char *addr;

  who = mess->m_from;
  addr = addr_mess(who,MINDIV); 

  if (cmds[0].command != NULL)
  { 
    for (i=0; cmds[i].command != NULL; i++)
    {
      if ((cmds[i].tag & C_PR_MASK) & ~(prereqs))
	/* Dont meet the prereqs */
	continue;
      if (cmds[i].tag & C_DESC)
	/* Command is just a dummy description */
	pmessage(who,MINDIV,addr, cmds[i].command);
#ifdef VOTING
      else if (cmds[i].tag & (C_VC_TEAM | C_VC_ALL))
      {
	char ch;

	if (cmds[i].tag & C_VC_TEAM)
	  ch = 'T';
	else if (cmds[i].tag & C_VC_ALL)
	  ch = 'M';
	else
	  ch = '?';
	pmessage(who,MINDIV,addr, "|%10s - %c: %s",
		 cmds[i].command, ch, cmds[i].desc);
      }
#endif /* VOTING */
      else
	pmessage(who,MINDIV,addr, "|%10s - %s",
		 cmds[i].command, cmds[i].desc);
    }
  }
}
