#include <stdio.h>
#include <ctype.h>
#include "Connect.h"
#include "Parse.h"
#include "inet-udp.h"
#include "server.h"

Trap mapPort(), connectPorts(), setServers(),
  setVendor(), setProgram(), setVersion(),
  newPool(), setLicenses();

Keywords mainwords[] =
{
  { "port",			mapPort },
  { "connection",		connectPorts },
  { "serverconnections",	setServers },
  { "vendor",			setVendor },
  { "program",			setProgram },
  { "version",			setVersion },
  { "pool",			newPool },
  { "licenses",			setLicenses },
/*
  { "authentication",		setAuthentication },
  { "authorization",		setAuthorization },
  { "totallicenses",		setTotallicenses },
*/
  { NULL,		NULL }
};

/*
 * ERRORS:
 *
 * APP_PORTTOOLARGE: FATAL
 * The port number specified is out of range.
 *
 * APP_PORTNUMEXPECTED: FATAL
 * A port number was expected, but not found.
 *
 * APP_PORTINITIALIZED: FATAL
 * The port number specified was already initialized.
 */
Trap mapPort(block, line)
     MasterBlock *block;
     char *line;
{
  int i;
  srvinfo *info;
  char *temp;
  Trap retval;

  if (Parse_GetCurrentData(block, "srvinfo",
			   (caddr_t *)&info, sizeof(srvinfo)))
    {
      if (Error_Severity == S_FATAL)
	return CHECK;
      else
	Error_Pop();
    }

  if (!info->portsInitialized)
    {
      for (i = 0; i < MAXPORTS; i++)
	info->ports[i] = NOADDRESS;
      info->portsInitialized++;
    }

  while (isspace(*line)) line++;

  if (isdigit(*line))
    {
      i = atoi(line);
      if (i >= MAXPORTS)
	Return(APP_PORTTOOLARGE, i);
    }
  else
    Return(APP_PORTNUMEXPECTED, NULL);

  if (info->ports[i] != NOADDRESS)
    Return(APP_PORTINITIALIZED, i);

  while (isdigit(*line)) line++;
  while (isspace(*line)) line++;

  temp = (char *)malloc(strlen(line) + 1);
  if (temp == NULL)
    Return(MEMORY_ALLOC, strlen(line) + 1);

  strcpy(temp, line);
  if (temp[strlen(temp) - 1] == '\n')
    temp[strlen(temp) - 1] = '\0';

  retval = Connect_NameToAddress(temp, &(info->ports[i]));
  free(temp);
  return retval;
}

int getnum(ptr)
     char **ptr;
{
  char *line;
  int i;

  line = *ptr;
  if (isdigit(*line))
    i = atoi(line);
  else
    return -1;

  while (isdigit(*line)) line++;
  while (isspace(*line)) line++;
  *ptr = line;
  return i;
}

/*
 * ERRORS:
 *
 * APP_CONNTOOLARGE: FATAL
 * The connection number specified is out of range.
 *
 * APP_CONNNUMEXPECTED: FATAL
 * A connection number was expected, but not found.
 *
 * APP_CONNINITIALIZED: FATAL
 * The connection number specified was already initialized.
 *
 * APP_CONNPORTUNDEFINED: FATAL
 * A port specified in the connection was not defined.
 */
Trap connectPorts(block, line)
     MasterBlock *block;
     char *line;
{
  int i, j, k;
  srvinfo *info;

  if (Parse_GetCurrentData(block, "srvinfo",
			   (caddr_t *)&info, sizeof(srvinfo)))
    {
      if (Error_Severity == S_FATAL)
	return CHECK;
      else
	Error_Pop();
    }

  if (!info->connectionsInitialized)
    {
      for (i = 0; i < MAXCONNS; i++)
	info->fromConnections[i] = NOADDRESS;
      info->connectionsInitialized++;
    }

  while (isspace(*line)) line++;
  i = getnum(&line);
  if (i == -1)
    Return(APP_CONNNUMEXPECTED, NULL);
  if (i >= MAXCONNS)
    Return(APP_CONNTOOLARGE, i);

  if (info->fromConnections[i] != NOADDRESS)
    Return(APP_CONNINITIALIZED, i);

  j = getnum(&line);
  k = getnum(&line);
  if (j >= MAXPORTS || k >= MAXPORTS)
    Return(APP_PORTTOOLARGE, MAX(j, k)); /* heh */

  if (j == -1 || k == -1)
    Return(APP_PORTNUMEXPECTED, NULL);

  if (info->ports[j] == NOADDRESS ||
      info->ports[k] == NOADDRESS)
    Return(APP_CONNPORTUNDEFINED, i);

  info->fromConnections[i] = info->ports[j];
  info->toConnections[i] = info->ports[k];
  return OK;
}

/*
 * ERRORS:
 *
 * APP_CONNSUNSPEC: FATAL
 * No connections had been specified when classification occurred.
 *
 * APP_CONNUNDEFINED: FATAL
 * Classification of an undefined connection was attempted.
 */
