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

amass.c (C-Munipack project)
Air-mass coefficient computation
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>
#include <math.h>
#include <limits.h>

#include "comfun.h"
#include "console.h"
#include "cmpack_common.h"
#include "cmpack_amass.h"
#include "trajd.h"

/**********************   PUBLIC FUNCTIONS   ***************************/

/* Compute airmass coefficient X. ra is in hours; dec, lon, lat in degrees */
int cmpack_airmass(double jd, double ra, double dec, double lon, double lat, 
	double *airmass, double *alt)
{
	double x = -1, lmst, har, h;

	/* Local mean sidereal time */
	lmst = cmpack_siderealtime(jd) + (lon/15.0);
	/* Hour angle */
	har = (lmst - ra)/12.0*M_PI;
	/* aparent altitude in degrees above horizon */
	lat = lat/180.0*M_PI;
	dec = dec/180.0*M_PI;
	h = asin(sin(dec)*sin(lat) + cos(dec)*cos(har)*cos(lat))/M_PI*180.0;
	if (alt)
		*alt = h;

	/* Is the star above the horizon? */
	if (h>=0) {
		/* Pickering's formula */
		x = 1.0 / sin((h/180.0*M_PI + 244/(165+47*pow(h, 1.1))/180.0*M_PI));
		if (airmass)
			*airmass = x;
	} else {
		if (airmass)
			*airmass = -1.0;
	}
	return CMPACK_ERR_OK;
}

/* Append air mass coefficient to the specified file */
int cmpack_airmass_table(CmpackTable *tab, const char *objname, double ra, 
	double dec, const char *location, double lon, double lat, CmpackConsole *con, 
	unsigned flags)
{
	int		res, no_airmass, no_altitude, jd_column, x_column, a_column;
	char	msg[MAXLINE];
	double	jd, x, alt;

	no_airmass	= (flags & CMPACK_AMASS_NOAIRMASS)!=0;
	no_altitude	= (flags & CMPACK_AMASS_NOALTITUDE)!=0;

	/* Print parameters */
	if (is_debug(con)) {
		printout(con, 1, "Configuration parameters:");
		printpard(con, "R.A.", 1, ra, 3);
		printpard(con, "Dec.", 1, dec, 3);
		printpard(con, "Lon.", 1, lon, 3);
		printpard(con, "Lat.", 1, lat, 3);
  	}

	jd_column = cmpack_tab_find_column(tab, "JD");
	if (jd_column<0) 
		jd_column = cmpack_tab_find_column(tab, "JDGEO");
	if (jd_column<0) {
		printout(con, 0, "Missing column with Julian date");
		return CMPACK_ERR_KEY_NOT_FOUND;
	}

	x_column = -1;
	if (!no_airmass) {
		x_column = cmpack_tab_find_column(tab, "AIRMASS");
		if (x_column<0)
			x_column = cmpack_tab_add_column_dbl(tab, "AIRMASS", AMASS_PRECISION, 0.0, 1e99, INVALID_AMASS);
	}

	a_column = -1;
	if (!no_altitude) {
		a_column = cmpack_tab_find_column(tab, "ALTITUDE");
		if (a_column<0)
			a_column = cmpack_tab_add_column_dbl(tab, "ALTITUDE", ALT_PRECISION, -90.0, 90.0, INVALID_ALT);
	}

	if (objname)
		cmpack_tab_pkys(tab, "OBJECT", objname);
	else
		cmpack_tab_dkey(tab, "OBJECT");
	cmpack_ratostr(ra, msg, 256);
	cmpack_tab_pkys(tab, "RA", msg);
	cmpack_dectostr(dec, msg, 256);
	cmpack_tab_pkys(tab, "DEC", msg);
	
	if (location)
		cmpack_tab_pkys(tab, "LOCATION", location);
	else
		cmpack_tab_dkey(tab, "LOCATION");
	cmpack_lontostr(lon, msg, 256);
	cmpack_tab_pkys(tab, "LONGITUDE", msg);
	cmpack_lattostr(lat, msg, 256);
	cmpack_tab_pkys(tab, "LATITUDE", msg);
	
	res = cmpack_tab_rewind(tab);
	while (res==0) {
		cmpack_tab_gtdd(tab, jd_column, &jd);
		if (jd<=0) {
			printout(con, 0, "Invalid Julian date of observation");
			return CMPACK_ERR_INVALID_JULDAT;
		}
		if (cmpack_airmass(jd, ra, dec, lon, lat, &x, &alt)!=0) {
			x = -1.0;
			alt = -99.9;
		}
		if (is_debug(con)) {
			sprintf(msg, "%.7f -> Alt. = %.3f, X = %.3f", jd, alt, x); 
			printout(con, 1, msg);
		}
		if (x_column>=0)
			cmpack_tab_ptdd(tab, x_column, x);
		if (a_column>=0)
			cmpack_tab_ptdd(tab, a_column, alt);
		res = cmpack_tab_next(tab);
	}

	/* Normal return */
	return 0;
}

