/**************************************************************

helcor.c (C-Munipack project)
Heliocentric correction tool
Copyright (C) 2003 David Motl, dmotl@volny.cz

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 <stdlib.h>
#include <string.h>

#ifdef _WIN32
#include <io.h>
#endif

#include "cmunipack.h"
#include "cmdline.h"
#include "cfgfile.h"
#include "utils.h"

/* Program */
AppName prog = 
{ 
	"helcor", 
	"utility for computing heliocentric correction"
};

/* Options */
CmdOption opt[] =
{
	{ "right-ascension", 'a', "right ascension of object in hours", "value", CMD_PTYPE_DOUBLE },
	{ "declination", 'd', "declination of object in degrees", "value", CMD_PTYPE_DOUBLE },
	{ "configuration-file", 'p', "read parameters from configuration file", "filepath", CMD_PTYPE_FILEPATH },
	{ "set", 's', "set configuration parameter", "name=value", CMD_PTYPE_PARAMLIST },
	{ "jdgeo-to-jdhel", 0, "convert JDgeo to JDhel (default)" },
	{ "jdhel-to-jdgeo", 'r', "convert JDhel to JDgeo" },
	{ "no-conversion", 'n', "do not convert JD" },
	{ "append-hcorr", 'k', "append helioc. corr. to the end of each line" },
	{ "julian-date", 'j', "compute h.c. for given julian date, do not process files", "jd", CMD_PTYPE_DOUBLE },
	{ "read-dirfile", 'i', "read list of source CCD frames from specified file", "filepath", CMD_PTYPE_FILEPATH },
	{ "make-dirfile", 'g', "save list of output files to specified file", "filepath", CMD_PTYPE_FILEPATH },
	{ "output-mask", 'o', "change output file mask (default='%-helcor.dat')", "mask", CMD_PTYPE_FILEMASK },
	{ "counter", 'c', "set initial counter value (default=1)", "value", CMD_PTYPE_INT },
	{ "help", 'h', "print list of command-line parameters" },
	{ "quiet", 'q', "quiet mode; suppress all messages" },
	{ "version", 0, "print software version" },
	{ "licence", 0, "print software licence" },
	{ "verbose", 0, "verbose mode; print debug messages" },
	{ NULL }
};

/* Input files */
CmdParam flist[] = 
{
	{ "files", "names of files to conversion", CMD_PTYPE_FILELIST },
	{ NULL }
};

/* Configuration parameters */
CfgParam cfg[] = 
{
	{ "right-ascension", CFG_PTYPE_DOUBLE, "right ascension of object in hours" },
	{ "declination", CFG_PTYPE_DOUBLE, "declination of object in degrees" },
	{ NULL }
};

/* Command-line definition */
AppInfo cmd = 
{ 
	&prog, opt, flist, cfg
};

typedef struct _CmpackHelCorr
{
	int ra_valid, dec_valid;
	double ra_value, dec_value;
} CmpackHelCorr;

static void report(int status, const char *file)
{
	PrintError(&cmd, file, 0, status);
}

static void error(int status, const char *file)
{
	PrintError(&cmd, file, 0, status);
	exit(status);
}

