/*
  bed2sga.c

  Convert BED file to SGA format.
  
  # Arguments:
  #   BED File
  #   Species (e.g. hg19)
  # Options:
  #   Set Path to locate chr_NC_gi file 
  #   (used for chrom name to NCBI id conversion)
  #   Set Feature name 
  #   Center SGA file 
  #   Unoriented SGA file 
  #   Extended SGA file 
  #   Use BED score field to set SGA count field
  #   Input is ENCODE narrowPeak format

  Giovanna Ambrosini, EPFL/ISREC, Giovanna.Ambrosini@epfl.ch

  Copyright (c) 2014 EPFL and Swiss Institute of Bioinformatics.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/
/*
#define DEBUG 
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <getopt.h>
#include <assert.h>
#include <sys/stat.h>
#include "hashtable.h"
#ifdef DEBUG
#include <mcheck.h>
#endif

#include "version.h"

#define BUF_SIZE 8192
#define LINE_SIZE 1024
#define FT_MAX  64
#define CHR_NB 18
#define AC_MAX 18
#define POS_MAX 16
#define SCORE_MAX 12
#define NAME_MAX 128
#define FIELD_MAX 64

typedef struct _options_t {
  char *dbPath;
  char *extField;
  int help;
  int debug;
  int db;
  int useScore;
  int useSigVal;
  int center;
  int unoriented;
  int extend;
  int narrowPeak;
  int regional;
} options_t;

static options_t options;

static hash_table_t *ac_table = NULL;

char *Species = NULL;
char *Feature = NULL;

int check_name_flag = 0;

int extIdx[10];
int extLen = 0;

int
process_ac()
{
  FILE *input;
  int c;
  char buf[LINE_SIZE];
  char *chrFile;
  char chrom[12];
  int cLen;
  int break_flag = 0;
  int read_chr_nc = 0;

  if (options.db) {
      /*cLen = (int)strlen(options.dbPath) + (int)strlen(Species) + 12;*/
      cLen = (int)strlen(options.dbPath) + 12;
      if ((chrFile = (char*)malloc(cLen * sizeof(char))) == NULL) {
        perror("process_ac: malloc");
        exit(1);
      }
      strcpy(chrFile, options.dbPath);
  } else {
      /*cLen = 21 + (int)strlen(Species) + 12;*/
      cLen = 21 + 12;
      if ((chrFile = (char*)malloc(cLen * sizeof(char))) == NULL) {
        perror("process_ac: malloc");
        exit(1);
      }
      strcpy(chrFile, "/home/local/db/genome");
  }
  /* strcat(chrFile, "/"); */
  /*strcat(chrFile, Species); */
  strcat(chrFile, "/chr_NC_gi");

  input = fopen(chrFile, "r");
  if (input == NULL) {
    fprintf(stderr, "Could not open file %s: %s(%d)\n",
            chrFile, strerror(errno), errno);
    return 1;
  }

  do {
      c = fgetc(input);
  } while(c != '\n');

  ac_table = hash_table_new(MODE_COPY);
  while (fgets(buf, LINE_SIZE, input) != NULL) {
    char *s;
    char chr_nb[CHR_NB] = "";
    char ncbi_ac[AC_MAX] = "";
    char field[128];
    int i = 0;
    int nb_len = 0;
    int ac_len = 0;
    s = buf;
    /* Check line */
    /* Get first character: if (char=# and not break_flag) check species */
    /* printf ("chr_NC_gi line : %s\n", s); */
    if (*s == '#') {
      if (!break_flag) {
        /* Get first word */
        s++;
        if ( sscanf(s, "%127[^\t]", field) == 1 ) {
          /* printf ("field: %s Species: %s\n", field, Species); */
          if ((strcmp(field, Species) == 0)) {
            /* printf ("setting flags read_chr_nc break_flag...\n"); */
            read_chr_nc = 1;;
            break_flag = 1;
          } else {
            /* printf ("next line...\n"); */
            continue;
          }
        }
      } else {
        break;
      }
    }
    if (read_chr_nc) {
      /* Chrom NB */
      while (*s != 0 && !isspace(*s)) {
        if (i >= CHR_NB) {
          fprintf(stderr, "Chrom NB too long in %s\n", s);
          fclose(input);
          exit(1);
        }
        chr_nb[i++] = *s++;
      }
      if (i < CHR_NB)
        chr_nb[i] = 0;
      nb_len = i + 1;
      while (isspace(*s))
        s++;
      /* Chromosome NCBI AC */
      i = 0;
      while (*s != 0 && !isspace(*s)) {
        if (i >= AC_MAX) {
          fprintf(stderr, "AC too long \"%s\" \n", s);
          fclose(input);
          exit(1);
        }
        ncbi_ac[i++] = *s++;
      }
      if (i < AC_MAX)
        ncbi_ac[i] = 0;
      ac_len = i + 1;
      strcpy(chrom, "chr");
      strcat(chrom, chr_nb);
      nb_len = (int)strlen(chrom) + 1;
      /* printf("adding key %s (len = %d) value %s (ac) (len = %d) to hash table\n", chrom, nb_len, ncbi_ac, ac_len); */ 
      /* Store both chromosome number to NCBI identifier and NCBI identifier to NCBI identifier keys */
      hash_table_add(ac_table, chrom, (size_t)nb_len, ncbi_ac, (size_t)ac_len);
      if (options.debug) {
        char *ac = hash_table_lookup(ac_table, chrom, (size_t)nb_len);
        fprintf (stderr, " AC Hash table: %s (len = %d) -> %s (len = %d)\n", chrom, nb_len, ac, ac_len);
      }
      hash_table_add(ac_table, ncbi_ac, (size_t)ac_len, ncbi_ac, (size_t)ac_len);
      if (options.debug) {
        char *ac = hash_table_lookup(ac_table, ncbi_ac, (size_t)ac_len);
        fprintf (stderr, " AC Hash table: %s (len = %d) -> %s (len = %d)\n", ncbi_ac, ac_len, ac, ac_len);
      }
    }
  }
  return 0;
}

