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

airmass.c (C-Munipack project)
Air-mass coefficient computation 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 <stdlib.h>
#include <stdio.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 = 
{ 
	"airmass", 
	"utility for computation air-mass coefficient"
};

/* Command-line 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 },
	{ "longitude", 'l', "longitude of observer in degrees (positive to the East)", "value", CMD_PTYPE_DOUBLE },
	{ "latitude", 'b', "latitude of observer in degrees (positive to the North)", "value", CMD_PTYPE_DOUBLE },
	{ "altitude", 0, "include apparent altitude of the object in degrees" },
	{ "configuration-file", 'p', "read parameters from configuration file", "filepath", CMD_PTYPE_FILEPATH },
	{ "set", 's', "set configuration parameter", "name=value", CMD_PTYPE_PARAMLIST },
	{ "julian-date", 'j', "compute X for given julian date, do not process files", "jd", CMD_PTYPE_DOUBLE },
	{ "read-dirfile", 'i', "read list of source file 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='%-airmass.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 process", CMD_PTYPE_FILELIST },
	{ NULL }
};

/* Configuration parameters */
CfgParam cfg[] = 
{
	{ "longitude", CFG_PTYPE_DOUBLE, "longitude of observer in degrees (positive to the North)" },
	{ "latitude", CFG_PTYPE_DOUBLE, "latitude of observer in degrees (positive to the North)" },
	{ "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 _CmpackAirMass
{
	int ra_valid, dec_valid;
	double ra_value, dec_value;
	int lon_valid, lat_valid;
	double lon_value, lat_value;
} CmpackAirMass;

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);
}

static int amass(CmpackAirMass *lc, const char *srcpath, const char *dstpath, int altitude)
{
	FILE	*f, *g;
	int		res, head_found;
	char	buf[MAXLINE], eol[MAXLINE], *endptr;
	double	jd, amass, alt;
	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;
	}
	if (!lc->lon_valid) {
		fprintf(stderr, "Missing observer's longitude");
		return CMPACK_ERR_NO_OBS_COORDS;
	}
	if (!lc->lat_valid) {
		fprintf(stderr, "Missing observer's latitude");
		return CMPACK_ERR_NO_OBS_COORDS;
	}
	
	printf("%s => %s\n", srcpath, dstpath);

	/* Check parameters */
	res = cmpack_airmass(2450000.0, lc->ra_value, lc->dec_value, lc->lon_value, lc->lat_value, NULL, NULL);
	if (res!=0) {
		error(res, srcpath);
		return res;
	}

	/* 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;
	}

	/* Process file line by line */
	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 */
				i = strcspn(buf, "\r\n");
				strcpy(eol, buf+i);
				buf[i] = '\0';
				fprintf(g,"%s AIRMASS%s%s", buf, (altitude ? " ALTITUDE" : ""), eol);
				head_found = 1;
				continue;
			}
		}

		jd = strtod(buf, &endptr);
		if (endptr==buf || jd<2400000 || jd>=3000000) {
			/* Any other line */
			fprintf(g,"%s",buf);
			continue;
		}
			
		cmpack_airmass(jd, lc->ra_value, lc->dec_value, lc->lon_value, lc->lat_value, &amass, &alt);
		i = strcspn(buf, "\r\n");
		strcpy(eol, buf+i);
		buf[i] = '\0';
		if (!altitude) {
			int prec = cmpack_get_param_long(CMPACK_PARAM_AMASS_PRECISION);
			fprintf(g, "%s %.*f%s", buf, prec, amass, eol);
		} else {
			int prec_am = cmpack_get_param_long(CMPACK_PARAM_AMASS_PRECISION),
				prec_alt = cmpack_get_param_long(CMPACK_PARAM_ALT_PRECISION);
			fprintf(g, "%s %.*f %.*f%s", buf, prec_am, amass, prec_alt, alt, eol);
		}
	}

	/* Close files */
	fclose(f);
	fclose(g);
	return 0;
}

int main(int argc, char **argv)
{
	FILE	*din = NULL, *dout = NULL;
	int		i, icit, res, count, altitude = 0, in_files = 0, out_files = 0;
	char 	line[MAXLINE], outf[MAXLINE], buf1[MAXLINE];
	char	*dirfile_in, *dirfile_out, *out_mask, *cfgfile, **files;
	double	jd, x, alt;
	CmpackAirMass 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(CmpackAirMass));

	/* Read configuration file */
	if (cmdline_gets(&cmd, "configuration-file", &cfgfile)) {
		res = cfgfile_read(&cmd, cfgfile);
		if (res!=0) error(res, cfgfile);
	}
	
	/* Set configuration parameters */
	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;
	}
	if (cfgfile_getd(&cmd, "longitude", &x)) {
		lc.lon_value = x;
		lc.lon_valid = 1;
	}
	if (cfgfile_getd(&cmd, "latitude", &x)) {
		lc.lat_value = x;
		lc.lat_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, "longitude",  &x)) {
		lc.lon_value = x;
		lc.lon_valid = 1;
	}
	if (cmdline_getd(&cmd, "latitude",  &x)) {
		lc.lat_value = x;
		lc.lat_valid = 1;
	}
	if (cmdline_isdef(&cmd, "altitude"))
		altitude = 1;

	if (cmdline_getd(&cmd, "julian-date",  &jd)) {
		/* Convert single julian date */
		res = cmpack_airmass(jd, lc.ra_value, lc.dec_value, lc.lon_value, lc.lat_value, &x, &alt);
		if (res!=0) 
			error(res, NULL);
		printf("Air-mass coefficient: %.4f\n\n", x);
		if (altitude)
			printf("Altitude            : %.1f deg.\n\n", alt);
	} else {
		/* Process table in a file */

		/* prepare format string for generating output file names */
		if (!cmdline_gets(&cmd, "output-mask", &out_mask))
			out_mask = "%-airmass.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)) {
					sscanf(buf1, "%1023s", line);
					if (CheckFilePath(line)) {
						in_files++;
						FormatOutputName(outf, MAXLINE, out_mask, line, icit++);
						res = amass(&lc, line, outf, altitude);
						if (res==0) {
							if (dout) fprintf(dout, "%s\n", outf);
							out_files++;
						} else {
							report(res, line);
						}
					}
				}
				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 = amass(&lc, line, outf, altitude);
									if (res==0) {
										if (dout) fprintf(dout, "%s\n", outf);
										out_files++;
									} else {
										report(res, fd.name);
									}
								}
							} while (_findnext(fh, &fd)==0);
							_findclose(fh);
						}
#else
						in_files++;
						FormatOutputName(outf, MAXLINE, out_mask, files[i], icit++);
						res = amass(&lc, files[i], outf, altitude);
						if (res==0) {
							if (dout) fprintf(dout, "%s\n", outf);
							out_files++;
						} else {
							report(res, files[i]);
						}
#endif
					}
				}
			}
		}

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

		PrintEpilogueEx(&cmd, in_files, out_files);
	}

	Clean(&cmd);

	return 0;
}
