#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <vlcutils/error.h>
#include "index.h"
#include "matchtable.h"
#include "dnalib.h"
#include "interactive.h"
#include "mapsearch.h"

static void usage(void);
static void opt0(int argc, char *argv[]);
static void opt1(int argc, char *argv[]);
static void opt2(int argc, char *argv[]);
static void opt3(int argc, char *argv[]);
static void opt4(int argc, char *argv[]);
static void opt5(int argc, char *argv[]);

int main(int argc, char **argv)
{
  int opt;

  set_program_name(argv[0]);

  if (argc < 2)
       usage();

  opt = atoi(argv[1]);
  switch (opt) {
  case 0: 
       opt0(argc, argv);
       break;
  case 1: 
       opt1(argc, argv);
       break;
  case 2: 
       opt2(argc, argv);
       break;
  case 3: 
       opt3(argc, argv);
       break;
  case 4: 
       opt4(argc, argv);
       break;
  case 5: 
       opt5(argc, argv);
       break;
  default:
       fprintf(stderr, "%s: Invalid option: %d\n", program_name, opt);
       usage();
  }
  return(0);
}

static void usage(void)
{
     assert(program_name);
     printf("Usage: %s opt\n", program_name);
     printf("opt = 0 => (* * input_file) :\n");
     printf("            Display statistics about the input file\n");
     printf("opt = 1 => (* * input_file output_file window_size string_per_page) :\n");
     printf("            Create index structure using a sliding window\n");
     printf("opt = 2 => (* * index_file query_file output_file error_rate) :\n");
     printf("            Create Match Table\n");
     printf("opt = 3 => (* * matrix_file) :\n");
     printf("            Read Match Table\n");
     printf("opt = 4 => (* * matrix_file buffer_size) :\n");
     printf("            Partition Match Table\n");
     printf("opt = 5 => (* * input_file index_file query_file NN) :\n");
     printf("            Order the MBRs for interactive search\n");
     exit(1);
}

static void opt0(int argc, char *argv[])
{
     const char *inputfname;

     if (argc < 3)
	  usage();
     inputfname = argv[2];
     statistics(inputfname);
}

static void opt1(int argc, char *argv[])
{
     const char *input_filename, *output_filename;
     FILE *input, *output;
     int windowSize, boxCapacity;

     if (argc < 6)
	  usage();
     input_filename = argv[2];
     output_filename = argv[3];
     windowSize = atoi(argv[4]);
     boxCapacity = atoi(argv[5]);

     input = fopen(input_filename, "r");
     if (!input)
       fatal_perror("%s", input_filename);

     output = fopen(output_filename, "w");
     if (!output)
       fatal_perror("%s", output_filename);

     create_index_file(input, output, windowSize, boxCapacity);
}

static void opt2(int argc, char *argv[])
{
     const char *index_filename, *query_filename, *output_filename;
     double error_rate;
     FILE *input_stream, *output_stream;
     struct index *index;
     struct matchtable *matchtable;

     if (argc < 6)
	  usage();
     index_filename = argv[2];
     query_filename = argv[3];
     output_filename = argv[4];
     error_rate = atof(argv[5]);

     if (error_rate < 0 || error_rate > 1)
       fatal_error("Error rate should be between 0 and 1.");

     output_stream = fopen(output_filename, "w");
     if (!output_stream)
       fatal_perror("%s: fopen", output_filename);

     index = read_index(index_filename);

     input_stream = fopen(query_filename, "r");
     if (!input_stream)
       fatal_perror("%s", query_filename);

     matchtable = compute_matchtable(input_stream, index, error_rate);
     fprint_matchtable(output_stream, matchtable);
     fclose(output_stream);
     free_matchtable(matchtable);
}

static void opt3(int argc, char *argv[])
{
     const char *matrixfname;

     if (argc < 3)
	  usage();
     matrixfname = argv[2];
     readMatrix(matrixfname);
}

static void opt4(int argc, char *argv[])
{
     const char *matrixfname;
     int bufferSize;

     if (argc < 4)
	  usage();
     matrixfname = argv[2];
     bufferSize = atoi(argv[3]);
     mapSearch(matrixfname, bufferSize);
}

static void opt5(int argc, char *argv[])
{
     const char *indexfname, *queryfname;
     int NN;

     if (argc < 5)
	  usage();
     indexfname = argv[2];
     queryfname = argv[3];
     NN = atoi(argv[4]);
     interactiveOrder(indexfname, queryfname, NN);
}