int
process_bed(FILE *input, char *iFile) 
{
  unsigned long start, end;
  int score;
  char *s, *res, *buf;
  size_t bLen = LINE_SIZE;

  if (options.debug)
    fprintf(stderr, " Processing BED file %s\n", iFile);
  if ((s = malloc(bLen * sizeof(char))) == NULL) {
    perror("process_bed: malloc");
    exit(1);
  }
#ifdef DEBUG
  int c = 1; 
#endif
  while ((res = fgets(s, (int) bLen, input)) != NULL) {
    size_t cLen = strlen(s);
    char bed_fld[12][FIELD_MAX]; 
    char ext_buf[LINE_SIZE];
    char strand = '\0';
    char field[32];
    float signal_val = 0.0;
    unsigned long pos = 0;
    unsigned long pos2 = 0;
    int count = 0;
    int id_len = 0;
    char *ac;
    int i = 0;

    while (cLen + 1 == bLen && s[cLen - 1] != '\n') {
      bLen *= 2;
      if ((s = realloc(s, bLen)) == NULL) {
        perror("process_file: realloc");
        exit(1);
      }
      res = fgets(s + cLen, (int) (bLen - cLen), input);
      cLen = strlen(s);
    }
    if (s[cLen - 1] == '\n')
      s[cLen - 1] = 0;
    else if (s[cLen - 1] == '\n' && s[cLen - 2] == '\r')
      s[cLen - 2] = 0;

    buf = s;
    /* printf ("BED line : %s\n", s); */
    /* Check line */
    /* Get first word/field */
    if ( sscanf(s, "%31[^ ]", field) == 1 ) {
      if ( (strcmp(field, "track") == 0) || (strcmp(field, "browser") == 0) || (strcmp(field, "itemRgb") == 0) )
        continue;
    }
    /* Get BED fields */
    /* Chrom NB */
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= CHR_NB) {
        bed_fld[0][i] = 0;
        fprintf(stderr, "Chrom NB too long \"%s\" Skipping line...\n", bed_fld[0]);
        break;
      }
      bed_fld[0][i++] = *buf++;
    }
    if (i < AC_MAX)
      bed_fld[0][i] = 0;
    else
      continue;
    while (isspace(*buf))
      buf++;
    /* Start Position */
    i = 0;
    while (isdigit(*buf)) {
      if (i >= POS_MAX) {
        fprintf(stderr, "Start position too large \"%s\" \n", buf);
        exit(1);
      }
      bed_fld[1][i++] = *buf++;
    }
    bed_fld[1][i] = 0;
    start = (unsigned long)atoi(bed_fld[1]);
    while (isspace(*buf))
      buf++;
    /* End Position */
    i = 0;
    while (isdigit(*buf)) { 
      if (i >= POS_MAX) {
        fprintf(stderr, "End position too large \"%s\" \n", buf);
        exit(1);
      }
      bed_fld[2][i++] = *buf++;
    }
    bed_fld[2][i] = 0;
    end = (unsigned long)atoi(bed_fld[2]);
    while (isspace(*buf))
      buf++;
    /* Name */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field Name too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[3][i++] = *buf++;
    }
    bed_fld[3][i] = 0;
    while (isspace(*buf))
      buf++;
    /* Score */
    i = 0;
    while (isdigit(*buf) || *buf == '+' || *buf == '-' || *buf == '.') { 
      if (i >= SCORE_MAX) {
        fprintf(stderr, "Score too large \"%s\" \n", buf);
        exit(1);
      }
      bed_fld[4][i++] = *buf++;
    }
    bed_fld[4][i] = 0;
    score = atoi(bed_fld[4]);
    while (isspace(*buf))
      buf++;
    /* Field 6/Strand */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field 6 too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[5][i++] = *buf++;
    }
    bed_fld[5][i] = 0;
    while (isspace(*buf))
      buf++;
   /* Field 7 */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field 7 too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[6][i++] = *buf++;
    }
    bed_fld[6][i] = 0;
    while (isspace(*buf))
      buf++;
   /* Field 8 */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field 8 too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[7][i++] = *buf++;
    }
    bed_fld[7][i] = 0;
    while (isspace(*buf))
      buf++;
   /* Field 9 */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field 9 too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[8][i++] = *buf++;
    }
    bed_fld[8][i] = 0;
    while (isspace(*buf))
      buf++;
   /* Field 10 */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field 10 too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[9][i++] = *buf++;
    }
    bed_fld[9][i] = 0;
    while (isspace(*buf))
      buf++;
   /* Field 11 */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field 11 too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[10][i++] = *buf++;
    }
    bed_fld[10][i] = 0;
    while (isspace(*buf))
      buf++;
   /* Field 12 */
    i = 0;
    while (*buf != 0 && !isspace(*buf)) {
      if (i >= FIELD_MAX) {
        fprintf(stderr, "Field 12 too long \"%s\" \n", buf);
        fclose(input);
        exit(1);
      }
      bed_fld[11][i++] = *buf++;
    }
    bed_fld[11][i] = 0;
    while (isspace(*buf))
      buf++;
