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

konve.c (C-Munipack project)
CCD frame conversion utility
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 = 
{ 
	"konve", 
	"Utility for conversion CCD frames to FITS format"
};

/* Options */
CmdOption opt[] =
{
	{ "print-info", 'n', "print short info about frames, don't make any output files" },
	{ "print-header", 'e', "print content of the header, don't make any output files" },
	{ "configuration-file", 'p', "read parameters from configuration file", "filepath", CMD_PTYPE_FILEPATH },
	{ "set", 's', "set configuration parameter", "name=value", CMD_PTYPE_PARAMLIST },
	{ "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='kout???.fts')", "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", "file names of CCD frames to convert", CMD_PTYPE_FILELIST },
	{ NULL }
};

/* Configuration parameters */
CfgParam cfg[] = 
{
	{ "flip-image", CFG_PTYPE_STRING, "flip image (value can be 'x', 'y' or 'xy')" },
	{ "time-corr", CFG_PTYPE_DOUBLE, "time correction in seconds (>0 = to future, <0 = to past)" },
	{ NULL }
};

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

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 konve(CmpackKonv *lc, const char *srcpath, const char *dstpath)
{
	int res;
	CmpackCcdFile *src, *dst;

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

	res = cmpack_ccd_open(&src, srcpath, CMPACK_OPEN_READONLY, 0);
	if (res!=0) {
		report(res, srcpath);
		return res;
	}
	res = cmpack_ccd_open(&dst, dstpath, CMPACK_OPEN_CREATE, 0);
	if (res!=0) {
		report(res, dstpath);
		cmpack_ccd_destroy(src);
		return res;
	}
	res = cmpack_konv(lc, src, dst);
	cmpack_ccd_destroy(src);
	if (res!=0) {
		report(res, srcpath);
		cmpack_ccd_destroy(dst);
		return res;
	}
	res = cmpack_ccd_close(dst);
	if (res!=0) {
		report(res, dstpath);
		cmpack_ccd_destroy(dst);
		return res;
	}
	return 0;
}

/* Print short info */
static int print_info(CmpackCcdFile *file)
{
	int res;
	char datestr[64], timestr[64], msg[64];
	CmpackCcdParams params;

  	/* Check parameters */
	if (!file) 
		return CMPACK_ERR_INVALID_PAR;

	res = cmpack_ccd_get_params(file, CMPACK_CM_IMAGE | CMPACK_CM_FORMAT |
		CMPACK_CM_OBJECT | CMPACK_CM_DATETIME | CMPACK_CM_EXPOSURE |
		CMPACK_CM_CCDTEMP | CMPACK_CM_FILTER, &params);
	if (res!=0)
		return res;

	/* Print short info */
	if (params.format_name) 
		printf("File format: %s\n", params.format_name);
	printf("Image size : %d x %d pixels\n", params.image_width, params.image_height);
	cmpack_datetostr(&params.date_time.date, datestr, 64);
	cmpack_timetostr(&params.date_time.time, timestr, 64);
  	printf("Date & time: %s %s UT\n" , datestr, timestr);
	if (params.exposure>0) 
		printf("Exposure   : %.2f s\n", params.exposure);
	if (params.ccdtemp > -999 && params.ccdtemp < 999) 
		printf("Temperature: %.1f deg.C\n", params.ccdtemp);
	if (params.filter) 
      	printf("Filter     : %s\n", params.filter);
	if (params.object.designation) {
      	printf("Object     : %s\n", params.object.designation);
	}
	if (params.object.ra_valid) {
		cmpack_ratostr(params.object.ra, msg, 64);
      	printf("R.A.       : %s\n", msg);
	}
	if (params.object.dec_valid) {
		cmpack_dectostr(params.object.dec, msg, 64);
      	printf("Declination: %s\n", msg);
	}
	if (params.observer) 
		printf("Observer   : %s\n", params.observer);
	if (params.location.designation) 
      	printf("Observatory: %s\n", params.location.designation);
	if (params.location.lon_valid) {
		cmpack_lontostr(params.location.lon, msg, 64);
      	printf("Longitude  : %s\n", msg);
	}
	if (params.location.lat_valid) {
		cmpack_lattostr(params.location.lat, msg, 64);
      	printf("Latitude   : %s\n", msg);
	}
 	return 0;
}

