# include "pcontrol.h"

Stack *HostPool_Idle;
Stack *HostPool_Busy;
Stack *HostPool_Done;
Stack *HostPool_Down;
Stack *HostPool_Off;

void InitHostStacks () {
  HostPool_Idle = InitStack ();
  HostPool_Busy = InitStack ();
  HostPool_Done = InitStack ();
  HostPool_Down = InitStack ();
  HostPool_Off  = InitStack ();
}

char *GetHostStackName (int StackID) {
  switch (StackID) {
    case PCONTROL_HOST_IDLE: return ("IDLE");
    case PCONTROL_HOST_DOWN: return ("DOWN");
    case PCONTROL_HOST_DONE: return ("DONE");
    case PCONTROL_HOST_BUSY: return ("BUSY");
    case PCONTROL_HOST_OFF:  return ("OFF");
  }
  gprint (GP_ERR, "error: unknown host stack : programming error\n");
  pcontrol_exit (1);
}

Stack *GetHostStack (int StackID) {
  switch (StackID) {
    case PCONTROL_HOST_IDLE: return (HostPool_Idle);
    case PCONTROL_HOST_DOWN: return (HostPool_Down);
    case PCONTROL_HOST_DONE: return (HostPool_Done);
    case PCONTROL_HOST_BUSY: return (HostPool_Busy);
    case PCONTROL_HOST_OFF:  return (HostPool_Off);
  }
  gprint (GP_ERR, "error: unknown host stack : programming error\n");
  pcontrol_exit (1);
}

Stack *GetHostStackByName (char *name) {
  if (!strcasecmp (name, "idle")) return (HostPool_Idle);
  if (!strcasecmp (name, "down")) return (HostPool_Down);
  if (!strcasecmp (name, "done")) return (HostPool_Done);
  if (!strcasecmp (name, "busy")) return (HostPool_Busy);
  if (!strcasecmp (name, "off"))  return (HostPool_Off);
  return (NULL);
}

/* add host to position in stack */
int PutHost (Host *host, int StackID, int where) {

  int stat;
  Stack *stack;

  stack = GetHostStack (StackID);
  if (stack == NULL) return (FALSE);

  host[0].stack = StackID;
  stat = PushStack (stack, where, host, host[0].HostID, host[0].hostname);
  // XXX need to handle the error conditions, or we drop the host & leak memory
  return (stat);
}
  
/* find the host by ID in the defined host stacks */
Host *PullHostByID (IDtype HostID, int *StackID) {

  Host *host;

  *StackID = PCONTROL_HOST_IDLE;
  host = PullHostFromStackByID (*StackID, HostID);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_DOWN;
  host = PullHostFromStackByID (*StackID, HostID);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_DONE;
  host = PullHostFromStackByID (*StackID, HostID);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_BUSY;
  host = PullHostFromStackByID (*StackID, HostID);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_OFF;
  host = PullHostFromStackByID (*StackID, HostID);
  if (host != NULL) return (host);

  *StackID = -1;
  return (NULL);
}

/* find the host by ID in the defined host stacks */
Host *PullHostByName (char *name, int *StackID) {

  Host *host;

  *StackID = PCONTROL_HOST_IDLE;
  host = PullHostFromStackByName (*StackID, name);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_DOWN;
  host = PullHostFromStackByName (*StackID, name);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_DONE;
  host = PullHostFromStackByName (*StackID, name);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_BUSY;
  host = PullHostFromStackByName (*StackID, name);
  if (host != NULL) return (host);

  *StackID = PCONTROL_HOST_OFF;
  host = PullHostFromStackByName (*StackID, name);
  if (host != NULL) return (host);

  *StackID = -1;
  return (NULL);
}

Host *PullHostFromStackByID (int StackID, IDtype ID) {

  Host *host;
  Stack *stack;

  stack = GetHostStack (StackID);
  if (stack == NULL) return (NULL);

  host = PullStackByID (stack, ID);
  return (host);
}

Host *PullHostFromStackByName (int StackID, char *name) {

  Host *host;
  Stack *stack;

  stack = GetHostStack (StackID);
  if (stack == NULL) return (NULL);

  host = PullStackByName (stack, name);
  return (host);
}

IDtype AddHost (char *hostname) {

  Host *host;

  ALLOCATE (host, Host, 1);

  host[0].hostname  = strcreate (hostname);
  host[0].stdin_fd  = 0;
  host[0].stdout_fd = 0;
  host[0].stderr_fd = 0;
  host[0].HostID    = NextHostID();

  host[0].lasttry.tv_sec = 0;
  host[0].lasttry.tv_usec = 0;
  host[0].nexttry.tv_sec = 0;
  host[0].nexttry.tv_usec = 0;

  host[0].markoff  = FALSE;
  host[0].job      = NULL;
  PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
  return (host[0].HostID);
}

void DelHost (Host *host) {
  FREE (host[0].hostname);
  FREE (host[0].job);
  FREE (host);
}
