# include "opihi.h"

// if the user has installed the libedit version of readline, we need to modify a couple symbols:
# ifndef RL_READLINE_VERSION
# define rl_completion_matches(A,B) completion_matches(A,B)
# endif

static Command  *commands;
static int      Ncommands;
static int      NCOMMANDS;

void InitCommands () {
  NCOMMANDS = 20;
  Ncommands = 0;
  ALLOCATE (commands, Command, NCOMMANDS);
}

void AddCommand (Command *new) {
  
  commands[Ncommands] = *new;
  Ncommands ++;
  if (Ncommands == NCOMMANDS) {
    NCOMMANDS += 20;
    REALLOCATE (commands, Command, NCOMMANDS);
  }
}

int DeleteCommand (Command *command) {

  int i, Nc;

  Nc = -1;
  for (i = 0; i < Ncommands; i++) {
    if (command == &commands[i]) {
      Nc = i;
      break;
    }
  }
  if (Nc == -1) {
    gprint (GP_ERR, "programming error: command not found\n");
    return (FALSE);
  }

  free (commands[Nc].name);
  for (i = Nc + 1; i < Ncommands; i++)
    commands[i - 1] = commands[i];
  Ncommands --;
  REALLOCATE (commands, Command, Ncommands);
  return (TRUE);
}

/* return command which unambiguously matches name */
Command *MatchCommand (char *name, int VERBOSE, int EXACT) {

  int i, match[10], Nmatch;

  /* try for an exact match first */
  for (i = 0; i < Ncommands; i++) {
    if (!strcmp (commands[i].name, name)) {
      return (&commands[i]);
    }
  }
  if (EXACT) {
    if (VERBOSE) gprint (GP_ERR, "no exact match to %s\n", name);
    return (NULL);
  }

  /* not found as complete command, try partial */
  Nmatch = 0;
  for (i = 0; (Nmatch < 10) && (i < Ncommands); i++) {
    if (!strncmp (commands[i].name, name, strlen(name))) {  /* found a command */
      match[Nmatch] = i;
      Nmatch ++;
    }
  }
  if (Nmatch == 1) return (&commands[match[0]]);

  if (Nmatch > 1) {
    if (VERBOSE) {
      gprint (GP_ERR, "ambiguous command: %s ( ", name);
      for (i = 0; i < Nmatch; i++) {
	gprint (GP_ERR, "%s ", commands[match[i]].name);
      }
      gprint (GP_ERR, ")\n");
    }
    return (NULL);
  }
  if (VERBOSE) gprint (GP_ERR, "%s: Command not found.\n", name);
  return (NULL);
}  

/* generate a command completion list for readline */
/**** these probably do not interact well with OHANA memory!!! ****/
char *command_generator (const char *text, int state) {

  /* i must be remembered from call to call */
  static int i, len;

  /* On first call, state is set to 0: initial the state */
  if (!state) {
    i = -1;  
    len = strlen (text);
  }

  /* Return the next partial match from the command list */
  for (i++; i < Ncommands; i++) {
    if (!len) 
      return (strcreate(commands[i].name));
    if (!strncmp (commands[i].name, text, len)) {
      return (strcreate(commands[i].name));
    }
  }

  /* If no names matched, then return NULL. */
  return ((char *)NULL);
}

/* tell readline to use out command_generator rather than basic completion */
char **command_completer (const char *text, int start, int end) {
  
  char **matches;

  matches = (char **) NULL;
  
  if (start == 0) {
    matches = rl_completion_matches (text, command_generator);
  }

  return (matches);
}

void print_commands (FILE *f) {

  int i, *seq;

  ALLOCATE (seq, int, Ncommands);
  sort_commands (seq);
  for (i = 0; i < Ncommands; i++) {
    fprintf (f, "%-25s -- %s\n", commands[seq[i]].name, commands[seq[i]].help);
  }
  free (seq);

  return;
}

void sort_commands (int *seq) {

  int l,j,ir,i, N;
  int temp;
  
  N = Ncommands;
  for (i = 0; i < N; i++) 
    seq[i] = i;
  
  l = N >> 1;
  ir = N - 1;
  for (;;) {
    if (l > 0) {
      temp = seq[--l];
    }
    else {
      temp = seq[ir];
      seq[ir] = seq[0];
      if (--ir == 0) {
        seq[0] = temp;
        return;
      }
    }
    i = l;
    j = (l << 1) + 1;
    while (j <= ir) {
      if (j < ir && (strcmp (commands[seq[j]].name, commands[seq[j+1]].name) < 0)) ++j;
      if (strcmp (commands[temp].name, commands[seq[j]].name) < 0) {
        seq[i]=seq[j];
        j += (i=j) + 1;
      }
      else j = ir + 1;
    }
    seq[i] = temp;
  }
}