#ifdef DEBUG
    printf(" [%d]   Chr nb: %s  Start: %lu  End: %lu  Name: %s  Score: %s  Strand: %c  Field #7 %s  Field #8 %s  Field #9 %s  Field #10 %s  Field #11 %s  Field #12 %s\n", c++, bed_fld[0], start, end, bed_fld[3], score, bed_fld[5], bed_fld[6], bed_fld[7], bed_fld[8], bed_fld[9], bed_fld[10], bed_fld[11]);
#endif
    /* Set SGA Strand field  */
    if (!options.regional) {
      if (bed_fld[5][0] == '+' || bed_fld[5][0] == '-')
        strand = bed_fld[5][0];
      else
        strand = '0';
    }
    /* Set SGA Feature field */
    if (check_name_flag) {
      if (bed_fld[3][0] != '\0')
        strcpy(Feature, bed_fld[3]);
    }
    count = 1;
    if (!options.narrowPeak) {
      /* Set SGA Position field */
      if (options.regional) {  /* Set star (line +) and end positions (line -) */
        pos = start + 1;
        pos2 = end;
      } else {
        if (options.center) {
          pos = (unsigned long)((long double)(start + end)/2 + 0.5); 
          /* Set strand to zero - no strand */
          //if ((strand == '\0') || (strand == '.') || (options.unoriented)) {
          if (options.unoriented) {
            strand = '0';
          }
        } else {
          if (strand == '+') {
            pos = start + 1; 
          } else if (strand == '-') {
            pos = end; 
          } else { /* BED file has no strand: Center position */
            pos = (unsigned long)((long double)(start + end)/2 + 0.5); 
            /* printf ("Start %lu  End %lu  Position %lu\n", start, end, pos); */
            strand = '0';
          }
        }
      }
      /* Set SGA Count field */
      if (options.useScore) { /* Use BED score field to set SGA count field */
        count = score;
      }
    } else { /* ENCODE narrowPeak format  */
      /* Set SGA Position field */
      long peak_offset = (long)atoi(bed_fld[9]); 
      if (peak_offset == -1) {
        pos = (unsigned long)((long double)(start + end)/2 + 0.5); 
        strand = '0';
      } else {
        pos = start + peak_offset + 1;
      }
      /* Set SGA Count field */
      if (options.useSigVal) { /* Use BED signalValue field to set SGA count field */
        signal_val = atof(bed_fld[6]);
        count = (int)(signal_val + 0.5);
      }
    }
    /* Check for extension option */
    if (options.extend) { 
      /* printf (" Extended fileds: %d\n", extLen); */
      /* printf (" concatenating field: %d\n", extIdx[0]); */
      strcpy(ext_buf, bed_fld[extIdx[0]-1]);
      for (i = 1; i < extLen; i++) {
        /* printf (" concatenating field: %d %s\n", extIdx[i], bed_fld[extIdx[i]-1]); */
        strcat(ext_buf, "\t");
        strcat(ext_buf, bed_fld[extIdx[i]-1]);
      }
      /* printf(" Extended fields: %s\n", ext_buf); */
      if (options.debug)
        fprintf(stderr, " Extended fields: %s\n", ext_buf);
    }
    if (Species != NULL) {
      id_len = (int)strlen(bed_fld[0]) + 1;
      ac = hash_table_lookup(ac_table, bed_fld[0], (size_t)id_len);
      if (ac == NULL) 
        continue;
    } else {
      ac = malloc (strlen(bed_fld[0]) + 1);
      strcpy(ac, bed_fld[0]);
    }
    /* Print out SGA line(s) */
    if (options.regional) { /* 2-line SGA format  */
      if (options.extend) { 
        printf("%s\t%s\t%lu\t+\t%d\t%s\n", ac, Feature, pos, count, ext_buf);
        printf("%s\t%s\t%lu\t-\t%d\t%s\n", ac, Feature, pos2, count, ext_buf);
      } else {
        printf("%s\t%s\t%lu\t+\t%d\n", ac, Feature, pos, count);
        printf("%s\t%s\t%lu\t-\t%d\n", ac, Feature, pos, count);
      }
    } else {
      if (options.extend) { 
        printf("%s\t%s\t%lu\t%c\t%d\t%s\n", ac, Feature, pos, strand, count, ext_buf);
      } else {
        printf("%s\t%s\t%lu\t%c\t%d\n", ac, Feature, pos, strand, count);
      }
    }
  } /* End of While */
  if (input != stdin) {
    fclose(input);
  }
  return 0;
}