/* Create a table with airmass and altitude values */
int cmpack_airmass_curve(CmpackFrameSet *fset, CmpackTable **ptable, const char *objname, 
	double ra, double dec, const char *location, double lon, double lat,
	CmpackAMassFlags flags, CmpackConsole *con)
{	
	int cols = CMPACK_FC_JULDAT | CMPACK_FC_AIRMASS | CMPACK_FC_ALTITUDE;

	if (flags & CMPACK_AMASS_FRAME_IDS)
		cols |= CMPACK_FC_FRAME;
	if (flags & CMPACK_AMASS_NOAIRMASS)
		cols &= ~CMPACK_FC_AIRMASS;
	if (flags & CMPACK_AMASS_NOALTITUDE)
		cols &= ~CMPACK_AMASS_NOALTITUDE;

	return cmpack_fset_plot(fset, ptable, CMPACK_TABLE_AIRMASS, (CmpackFSetColumns)cols, 
		0, 0, objname, ra, dec, location, lon, lat, con);
}

/* Append air mass coefficient to the specified file */
int cmpack_airmass_fset(CmpackFrameSet *fset, const char *objname, double ra, 
	double dec, const char *location, double lon, double lat, CmpackConsole *con)
{
	int		res, jd_prec;
	char	msg[MAXLINE];
	double	x, alt;
	CmpackFrameInfo info;
	CmpackFrameSetInfo data;

	/* Print parameters */
	if (is_debug(con)) {
		printout(con, 1, "Configuration parameters:");
		printpard(con, "R.A.", 1, ra, 3);
		printpard(con, "Dec.", 1, dec, 3);
		printpard(con, "Lon.", 1, lon, 3);
		printpard(con, "Lat.", 1, lat, 3);
  	}

	cmpack_fset_get_info(fset, CMPACK_FS_JD_PREC, &data);
	jd_prec = data.jd_prec;

	data.objcoords.ra_valid = 1;
	data.objcoords.ra = ra;
	data.objcoords.dec_valid = 1;
	data.objcoords.dec = dec;
	data.objcoords.designation = (char*)objname;
	data.location.lon_valid = 1;
	data.location.lat = lat;
	data.location.lat_valid = 1;
	data.location.lon = lon;
	data.location.designation = (char*)location;
	cmpack_fset_set_info(fset, CMPACK_FS_OBJECT | CMPACK_FS_LOCATION, &data);

	res = cmpack_fset_rewind(fset);
	while (res==0) {
		cmpack_fset_get_frame(fset, CMPACK_FI_JULDAT, &info);
		if (info.juldat<=0) {
			printout(con, 0, "Invalid Julian date of observation");
		} else {
			if (cmpack_airmass(info.juldat, ra, dec, lon, lat, &x, &alt)==0) {
				info.airmass = x;
				info.altitude = alt;
				if (is_debug(con)) {
					sprintf(msg, "%.*f -> Alt. = %.*f, X = %.*f", jd_prec, info.juldat, 
						ALT_PRECISION, alt, AMASS_PRECISION, x); 
					printout(con, 1, msg);
				}
			}
		}
		cmpack_fset_set_frame(fset, CMPACK_FI_AIRMASS_ALT, &info);
		res = cmpack_fset_next(fset);
	}

	/* Normal return */
	return 0;
}