int hcorr(CmpackHelCorr *lc, const char *srcpath, const char *dstpath,
		int mod, int rev, int inc)
{
	FILE  *f, *g;
	int    dec, head_found;
	char   buf[MAXLINE], eol[MAXLINE], *endptr, *aux;
	double jdin, jdout, hcor;
	size_t i;

	if (!lc->ra_valid) {
		fprintf(stderr, "Missing object's right ascension");
		return CMPACK_ERR_NO_OBJ_COORDS;
	}
	if (!lc->dec_valid) {
		fprintf(stderr, "Missing object's declination");
		return CMPACK_ERR_NO_OBJ_COORDS;
	}

	printf("%s => %s\n", srcpath, dstpath);

	/* Open source file */
	f = fopen(srcpath,"r");
	if (f==NULL) {
		report(CMPACK_ERR_CANT_OPEN_SRC, srcpath);
		return CMPACK_ERR_CANT_OPEN_SRC;
	}

	/* Open destination file */
	g = fopen(dstpath,"w");
	if (g==NULL) {
		fclose(f);
		report(CMPACK_ERR_CANT_OPEN_OUT, dstpath);
		return CMPACK_ERR_CANT_OPEN_OUT;
	}

	head_found = 0;
	while (fgets(buf,MAXLINE,f)!=NULL) {
		if (!head_found) {
      		if (strstr(buf, "JD ")==buf || strstr(buf, "JDHEL ")==buf || strstr(buf, "JDGEO ")==buf) {
				/* This is a header line */
	      		if (!mod) {
					if (inc) {
						i = strcspn(buf, "\r\n");
						strcpy(eol, buf+i);
						buf[i] = '\0';
						fprintf(g,"%s HELCOR%s", buf, eol);
					} else {
						fprintf(g,"%s", buf);
					}
	      		} else {
		      		endptr = buf + strcspn(buf, " ");
		      		aux = (!rev ? "JDHEL" : "JDGEO");
					if (inc) {
						i = strcspn(buf, "\r\n");
						strcpy(eol, buf+i);
						buf[i] = '\0';
						fprintf(g,"%s%s HELCOR%s", aux, endptr, eol);
					} else {
						fprintf(g,"%s%s", aux, endptr);
					}
				}
				head_found = 1;
				continue;
			}
		}
		
		jdin = strtod(buf,&endptr);
		if (endptr==buf || jdin<2400000 || jdin>=3000000) {
			/* Any other line */
			fprintf(g, "%s", buf);
			continue;
		}
			
		/* Determine, how many decimal places were used */
		aux = strchr(buf,'.');
		dec = (aux<endptr ? (int)(endptr-aux)-1 : cmpack_get_param_long(CMPACK_PARAM_JD_PRECISION));
		
		hcor = cmpack_helcorr(jdin, lc->ra_value, lc->dec_value);
		if (!mod) {
			jdout = jdin;
			if (inc) {
				i = strcspn(buf, "\r\n");
				strcpy(eol, buf+i);
				buf[i] = '\0';
				fprintf(g,"%s %.*f%s", buf, dec, hcor, eol);
			} else {
				fprintf(g, "%s" , buf);
			}
		} else {
			jdout = jdin + hcor * (rev ? -1.0 : 1.0);
			if (inc) {
				i = strcspn(buf, "\r\n");
				strcpy(eol, buf+i);
				buf[i] = '\0';
				fprintf(g,"%.*f%s %.*f%s", dec, jdout, endptr, dec, hcor, eol);
			} else {
				fprintf(g, "%.*f%s" , dec, jdout, endptr);
			}
		}
	}
	/* Normal return */
	fclose(f);
	fclose(g);
 	return 0;
}

