/*
  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 SIB 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 64
#define AC_MAX 64
#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;
char *progname = NULL;

void show_help(void) {
    fprintf(stderr,
            "Usage: %s [options] [-a <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 current working directory]\n"
            "  \t\t -f|--feature <ft>         Set Feature name <ft>\n"
            "  \t\t -a|--species <spec>       Assembly <spec> (i.e hg19)\n"
            "  \t\t -s                        Deprecated, please use -a.\n"
            "  \t\t -C|--center               Generate a Centered SGA file\n"
            "  \t\t -c                        Deprecated, please use -C|--center\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 -x|--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", progname,
            VERSION);
}

/* String match function  */
int match(char text[], char pattern[]) {
    int c, d, e, text_length, pattern_length, position = -1;

    text_length = strlen(text);
    pattern_length = strlen(pattern);

    if (pattern_length > text_length) {
        return -1;
    }

    for (c = 0; c <= text_length - pattern_length; c++) {
        position = e = c;

        for (d = 0; d < pattern_length; d++) {
            if (pattern[d] == text[e]) {
                e++;
            } else {
                break;
            }
        }
        if (d == pattern_length) {
            return position;
        }
    }

    return -1;
}


int process_ac(void) {
    FILE *input;
    //int c;
    char buf[LINE_SIZE];
    char *chrFile;
    char chrom[CHR_NB];
    int cLen;
    int break_flag = 0;
    int read_chr_nc = 0;
    int pmatch = -1;

    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, ".");
    }
    /* strcat(chrFile, "/"); */
    /*strcat(chrFile, Species); */
    strcat(chrFile, "/chr_NC_gi");

    input = fopen(chrFile, "r");
    if (NULL == input) {
        if (ENOENT == errno) {
            fprintf(stderr,
                    // ERROR: Could not open ./chr_NC_gi - no such file or directory. See option -i.
                    "ERROR: Could not open %s - %s. See option -i.\n\n",
                    chrFile, strerror(errno));
            show_help();

        } else {
            fprintf(stderr, "Could not open `%s`: %s(%d)\n",
                    chrFile, strerror(errno), errno);
            show_help();
        }
        return 1;
    }

    /* Reading this line causes bed2sga to fail on the first species in chr_NC_gi,
     * so this part is commented out. I'm keeping it for a while in case it turns out
     * it was needed after all, then I'll simply delete the lines (TJ).
     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 */
        if (options.debug)
            printf("chr_NC_gi line : %s\n", s);
        if (*s == '#') {
            if (!break_flag) {
                /* Get first word */
                s++;
                if (sscanf(s, "%127[^\t\n]", field) == 1) {
                    if (options.debug) {
                        printf ("field: '%s' Species: '%s'\n", field, Species);
                    }
                    if ((strcmp(field, Species) == 0)) {
                        if (options.debug) 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;
            pmatch = match(chr_nb, "scaff");
            if (pmatch == -1) {
                strcpy(chrom, "chr");
                strcat(chrom, chr_nb);
            } else {
                strcpy(chrom, chr_nb);
            }
            nb_len = (int) strlen(chrom) + 1;
            /* fprintf(stderr,
               "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: chrom: %s (len = %d) -> NCBI AC: %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: NCBI AC: %s (len = %d) -> AC: %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-1] = 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, pos2, 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[]) {
    progname = argv[0];
    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, 'a' },
        { "extend", required_argument, 0, 'x' },
        { "center", no_argument, 0, 'c' },
        { "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:a:s:Ccurx:", 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':
            fprintf(stderr,
                    "WARNING: option -s is deprecated, please use -a.\n");
            Species = optarg;
            break;
        case 'a':
            Species = optarg;
            break;
        case 'C':
            fprintf(stderr,
                    "WARNING: -c is deprecated; please use -C instead.\n");
            options.center = 1;
            break;
        case 'c':
            options.center = 1;
            break;
        case 'x':
            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;
            }
            break;
        default:
            printf("?? getopt returned character code 0%o ??\n", c);
            usage = 1;
        }
    }
    if (optind > argc || options.help == 1 || usage) {
        show_help();
        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);
                show_help();
                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(argv[0]) == 0) {
        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;
}
