#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <sprog.h>

void sprog_process(const struct sprog_family *fam, void *arg, const struct sprog_data *d, int mode);

void sprog_error(const char *text, ...) {
  va_list l;
  va_start(l, text);
  vfprintf(stderr, text, l);
  va_end(l);
}

void sprog_info(const char *text, ...) {
  va_list l;
  va_start(l, text);
  vprintf(text, l);
  va_end(l);
}

void sprog_sleep(int msec) {
  usleep(msec * 1000);
}

void sprog_communicate(const struct sprog_family *fam, const struct sprog_data *d, int mode, const char *port, int baud) {
  void *arg;
  struct serial_device dev;
  
  serial_open(&dev, port, baud);
  arg = fam->setup(&dev);
  sprog_process(fam, arg, d, mode);
}

int sprog_waitdata(struct serial_device *port, int timeout) {
  fd_set read_set;
  struct timeval tval;
  FD_ZERO(&read_set);
  FD_SET(port->fd, &read_set);
  tval.tv_sec = timeout/1000;
  tval.tv_usec = (timeout%1000)*1000;
  if(select(port->fd+1, &read_set, NULL, NULL, &tval)!=1)
    return 0;
  return 1;
}

void sprog_process(const struct sprog_family *fam, void *arg, const struct sprog_data *d, int mode) {
  fam->init(arg);
  if(mode==1)
    fam->exec(arg, d);
  else if(mode==2)
    fam->write(arg, d);
}

void sprog_load(struct sprog_data *d, const char *path) {
  char buf[4096];
  int fd;
  int n;
  
  fd = open(path, O_RDONLY);
  if(fd<0) {
    sprog_error("Unable to open '%s': %s\n", path, strerror(errno));
    return;
  }
  
  d->size = 0; 

  while((n = read(fd, buf, sizeof(buf)))>0)
    sprog_append_data(d, buf, n);
    
  if(n<0) {
    sprog_error("Error while reading from '%s': %s\n", path, strerror(errno));
    free(d->data);
    d->size = 0;
    d->data = NULL;
    return;
  }
}

void sprog_append_data(struct sprog_data *d, const char *data, int len) {
  int i;

  if(!d->data)
    d->size = 0;
  
  sprog_alloc_data(d, d->size+len);
  
  for(i=0; i<len; i++)
    d->data[i+d->size] = data[i];

  d->size += len;
}

void sprog_alloc_data(struct sprog_data *d, int len) {
  int alloc;
  alloc = d->alloc;
  
  if(!d->data) {
    alloc = 4096;
    d->size = 0;
  }
  
  while(len+128>alloc)
    alloc *= 2;
  
  if(d->data) {
    if(d->alloc!=alloc)
      d->data = realloc(d->data, alloc);
  } else
    d->data = malloc(alloc);
  
  d->alloc = alloc;
}

void sprog_progress(int progress, int total) {
  char buf[80];
  int i;
  int w;
  int p;
  
  if(progress==total) {
    p = 100;
    w = 70;
  } else {
    p = (progress*100)/total;
    w = (progress*70)/total;
  }
  
  for(i=0; i<70; i++) {
    if(i<w)
      buf[i] = ':';
    else
      buf[i] = ' ';
  }
  buf[i] = 0;
  
  sprog_info("\r[%s] %3d%%", buf, p);
  fflush(stdout);
}