Trap setServers(block, line)
     MasterBlock *block;
     char *line;
{
  srvinfo *info;
  int cnum;

  if (Parse_GetCurrentData(block, "srvinfo",
                           (caddr_t *)&info, sizeof(srvinfo)))
    {
      if (Error_Severity == S_FATAL)
        return CHECK;
      else
        Error_Pop();
    }

  if (!info->connectionsInitialized)
    Return(APP_CONNSUNSPEC, NULL);

  while (1)
    {
      while (isspace(*line)) line++;
      cnum = getnum(&line);
      if (cnum == -1)
	return OK;
      if (cnum > MAXCONNS)
	Return(APP_CONNTOOLARGE, cnum);
      if (info->fromConnections[cnum] == NOADDRESS ||
	  info->toConnections[cnum] == NOADDRESS)
	Return(APP_CONNUNDEFINED, cnum);
      info->serverConns[info->numServers++] = cnum;
      if (info->fromConnections[cnum] == info->toConnections[cnum])
	info->us = info->numServers - 1;
    }
}

/*
 * ERRORS:
 *
 * APP_NORELATIVES: FATAL
 * The requested place in the parse tree could not be found.
 */
Trap newblock(block, parent, sibling)
     MasterBlock *block;
     char *parent, *sibling;
{
  char *t;

  while (1)
    {
      t = Parse_CurrentBlockType(block);
      if (!strcmp(t, sibling))
	{
	  if (Parse_NewBlock(block, sibling, NULL))
	    return CHECK;
	  break;
	}

      if (!strcmp(t, parent))
	{
	  if (Parse_NewSubblock(block, sibling, NULL))
	    return CHECK;
	  break;
	}

      if (Parse_UpBlock(block))
	Return(APP_NORELATIVES, NULL);
    }

  return OK;
}

/*
 * ERRORS:
 *
 * APP_BADSTRING: FATAL
 * A user supplied string had zero length.
 */
Trap setVendor(block, line)
     MasterBlock *block;
     char *line;
{
  License *p;

  if (newblock(block, CONFIG, PACKAGE))
    return CHECK;

  if (Parse_GetCurrentData(block, PACKDATA, (caddr_t *)&p, sizeof(License)))
    {
      if (Error_Severity == S_FATAL)
	return CHECK;
      else
	Error_Pop();
    }

  while (isspace(*line)) line++;
  if (*line == '\0')
    Return(APP_BADSTRING, NULL);

  p->vendor = (char *)malloc(strlen(line) + 1);
  if (p->vendor == NULL)
    Return(MEMORY_ALLOC, strlen(line) + 1);
  strcpy(p->vendor, line);

  return OK;
}

/*
 * ERRORS:
 *
 * APP_PROGNOVEND: FATAL
 * Program was set without corresponding vendor.
 */
Trap setProgram(block, line)
     MasterBlock *block;
     char *line;
{
  License *p;

  if (Parse_GetCurrentData(block, PACKDATA, (caddr_t *)&p, 0))
    Return(APP_PROGNOVEND, NULL);

  while (isspace(*line)) line++;
  if (*line == '\0')
    Return(APP_BADSTRING, NULL);

  p->program = (char *)malloc(strlen(line) + 1);
  if (p->program == NULL)
    Return(MEMORY_ALLOC, strlen(line) + 1);
  strcpy(p->program, line);

  return OK;
}

/*
 * ERRORS:
 *
 * APP_VERSNOVEND: FATAL
 * Version was set without corresponding vendor.
 */
Trap setVersion(block, line)
     MasterBlock *block;
     char *line;
{
  License *p;

  if (Parse_GetCurrentData(block, PACKDATA, (caddr_t *)&p, 0))
    Return(APP_VERSNOVEND, NULL);

  while (isspace(*line)) line++;
  if (*line == '\0')
    Return(APP_BADSTRING, NULL);

  p->version = (char *)malloc(strlen(line) + 1);
  if (p->version == NULL)
    Return(MEMORY_ALLOC, strlen(line) + 1);
  strcpy(p->version, line);

  return OK;
}

/*
 * ERRORS:
 *
 * APP_LICNOPOOL: FATAL
 * Number of licenses was set without corresponding pool.
 *
 * APP_NONUMLIC: FATAL
 * A number of licenses was expected, but not found.
 */
Trap setLicenses(block, line)
     MasterBlock *block;
     char *line;
{
  Pool *p;

  if (Parse_GetCurrentData(block, POOLDATA, (caddr_t *)&p, 0))
    Return(APP_LICNOPOOL, NULL);

  while (isspace(*line)) line++;
  if (*line == '\0')
    Return(APP_BADSTRING, NULL);

  if (isdigit(*line))
    p->licenses = atoi(line);
  else
    Return(APP_NONUMLIC, NULL);

  return OK;
}

Trap newPool(block, line)
     MasterBlock *block;
     char *line;
{
  Pool *p;

  if (newblock(block, PACKAGE, POOL))
    return CHECK;

  if (Parse_GetCurrentData(block, POOLDATA, (caddr_t *)&p, sizeof(Pool)))
    {
      if (Error_Severity == S_FATAL)
	return CHECK;
      else
	Error_Pop();
    }

/*  fprintf(stdout, "%d\n", p->mostStale); */
  return OK;
}
