#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h>
#include "r5000/r5000.h"

enum {
  TOGGLE_POWER,
  CHANGE_CHANNEL,
  READ_STREAM,
  OPEN_CLOSE,
  SCAN_DEVICES,
  MAX_CMD,
};
char cmd_names[][20] = {
  {"TOGGLE_POWER"},
  {"CHANGE_CHANNEL"},
  {"READ_STREAM"},
  {"OPEN_CLOSE"},
  {"SCAN_DEVICES"},
};

char stb_names[][20] = {
  {"vip"},
  {"directv"},
  {"hdd"},
  {"dsr"},
  {0},
};

extern char strmfile[255];
void help(char *cmdline) {
  int i;
  printf("%s <-t type> <--m command> [--c channel] [--s serial] [-h]\n", cmdline);
  printf("\t-t/--type type     : set STB type to type.  'type' can be either\n");
  printf("\t                     a numerical value or string.  Valid types are:\n");
  for(i = 0; stb_names[i][0] != 0; i++) {
    printf("\t\t%d: %s\n", i, stb_names[i]);
  }
  printf("\t-m/--cmd command   : set command to execute.  'command' can be either\n");
  printf("\t                     a numerical value or string.  Valid commands are:\n");
  for(i = 0; i < MAX_CMD; i++) {
    printf("\t\t%d: %s\n", i, cmd_names[i]);
  }
  printf("\t-c/--channel       : set channel to read (this does NOT tune\n");
  printf("\t-s/--serial serial : set serial number\n");
  printf("\t-h/--help          : show this help message\n");
  exit(0);
}

static unsigned char buffer[1000189];
static unsigned char *ptr = buffer;
unsigned int r5000_device_tspacket_handler(unsigned char *tspacket, int len, void *callback_data)
{
    int fd = *(int *) callback_data;
    if (len <= 0)
      return 0;
    if(memcpy(ptr, tspacket, len));
    ptr+=len;
    if(ptr-buffer > 1000000) {
      write(fd, buffer, ptr-buffer);
      ptr = buffer;
    }
    return 1;
}

int main(int argc, char *argv[])
{
  r5kdev_t *usbdev;
  int glblfd, i, j;
  unsigned char buf[0x80];
  int stb = -1;
  int cmd = -1;
  int channel = -1;
  const char *serial = NULL;
  struct option long_options[] = {
    {"type", required_argument, NULL, 't'},
    {"cmd", required_argument, NULL, 'm'},
    {"channel", required_argument, NULL, 'c'},
    {"serial", required_argument, NULL, 's'},
    {"dbgfile", required_argument, NULL, 'D'},
    {"help", no_argument , NULL, 'h'},
    {0, 0, 0, 0}
  };
  while (1) {
    char c;
    c = getopt_long (argc, argv, 
                     "t:m:c:s:hD:",
                     long_options, NULL);
    if(c == EOF)
      break;
    switch(c) {
      case 't':
      {
        char *ptr;
        int i;
        stb = strtol(optarg, &ptr, 10);
        if(ptr == optarg) {
          stb = -1;
          for(i = 0; stb_names[i][0] != 0; i++) {
            if(strncasecmp(optarg, stb_names[i], strlen(stb_names[i])) == 0) {
              stb = i;
              break;
            }
          }
          if(stb == -1) {
            fprintf(stderr, "Unknown STB type: %s\n", optarg);
            exit(-1);
          }
        } else if(stb < 0 || stb >= R5K_STB_MAX) {
          fprintf(stderr, "Illegal STB type: %d\n", stb);
          exit(-1);
        }
        break;
      }
      case 'm':
      {
        char *ptr;
        int i;
        cmd = strtol(optarg, &ptr, 10);
        if(ptr == optarg) {
          cmd = -1;
          for(i = 0; i < MAX_CMD; i++) {
            if(strncasecmp(optarg, cmd_names[i], strlen(cmd_names[i])) == 0) {
              cmd = i;
              break;
            }
          }
          if(cmd == -1) {
            fprintf(stderr, "Unknown command: %d\n", optarg);
            exit(-1);
          }
        } else if(cmd < 0 || cmd >= MAX_CMD) {
          fprintf(stderr, "Illegal command: %d\n", cmd);
          exit(-1);
        }
        break;
      }
      case 'c':
      {
        char *ptr;
        channel = strtol(optarg, &ptr, 0);
        if(optarg == ptr) {
          fprintf(stderr, "Couldn't parse channel '%s'\n", optarg);
        }
        break;
      }
      case 's':
        serial = optarg;
        break;
      case 'h':
        help(argv[0]);
        break;
      case 'D':
        #ifdef R5K_DEBUG
          strncpy(strmfile, optarg, 255);
        #else
          fprintf(stderr, "--dbgfile only supported in debug mode.\nMake sure you know what you are doing!\n");
          exit(-1);
        #endif
    }
  }
  if(cmd == -1 || stb == -1) {
    fprintf(stderr, "Must specify --cmd and --stb\n");
    exit(-1);
  }
  if(cmd == SCAN_DEVICES) {
    r5kenum_t devs;
    printf("Scanning for R5000 devices\n");
    r5000_find_stbs(&devs);
    for(i=0; i < devs.count; i++) {
      printf("Found: %s\n", devs.serial[i]);
    }
    goto end;
  }
  glblfd=open("raw.ts", O_WRONLY | O_TRUNC | O_CREAT, 0666);
  usbdev = r5000_open(stb, r5000_device_tspacket_handler, &glblfd, serial);
  if(! usbdev) {
    fprintf(stderr, "R5000 device could not be found/opened\n");
    exit(-1);
  }
  if(cmd == TOGGLE_POWER) {
    printf("Toggling On/Off\n");
    r5000_toggle_on_off(usbdev);
  }
  if(cmd == CHANGE_CHANNEL) {
    printf("Setting channel 108\n");
    r5000_change_channel(usbdev, 108);
  }
  if(cmd == OPEN_CLOSE) {
    int on_off;
    printf("Doing open/close\n");
    on_off = r5000_get_power_state(usbdev);
    printf("State1: %d\n", on_off);
    r5000_close(usbdev);
    printf("Closed\n");
    sleep(2);
    usbdev = r5000_open(stb, r5000_device_tspacket_handler, &glblfd, serial);
    printf("ReOpened\n");
    on_off = r5000_get_power_state(usbdev);
    printf("State2: %d\n", on_off);
  }
  if(cmd == READ_STREAM) {
    printf("Reading stream\n");
    r5000_start_stream(usbdev);
    time_t t = time(NULL);
    while (time(NULL) - t < 10)
    {
      // This will timeout after 1ms regardless of data availability
      //usleep(10000);
      r5000_loop_iterate(usbdev, 10);
    }
    r5000_stop_stream(usbdev);
  }
end:
  r5000_close(usbdev);
  if(ptr != buffer)
    write(glblfd, buffer, ptr-buffer);
  close(glblfd);
}