int main(int argc, char **argv)
{
	FILE	*din = NULL, *dout = NULL;
	int		i, icit, res, count, in_files = 0, out_files = 0;
	int		correction = 0, reverse = 0, append = 0;
	char 	line[MAXLINE], outf[MAXLINE], buf1[MAXLINE];
	char	*dirfile_in, *dirfile_out, *out_mask, *cfgfile, **files;
	double	jd, x, helcor;
	CmpackHelCorr lc;

	Init(&cmd);

	/* Parse command line */
	if (!cmdline_parse(argc, argv, &cmd))
		return CMPACK_ERR_CMDLINE_ERROR;

	/* Process standard options */
	if (cmdline_isdef(&cmd, "version")) {
		PrintVersion(&cmd);
		return 0;
	}
	if (cmdline_isdef(&cmd, "licence")) {
		PrintLicense(&cmd);
		return 0;
	}
	if (cmdline_isdef(&cmd, "help")) {
		PrintHelp(&cmd);
		return 0;
	}

	/* Print program info */
	PrintPrologue(&cmd);

	memset(&lc, 0, sizeof(CmpackHelCorr));
	
	/* Read configuration file */
	if (cmdline_gets(&cmd, "configuration-file", &cfgfile)) {
		res = cfgfile_read(&cmd, cfgfile);
		if (res!=0) error(res, NULL);
	}

	/* Set configuration paremeters */
	if (cfgfile_getd(&cmd, "right-ascension", &x)) {
		lc.ra_value = x;
		lc.ra_valid = 1;
	}
	if (cfgfile_getd(&cmd, "declination", &x)) {
		lc.dec_value = x;
		lc.dec_valid = 1;
	}
	
	/* Set coordinates */
	if (cmdline_getd(&cmd, "right-ascension", &x)) {
		lc.ra_value = x;
		lc.ra_valid = 1;
	}
	if (cmdline_getd(&cmd, "declination", &x)) {
		lc.dec_value = x;
		lc.dec_valid = 1;
	}

	if (cmdline_getd(&cmd, "julian-date", &jd)) {
		/* Print hel. corr. for single JD */
		helcor = cmpack_helcorr(jd, lc.ra_value, lc.dec_value);
		printf("Heliocentric correction  : %14.6f\n", helcor);
		if (!reverse) 
			printf("Heliocentric julian date : %14.6f\n", jd+helcor);
		else
			printf("Geocentric julian date   : %14.6f\n", jd-helcor);
		printf("\n");
	} else {
		/* Process table in a file */

		/* Set mode */
		correction = 1; reverse = append = 0;
		if (cmdline_isdef(&cmd, "jdhel-to-jdgeo"))
			reverse = 1;
		if (cmdline_isdef(&cmd, "no-conversion"))
			correction = 0;
		if (cmdline_isdef(&cmd, "append-hcorr"))
			append = 1;
		if (!append && !correction) {
			fprintf(stderr, "There is no conversion mode specified.\n");
			exit(CMPACK_ERR_INVALID_PAR);
		}

		/* prepare format string for generating output file names */
		if (!cmdline_gets(&cmd, "output-mask", &out_mask))
			out_mask = "%-helcor.dat";
		if (!CheckFileMask(out_mask))
			error(CMPACK_ERR_INVALID_FILE_MASK, NULL);

		/* Initial counter value */
		if (!cmdline_geti(&cmd, "counter", &icit))
			icit = 1;

		/* Create output dirfile */
		if (cmdline_gets(&cmd, "make-dirfile", &dirfile_out)) {
			if (strcmp(dirfile_out, "@")==0) {
				dout = stdout;
			} else {
				dout = fopen(dirfile_out, "w+");
			}
			if (dout==NULL) 
				error(CMPACK_ERR_CANT_MAKE_DIRFILE, dirfile_out);
		}

		if (cmdline_gets(&cmd, "read-dirfile", &dirfile_in)) {
			/* Image names are read from a file */
			if (strcmp(dirfile_in, "@")==0) {
				din = stdin;
			} else {
				din = fopen(dirfile_in, "r");
			}
			if (din==NULL) {
				error(CMPACK_ERR_CANT_OPEN_DIRFILE, dirfile_in);
			} else {
				while (fgets(buf1, MAXLINE, din)) {
					if (sscanf(buf1, "%1023s", line) == 1 && CheckFilePath(line)) {
						in_files++;
						FormatOutputName(outf, MAXLINE, out_mask, line, icit++);
						res = hcorr(&lc, line, outf, correction, reverse, append);
						if (res==0) {
							if (dout) fprintf(dout, "%s\n", outf);
							out_files++;
						}
					}
				}
				if (din!=stdin)
					fclose(din);
			}
		} else {
			/* images names are given through the command line */
			if (cmdline_getparsv(&cmd, "files", &files, &count)) {
				for (i=0; i<count; i++) {
					if (CheckFilePath(files[i])) {
#ifdef _WIN32
						struct _finddata_t fd;
						intptr_t fh = _findfirst(files[i], &fd);
						if (fh!=-1) {
							do {
								if ((fd.attrib & _A_SUBDIR)==0)  {
									in_files++;
									MakeInputName(line, MAXLINE, files[i], fd.name);
									FormatOutputName(outf, MAXLINE, out_mask, fd.name, icit++);
									res = hcorr(&lc, line, outf, correction, reverse, append);
									if (res==0) {
										if (dout) fprintf(dout, "%s\n", outf);
										out_files++;
									}
								}
							} while (_findnext(fh, &fd)==0);
							_findclose(fh);
						}
#else
						in_files++;
						FormatOutputName(outf, MAXLINE, out_mask, files[i], icit++);
						res = hcorr(&lc, files[i], outf, correction, reverse, append);
						if (res==0) {
							if (dout) fprintf(dout, "%s\n", outf);
							out_files++;
						}
#endif
					}
				}
			}
		}

		if (dout && dout!=stdout)
			fclose(dout);

		PrintEpilogueEx(&cmd, in_files, out_files);
	}

	Clean(&cmd);

	return 0;
}
