/* ----------------------------------------------------------------------
 * getseq -- get quickly a fragment of a sequence
 * Copyright (C) 2000 January Weiner III
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 * USA.
 ---------------------------------------------------------------------- */

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>

#include "genpak.h"
#include "gp_getopt.h"

#define VERSION "0.7"
#define PROGNAME "gp_getseq"

char *progname ;

/*
 * structure holding program options
 */

typedef struct {
	char name[MAXNAZWA] ;
	FILE * list_fp ;
	FILE * in ;
	FILE * out ; 
	int list ;
	int reverse ;
	char* optname ; } opt_s ;


int readlistfile(FILE *list_fp, long *s, long *e, char* n) ;

int main(int argc, char *argv[])
{
	extern int optind ;
	extern char *optarg ;
	int c, width = 70 ; /* width with which the sequence gets formatted */
	sekw *outseq, *tempseq ;
	long start = 0, end = 0;
	char temp_name[MAXNAZWA] ;

	opt_s opt ;
	
	opt.in = NULL ;
	opt.out = NULL ;
	opt.list_fp = NULL ;
	opt.list = FALSE ;
	opt.optname = FALSE ;
	opt.reverse = FALSE ;

	/* initializing structure holding all warnings */

	allwarnings = NULL ;

	progname = argv[0] ;

	while ((c = gp_getopt(argc, argv, "l:n:rvhqd")) != EOF)
		switch(c) {
		case 'n':
			opt.optname = gp_strdup(optarg) ;
			gp_warn("Optional sequence name: %s",opt.optname) ;
			break ;
		case 'l':
			if(optarg[0] == '-' && strlen(optarg) == 1) {
				gp_warn("Reading list of sequences from standard input") ;
				opt.list_fp = stdin ;
			} else {
				gp_warn("Reading list of sequences from file %s",optarg) ;
				opt.list_fp = gp_file_open(optarg,"r") ;
				if(opt.list_fp == NULL) gp_error("Could not open file %s",optarg) ;
			}
			opt.list = TRUE ;
			break ;
		case 'r':
			gp_warn("Only reversing the sequence") ;
			opt.reverse = TRUE ;
			break ;
		case 'H':
			html = TRUE ;
			break ;
		case 'q':
			quiet = TRUE ;
			break ;
		case 'v':
			fprintf(stderr,"%s version %s\n",progname,VERSION) ;
			exit(0) ;
			break ;
		case 'd':
			debug = TRUE ;
			gp_warn("Running in debug mode") ;
			break ;
		case 'h':
			Help() ;
			break ;
		default:
			gp_error("Type '%s -h' for help",progname) ;
			break;
		}

	
	/*
	 * Unless we are using a list of sequences to cut out, we have to provide
	 * a sequence start and a sequence end.
	 */

	if(!opt.list && !opt.reverse) {
		
		if(optind + 2 > argc )
			gp_error("I need at least two arguments: start and end") ;
	
		if(sscanf(argv[optind], "%li", &start) != 1 )
			gp_error("Could not read the start base parameter") ;
	
		optind++ ;
		
		if(sscanf(argv[optind],"%li", &end) != 1 )
			gp_error("Could not read the end base parameter") ;

		optind++ ;

		if(debug) gp_warn("Reading sequence from %i to %i",start,end) ;
	}
	
	/* open the file pointer to read the sequences 
	 * from: standard input or a file provided? */

	if(optind >= argc) {
		if(debug) gp_warn("Reading master sequence from standard input") ;
		opt.in = stdin ;
	} else {
		if(debug) gp_warn("Reading master sequence from file %s", argv[optind]) ;
		opt.in = gp_file_open(argv[optind],"r") ;
	}

	/* opening the file pointer to write the output: 
 	 * standard output or file provided? */
	optind++ ;

	if(optind >= argc) {
		if(debug) gp_warn("Writing sequences to standard output") ;
		opt.out = stdout ;
	} else {
		if(debug) gp_warn("Writing sequences to file %s", argv[optind],"wb") ;
		opt.out = gp_file_open(argv[optind],"wb") ;
	}


	/* 
	 * This is the code that does all the actual work. If entries are taken
	 * from a list, it is executed as long as "workto" is TRUE. Otherwise
	 * execution stops after the first time.
	 */

	/* reverse option defined: only reverse the master sequence */
	if(opt.reverse) {
		if((tempseq = gp_seq_read(opt.in)) == NULL) 
			gp_error("No master sequence found!") ;
		outseq = gp_seq_reverse(tempseq) ;
		gp_seq_print_fasta(opt.out,outseq,width) ;
		return EXIT_SUCCESS ;
	}

	/* reading list of fragments from an optional fragments list. */
	if(opt.list) {
		/* reading the "master" sequence from which all the fragments come */
		if((tempseq = gp_seq_read(opt.in)) == NULL) 
			gp_error("No master sequence found!") ;

		*temp_name = '\0' ;
		/* reading fragments from the fragment list line by line */
		while(readlistfile(opt.list_fp,&start,&end,temp_name) == EXIT_SUCCESS) {
			if(debug)
				gp_warn("reading sequence from %i to %i",start,end) ;

			outseq = gp_seq_copy_frag(tempseq,start,end) ;

			if(opt.optname) 
				outseq->name = opt.optname ;
			else 
				if(*temp_name != '\0') outseq->name = gp_strdup(temp_name);

			gp_seq_print_fasta(opt.out,outseq,width) ;
			*temp_name = '\0' ;
		}
		return EXIT_SUCCESS ;
	}

	/* the standard behaviour: get a sequence from start to end */
	outseq = gp_seq_read_fragment(opt.in,start,end, 0) ;
	gp_seq_print_fasta(opt.out,outseq,width) ;

	if(html) gp_warn_print_all(opt.out) ;
	if(opt.list_fp != NULL) fclose(opt.list_fp) ;
	fclose(opt.out) ;
	fclose(opt.in) ;
	return(EXIT_SUCCESS);
}


/* Read sequence list from file */
int readlistfile(FILE *list_fp, long *s, long *e, char* n) {
	char bufor[BUFSIZ+1] ;

	bufor[0] = '\0' ;
	n[0] = '\0' ;

	do {
		if(fgets(bufor,BUFSIZ,list_fp) == NULL) {
			if(debug) gp_warn("Reading of list file terminated") ;
			return EXIT_FAILURE ;
		}
	} while(bufor[0] == '#') ;
		
	if(debug) gp_warn("Read line %s from list file",bufor) ;

	
	if(sscanf(bufor,"%li %li %99s",s,e,n)<2) {
		gp_warn("Could not interpret list file line") ;
		return EXIT_FAILURE ;
	}

	return EXIT_SUCCESS ;

}

/* Standard mesage */

void Help()
{
printf(_("\n"
"%s version %s  - get a sequence fragment"
"\n"
"  Usage:\n"
"     %s [options] start end [input file] [output file]\n"
"     %s -r [options] [input file] [output file]\n"
"     %s -l name [options] [input file] [output file]\n"
"\n"
"  Options:\n"
"     -r       : only reverse the sequence\n"
"     -l name  : take a list of sequences from file [name]\n"
"                (use '-' for standard input)\n"
"     -n name  : use alternate name for the sequence\n"
"     -H       : run in HTML mode (see man page)\n"
"     -q       : run in quiet mode\n"
"     -v       : print version information & exit\n"
"     -h       : print this help screen & exit\n\n")
,PROGNAME,VERSION,progname,progname,progname) ;
exit(EXIT_SUCCESS);
}


			