char** str_split(char* a_str, const char a_delim)
{
    char** result = 0;
    size_t count = 0;
    char* tmp = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;
    /* Count how many elements will be extracted. */
    while (*tmp) {
        if (a_delim == *tmp) {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }
    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);
    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;
    result = malloc(sizeof(char*) *count);

    if (result) {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token) {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }
    return result;
}

int
main(int argc, char *argv[])
{
  char** tokens;
#ifdef DEBUG
  mcheck(NULL);
  mtrace();
#endif
  FILE *input;
  int i = 0;
  int usage = 0;

  static struct option long_options[] =
    {
      /* These options may or may not set a flag.
         We distinguish them by their indices. */
      {"debug",      no_argument,       0, 'd'},
      {"help",       no_argument,       0, 'h'},
      {"db",         required_argument, 0, 'i'},
      {"feature",    required_argument, 0, 'f'},
      {"species",    required_argument, 0, 's'},
      {"extend",     required_argument, 0, 'e'},
      {"center",     no_argument,       0, 'c'},
      {"unoriented", no_argument,       0, 'u'},
      {"regional",   no_argument,       0, 'r'},
      /* These options only set a flag. */
      {"useScore",   no_argument,       &options.useScore, 1},
      {"useSigVal",  no_argument,       &options.useSigVal, 1},
      {"narrowPeak", no_argument,       &options.narrowPeak, 1},
      {0, 0, 0, 0}
    };

  int option_index = 0;

  while (1) {
    int c = getopt_long(argc, argv, "dhf:i:s:cure:", long_options, &option_index);
    if (c == -1)
      break;
    switch (c) {
      case 'd':
        options.debug = 1;
        break;
      case 'h':
        options.help = 1;
        break;
      case 'i':
        options.dbPath = optarg;
        options.db = 1;
        break;
      case 'f':
        Feature = optarg;
	break;
      case 's':
        Species = optarg;
        break;
      case 'c':
        options.center = 1;
        break;
      case 'e':
        options.extField = optarg;
        options.extend = 1;
        break;
      case 'u':
        options.unoriented = 1;
        break;
      case 'r':
        options.regional = 1;
        break;
      case 0:
        /* If this option set a flag, do nothing else now. */
        if (long_options[option_index].flag != 0)
          break;
      default:
        printf ("?? getopt returned character code 0%o ??\n", c);
        usage = 1;
    }
  }
  if (optind > argc || options.help == 1 || usage) {
    fprintf(stderr, "Usage: %s [options] [-s <s_assembly (e.g. hg19)>] [<] <BED file|stdin>\n"
             "      - version %s\n"
             "      where options are:\n"
	     "  \t\t -d|--debug                Produce Debug information\n"
	     "  \t\t -h|--help                 Show this Help text\n"
             "  \t\t -i|--db <path>            Use <path> to locate the assembly-specific chr_NC_gi file\n" 
             "  \t\t                           [default is: $HOME/db/genome]\n"
             "  \t\t -f|--feature <ft>         Set Feature name <ft>\n"
             "  \t\t -s|--species <spec>       Assembly <spec> (i.e hg19)\n"
             "  \t\t -c|--center               Generate a Centered SGA file\n"
             "  \t\t -u|--unoriented           Generate an unoriented SGA file\n"
             "  \t\t -r|--regional             Generate a 2-line[+/-] SGA file representing BED regions\n"
             "  \t\t                           (e.g. RepeatMasker regions)\n"
             "  \t\t -e|--extend <f1,f2,...>   Produce an extended SGA file with additional fields specified\n"
             "  \t\t                           by a comma-separated list of BED column numbers (from 1 to n)\n"
             "  \t\t --useScore                Use the BED 'score' field (#5) to set the SGA 'count' field\n"
             "  \t\t --useSigVal               Use the BED 'Signal Value' field (#7) to set the SGA 'count' field\n"
             "  \t\t                           [This option is only valid for ENCODE narrowPeak]\n"
             "  \t\t --narrowPeak              Use this option for ENCODE narrowPeak format\n"
             "  \t\t                           [Options --useScore, -c, and -u are ignored]\n"
	     "\n\tConvert BED format into SGA format.\n\n",
	     argv[0], VERSION);
      return 1;
  }
  if (argc > optind) {
      if(!strcmp(argv[optind],"-")) {
          input = stdin;
      } else {
          input = fopen(argv[optind], "r");
          if (NULL == input) {
              fprintf(stderr, "Unable to open '%s': %s(%d)\n",
                  argv[optind], strerror(errno), errno);
             exit(EXIT_FAILURE);
          }
          if (options.debug)
             fprintf(stderr, "Processing file %s\n", argv[optind]);
      }
  } else {
      input = stdin;
  }
  if (Feature == NULL) {
    if ((Feature = malloc(6 * sizeof(char))) == NULL) {
      perror("main: malloc Feature");
      exit(1);
    }
    strcpy(Feature, "chIP");
    check_name_flag = 1;
  } else {
    char *s = Feature;
    i = 0;
    while (*s != 0  && !isspace(*s)) {
      if (i >= FT_MAX) {
        fprintf(stderr, "Feature Name too long \"%s\" \n", Feature);
        return 1;
      }
      s++;
    }
  }
  if (options.narrowPeak) {
    options.center = 0;
    options.unoriented = 0;
    options.useScore = 0;
  } else {
    options.useSigVal = 0;
  }
  if (options.regional) {
    options.center = 0;
    options.unoriented = 0;
  }
  if (options.extend) {
    tokens = str_split(options.extField, ',');
    if (tokens) {
      for (i = 0; *(tokens + i); i++) {
        extIdx[i] =  atoi(*(tokens + i));
        free(*(tokens + i));
      }
      extLen = i;
      if (options.debug) {
        fprintf(stderr, " Number of TOKENS: %d\n", extLen);
      }
      free(tokens);
    }
  }
  if (options.debug) {
    fprintf(stderr, " Arguments:\n");
    fprintf(stderr, " Feature : %s\n", Feature);
    if (Species != NULL)
      fprintf(stderr, " Species : %s\n", Species);
    fprintf(stderr, " Centered SGA [on/off]: %d\n", options.center);
    fprintf(stderr, " Unoriented SGA [on/off]: %d\n", options.unoriented);
    fprintf(stderr, " Extended SGA [on/off]: %d. BED fields:", options.extend);
    for (i = 0; i < extLen; i++) {
      if (i == (extLen - 1)) {
        fprintf(stderr, " %d", extIdx[i]);
      } else { 
        fprintf(stderr, " %d,", extIdx[i]);
      }
    }
    fprintf(stderr, "\n");
    fprintf(stderr, " Use Score [on/off]: %d\n", options.useScore);
    fprintf(stderr, " NarrowPeak format [on/off]: %d\n", options.narrowPeak);
    fprintf(stderr, " Use Signal Value [on/off]: %d\n", options.useSigVal);
  }
  if (Species != NULL) {
    if (process_ac() == 0) {
      if (options.debug)
        fprintf(stderr, " HASH Table for chromosome access identifier initialized\n");
    } else {
      return 1;
    }
  }
  if (process_bed(input, argv[optind++]) != 0) {
    return 1;
  }
  return 0;
}