/* Print full header */
int print_head(CmpackCcdFile *file)
{
	int i;
	char *key, *val, *com;

  	/* Check parameters */
	if (!file) 
		return CMPACK_ERR_INVALID_PAR;

	/* Print full info */
	printf("%-20s %-24s %s\n","---Key---","---Value---","---Comments---");
	for (i=0; cmpack_ccd_get_param(file, i, &key, &val, &com)==0; i++) {
		printf("%-20.20s %-24.24s %-32.32s\n",
			(key ? key : ""), (val ? val : ""), (com ? com : ""));
		cmpack_free(key);
		cmpack_free(val);
		cmpack_free(com);
	}
	return 0;
}

static int print(int mode, const char *srcpath)
{
	int res;
	CmpackCcdFile *src;

	printf("\nFile       : %s\n", srcpath);

	res = cmpack_ccd_open(&src, srcpath, CMPACK_OPEN_READONLY, 0);
	if (res!=0) {
		report(res, srcpath);
		return res;
	}
	if (mode==1) 
		res = print_info(src);
	else
		res = print_head(src);
	cmpack_ccd_destroy(src);
	if (res!=0) {
		report(res, srcpath);
		return res;
	}
	return 0;
}

int main (int argc, char *argv[]) 
{
	FILE	*din = NULL, *dout = NULL;
	int		i, icit, res, count, mode, in_files = 0, out_files = 0;
	char 	line[MAXLINE], outf[MAXLINE], buf1[MAXLINE];
	char	*dirfile_in, *dirfile_out, *cfgfile, *par, *out_mask, **files;
	double	tcorr = 0;
	CmpackKonv *lc;
	CmpackConsole *con;

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

	/* Create context */
	lc = cmpack_konv_init();
	if (!lc) error(CMPACK_ERR_MEMORY, NULL);

	/* Set callback function and output level */
	con = cmpack_con_init();
	if (cmdline_isdef(&cmd, "quiet")) 
		cmpack_con_set_level(con, CMPACK_LEVEL_QUIET);
	if (cmdline_isdef(&cmd, "verbose"))
		cmpack_con_set_level(con, CMPACK_LEVEL_DEBUG);
	cmpack_konv_set_console(lc, con);

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

	/* Set conversion mode */
	mode = 0;
	if (cmdline_isdef(&cmd, "print-info"))
		mode = 1; 
	if (cmdline_isdef(&cmd, "print-header"))
		mode = 2;

	if (mode==0) {
		/* Image flipping */
		if (cfgfile_gets(&cmd, "flip-image", &par)) {
			int hflip = strchr(par,'x') || strchr(par,'X');
			int vflip = strchr(par,'y') || strchr(par,'Y');
			cmpack_konv_set_transposition(lc, hflip, vflip);
		}
		/* Time correction */
		if (cfgfile_getd(&cmd, "time-corr", &tcorr)) 
			cmpack_konv_set_toffset(lc, tcorr);
		/* prepare format string for generating output file names */
		if (!cmdline_gets(&cmd, "output-mask", &out_mask))
			out_mask = "kout???.fts";
		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);
		}
		while (fgets(buf1, MAXLINE, din)) {
			sscanf(buf1, "%1023s", line);
			if (CheckFilePath(line)) {
				in_files++;
				if (mode==0) {
					FormatOutputName(outf, MAXLINE, out_mask, line, icit++);
					res = konve(lc, line, outf);
					if (res==0) {
						if (dout) fprintf(dout, "%s\n", outf);
						out_files++;
					}
				} else {
					res = print(mode, line);
					if (res==0) 
						out_files++;
					break;
				}
			}
		}
		if (din && 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);
								if (mode==0) {
									FormatOutputName(outf, MAXLINE, out_mask, fd.name, icit++);
									res = konve(lc, line, outf);
									if (res==0) {
										if (dout) fprintf(dout, "%s\n", outf);
										out_files++;
									}
								} else {
									res = print(mode, line);
									if (res==0) 
										out_files++;
								}
							}
						} while (_findnext(fh, &fd)==0);
						_findclose(fh);
					}
#else
					in_files++;
					if (mode==0) {
						FormatOutputName(outf, MAXLINE, out_mask, files[i], icit++);
						res = konve(lc, files[i], outf);
						if (res==0) {
							if (dout) fprintf(dout, "%s\n", outf);
							out_files++;
						}
					} else {
						res = print(mode, files[i]);
						if (res==0) 
							out_files++;
					}
#endif
				}
			}
		}
	}

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

	PrintEpilogueEx(&cmd, in_files, out_files);

	cmpack_konv_destroy(lc);
	cmpack_con_destroy(con);
	Clean(&cmd);

	return 0;
}
