/*
  compactsga.c

  Merge equal tag positions within a SGA File

  # Arguments:
  # SGA file

  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>
#ifdef DEBUG
#include <mcheck.h>
#endif

#include "version.h"

/*#define BUF_SIZE 4096 */
#define BUF_SIZE 8192
#define LINE_SIZE 1024
#define FT_MAX  64
#define SEQ_ID  64
#define POS_MAX 16
#define CNT_MAX 16
#define EXT_MAX 256

typedef struct _options_t {
    int help;
    int debug;
} options_t;

static options_t options;
/*
int
process_sga(char *iFile)
*/
int process_sga(void) {
    /*
       FILE *f = fopen(iFile, "r");
     */
    unsigned long pos;
    char chr[SEQ_ID] = "";
    unsigned long p = 0;
    int tc = 0;
    int cnt = 0;
    char ft[FT_MAX] = "";
    char str = '\0';
    char desc[EXT_MAX] = "";
    char *s, *res, *buf;
    size_t bLen = LINE_SIZE;

    /*
       if (f == NULL) {
       fprintf(stderr, "Could not open file %s: %s(%d)\n",
       iFile, strerror(errno), errno);
       return 1;
       }
     */
    if ((s = malloc(bLen * sizeof(char))) == NULL) {
        perror("process_sga: malloc");
        exit(1);
    }
    /*
       if (options.debug)
       fprintf(stderr, "Processing file %s\n", iFile);
     */
#ifdef DEBUG
    int lc = 1;
#endif
    /*
       while ((res = fgets(s, (int) bLen, f)) != NULL) {
     */
    while ((res = fgets(s, (int) bLen, stdin)) != NULL) {
        char seq_id[SEQ_ID] = "";
        char feature[FT_MAX] = "";
        char position[POS_MAX] = "";
        char count[CNT_MAX] = "";
        char strand = '\0';
        char ext[EXT_MAX] = "";
        size_t cLen = strlen(s);
        unsigned int i = 0;

        memset(ext, 0, (size_t) EXT_MAX);
        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), f);
             */
            res = fgets(s + cLen, (int) (bLen - cLen), stdin);
            cLen = strlen(s);
        }
        if (s[cLen - 1] == '\n')
            s[cLen - 1] = 0;

        buf = s;
        /* Get SGA fields */
        /* SEQ ID */
        while (*buf != 0 && !isspace(*buf)) {
            if (i >= SEQ_ID) {
                fprintf(stderr, "Seq ID is too long \"%s\" \n", buf);
                exit(1);
            }
            seq_id[i++] = *buf++;
        }
        while (isspace(*buf))
            buf++;
        /* FEATURE */
        i = 0;
        while (*buf != 0 && !isspace(*buf)) {
            if (i >= FT_MAX) {
                fprintf(stderr, "Feature is too long \"%s\" \n", buf);
                exit(1);
            }
            feature[i++] = *buf++;
        }
        while (isspace(*buf))
            buf++;
        /* Position */
        i = 0;
        while (isdigit(*buf)) {
            if (i >= POS_MAX) {
                fprintf(stderr, "Position is too large \"%s\" \n", buf);
                exit(1);
            }
            position[i++] = *buf++;
        }
        position[i] = 0;
        pos = (unsigned long) atol(position);
        while (isspace(*buf))
            buf++;
        /* Strand */
        strand = *buf++;
        while (isspace(*buf))
            buf++;
        /* Counts */
        i = 0;
        while (isdigit(*buf)) {
            if (i >= CNT_MAX) {
                fprintf(stderr, "Count is too large \"%s\" \n", buf);
                exit(1);
            }
            count[i++] = *buf++;
        }
        count[i] = 0;
        cnt = atoi(count);
        while (isspace(*buf))
            buf++;
        /* SGA Extension */
        i = 0;
        while (*buf != 0) {
            if (i >= EXT_MAX) {
                fprintf(stderr, "Extension is too long \"%s\" \n", buf);
                exit(1);
            }
            ext[i++] = *buf++;
        }
#ifdef DEBUG
        printf
            (" [%d] seq ID: %s   Feat: %s (%c)  Pos: %lu  Cnts: %d Ext: %s\n",
             lc++, seq_id, feature, strand, pos, cnt, ext);
#endif
        if (!strcmp(feature, "END")) {
            continue;
        }
        if (pos == p && strcmp(seq_id, chr) == 0 && strand == str) {
            tc += cnt;
        } else {
            if (tc > 0) {
                if (strcmp(desc, "")) {
                    printf("%s\t%s\t%lu\t%c\t%d\t%s\n", chr, ft, p, str,
                           tc, desc);
                } else {
                    printf("%s\t%s\t%lu\t%c\t%d\n", chr, ft, p, str, tc);
                }
            }
            strcpy(chr, seq_id);
            strcpy(ft, feature);
            strcpy(desc, ext);
            p = pos;
            str = strand;
            tc = cnt;
        }
    }                           /* End of While */
    free(s);
    if (tc > 0) {
        if (strcmp(desc, "")) {
            printf("%s\t%s\t%lu\t%c\t%d\t%s\n", chr, ft, p, str, tc, desc);
        } else {
            printf("%s\t%s\t%lu\t%c\t%d\n", chr, ft, p, str, tc);
        }
    }
    return 0;
}

int main(int argc, char *argv[]) {
#ifdef DEBUG
    mcheck(NULL);
    mtrace();
#endif

    while (1) {
        int c = getopt(argc, argv, "dh");
        if (c == -1)
            break;
        switch (c) {
        case 'd':
            options.debug = 1;
            break;
        case 'h':
            options.help = 1;
            break;
        default:
            printf("?? getopt returned character code 0%o ??\n", c);
        }
    }
    /*
       if (optind == argc || options.help == 1) {
     */
    if (options.help == 1) {
        fprintf(stderr, "Usage: %s [options] < <SGA File>\n"
                "      - version %s\n"
                "      where options are:\n"
                "  \t\t -h     Show this help text\n"
                "  \t\t -d     Print debug information\n"
                "\n\tThe program reads a ChIP-seq data file in SGA format (<SGA File>),\n"
                "\tand merges equal tag positions into a single line adjusting the count\n"
                "\tfield accordingly\n\n", argv[0], VERSION);
        return 1;
    }
    /*
       if (process_sga(argv[optind++]) != 0) {
       return 1;
       }
     */
    if (process_sga() != 0) {
        return 1;
    }
    return 0;
}
