#include "macros.h"
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <errno.h>

#include "interact.h"

/* modifies line as a side effect.
   returns 0 if command was okay or parse error,
   returns nonzero if user requested to quit */
static int find_and_run_command(void* state, struct command* commands, char* line) {
  char* cmd;
  do cmd = strsep(&line," "); while (cmd && *cmd == '\0');
  if (!cmd)
    return 0;
  for(struct command* c = commands; c->name != NULL; c++) {
    if (strcasecmp(cmd,c->name) == 0) {
      return c->action(c->actiondata,state,line);
    }
  }
  printf("No such command '%s'. Type 'help' for a list of commands.\n",cmd);
  return 0;
}


void interact(void* state, struct command* commands, const char* prompt) {
  while (1) {
    char* line = readline(prompt);
    if (!line) {
      fprintf(stderr,"readline error, exiting.\n");
      return;
    }
    add_history(line);
    int result = find_and_run_command(state,commands,line);
    if (result != 0)
      return;
  }
}

void removenewline(char* line) {
  for(int i=0;i<4095 && line[i] != '\0'; i++) {
    if (line[i] == '\n') {
      line[i] = '\0';
      return;
    }
  }
}

void runscript(void* state, struct command* commands, FILE* f) {
  char line[4096];
  while(fgets(line,4096,f)) {
    removenewline(line);
    if (line[0] != '#' && line[0] != '\0') {
      find_and_run_command(state,commands,line);
    }
  }
}

int cmd_help(void* actiondata, void* state, char* line) {
  CAST(struct command*,commands,actiondata);
  printf("Availible commands: \n");
  for(struct command* c = commands; c->name != NULL; c++) {
    printf("%10s - %s\n", c->name, c->desc);
  }
  return 0;
}

int cmd_exit(void* actiondata, void* state, char* line) {
  return 1;
}

int cmd_callwithfloat(void* actiondata, void* state, char* line) {
  char * endptr = NULL;
  float value = strtof(line,&endptr);
  if (endptr == line || endptr == NULL) {
    printf("Error, was expecting a floating point number\n");
  }
  else if (errno == ERANGE) {
    printf("Error, number out of range\n");
  }
  else {
    void (*fn)(void*,float) = (void(*)(void*,float))actiondata;
    fn(state,value);
  }
  return 0;
}

