/***************************************************************************\
*              MoonTracker: A Moon and Sun AutoTracking Utility             *
*            Created by John A. Magliacane, KD2BD, on 29-Nov-2002           *
*                          Last update: 11-Jun-2026                         *
*****************************************************************************
*                                                                           *
* 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 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.                                  *
*                                                                           *
*****************************************************************************
*                                                                           *
* Celestial calculations are based on "SunMoonCalculator.java" created by   *
* T. Alonso Albi, on February 23, 2021.  An archived copy is available at:  *
*                                                                           *
* https://web.archive.org/web/20230522223142/https://conga.oan.es/~alonso   *
* /doku.php?id=blog:sun_moon_position                                       *
*                                                                           *
* Java ---> C by John A. Magliacane, KD2BD in 2023. Hamlib integration by   *
* Soren Straarup AK4WQ, Thomas Ingebretsen LA9ERA, and Norvald Ryeng LA6YKA *
*                                                                           *
\***************************************************************************/  

#include <stdio.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

#define PI			3.14159265358979323846
#define TWO_PI			6.283185307179586
#define PI_OVER_TWO		1.5707963267948966
#define JULIAN_DAYS_PER_CENTURY	36525.0
#define SECONDS_PER_DAY		86400.0
#define LIGHT_TIME_DAYS_PER_AU	0.00577551833109
#define J2000			2451545.0
#define RAD_TO_DEG       	57.29577951308232
#define DEG_TO_RAD      	0.017453292519943295
#define ARCSEC_TO_RAD		4.84813681109536e-06
#define AU			149597870.691
#define EARTH_RADIUS		6378.1366
#define SUN_RADIUS		696000
#define MOON_RADIUS		1737.4

int qthalt;
char *version={"v2.0"}, callsign[20];
double qthlat, qthlong;
struct termios orig_state;

enum TWILIGHT {ASTRONOMICAL, NAUTICAL, CIVIL, HORIZON_34arcmin};
enum TWILIGHT_MODE {CLOSEST, TODAY_UT, TODAY_LT, timeZone=0};
enum EVENT {RISE, SET, TRANSIT};

const double sun_elements[50][4]=
{ 
	{ 403406.0, 0.0, 4.721964, 1.621043 }, 
	{ 195207.0, -97597.0, 5.937458, 62830.348067 }, 
	{ 119433.0, -59715.0, 1.115589, 62830.821524 }, 
	{ 112392.0, -56188.0, 5.781616, 62829.634302 }, 
	{ 3891.0, -1556.0, 5.5474, 125660.5691 }, 
	{ 2819.0, -1126.0, 1.512, 125660.9845 }, 
	{ 1721.0, -861.0, 4.1897, 62832.4766 }, 
	{ 0.0, 941.0, 1.163, .813 }, 
	{ 660.0, -264.0, 5.415, 125659.31 }, 
	{ 350.0, -163.0, 4.315, 57533.85 }, 
	{ 334.0, 0.0, 4.553, -33.931 }, 
	{ 314.0, 309.0, 5.198, 777137.715 }, 
	{ 268.0, -158.0, 5.989, 78604.191 }, 
	{ 242.0, 0.0, 2.911, 5.412 }, 
	{ 234.0, -54.0, 1.423, 39302.098 }, 
	{ 158.0, 0.0, .061, -34.861 }, 
	{ 132.0, -93.0, 2.317, 115067.698 }, 
	{ 129.0, -20.0, 3.193, 15774.337 }, 
	{ 114.0, 0.0, 2.828, 5296.67 }, 
	{ 99.0, -47.0, .52, 58849.27 }, 
	{ 93.0, 0.0, 4.65, 5296.11 }, 
	{ 86.0, 0.0, 4.35, -3980.7 }, 
	{ 78.0, -33.0, 2.75, 52237.69 }, 
	{ 72.0, -32.0, 4.5, 55076.47 }, 
	{ 68.0, 0.0, 3.23, 261.08 }, 
	{ 64.0, -10.0, 1.22, 15773.85 }, 
	{ 46.0, -16.0, .14, 188491.03 }, 
	{ 38.0, 0.0, 3.44, -7756.55 }, 
	{ 37.0, 0.0, 4.37, 264.89 }, 
	{ 32.0, -24.0, 1.14, 117906.27 }, 
	{ 29.0, -13.0, 2.84, 55075.75 }, 
	{ 28.0, 0.0, 5.96, -7961.39 }, 
	{ 27.0, -9.0, 5.09, 188489.81 }, 
	{ 27.0, 0.0, 1.72, 2132.19 }, 
	{ 25.0, -17.0, 2.56, 109771.03 }, 
	{ 24.0, -11.0, 1.92, 54868.56 }, 
	{ 21.0, 0.0, .09, 25443.93 }, 
	{ 21.0, 31.0, 5.98, -55731.43 }, 
	{ 20.0, -10.0, 4.03, 60697.74 }, 
	{ 18.0, 0.0, 4.27, 2132.79 }, 
	{ 17.0, -12.0, .79, 109771.63 }, 
	{ 14.0, 0.0, 4.24, -7752.82 }, 
	{ 13.0, -5.0, 2.01, 188491.91 }, 
	{ 13.0, 0.0, 2.65, 207.81 }, 
	{ 13.0, 0.0, 4.98, 29424.63 }, 
	{ 12.0, 0.0, .93, -7.99 }, 
	{ 10.0, 0.0, 2.21, 46941.14 }, 
	{ 10.0, 0.0, 3.59, -68.29 }, 
	{ 10.0, 0.0, 1.5, 21463.25 }, 
	{ 10.0, -9.0, 2.55, 157208.4 } 
};

double	jd_UT=0.0, t=0.0, obsLon=0.0, obsLat=0.0, nutLon=0.0,
	nutObl=0.0, meanObliquity=0.0, TTminusUT=0.0, lst=0.0;

struct	doubleArray
{
	double var1, var2, var3, var4;
};

struct	intArray
{
	int var1, var2, var3, var4, var5, var6;
};

struct	Ephemeris
{
	double	azimuth, elevation, rise, set, transit, transitElevation,
		rightAscension, declination, distance, eclipticLongitude,
		eclipticLatitude, angularRadius;
};

char dateString[77]={0};

unsigned char twilight=HORIZON_34arcmin;
unsigned char twilightMode=CLOSEST;

double normalizeRadians(double r)
{
	/* Reduce an angle in radians to the range (0 - 2 PI) */

	while (r<0.0)
		r+=TWO_PI;

	while (r>TWO_PI)
		r-=TWO_PI;

	return r;	
}

void setUTDate(double jd)
{
	/* Sets the UT date from the provided Julian day and computes
	the nutation, obliquity, and sidereal time. TT minuts UT1 is not
	updated since it changes very slowly with time.  Use this only
	to update the computation time for the same year as the one used
	when the instance was created.	jd The new Julian day in UT.  */
  
	double M1, M2, t2, tmp, jd0, T0, secs, gmst, msday;

	jd_UT=jd;
	t=(jd+TTminusUT/SECONDS_PER_DAY-J2000)/JULIAN_DAYS_PER_CENTURY;

	/* Compute nutation */

	M1=(124.90-1934.134*t+0.002063*t*t)*DEG_TO_RAD;
	M2=(201.11+72001.5377*t+0.00057*t*t)*DEG_TO_RAD;
	nutLon=(-(17.2026+0.01737*t)*sin(M1)+(-1.32012+0.00013*t)*sin(M2)+0.2088*sin(2.0*M1))*ARCSEC_TO_RAD;
	nutObl=((9.2088+0.00091*t)*cos(M1)+(0.552204-0.00029*t)*cos(M2)-0.0904*cos(2.0*M1))*ARCSEC_TO_RAD;

	/* Compute mean obliquity */

	t2=t/100.0;
	tmp=t2*(27.87+t2*(5.79+t2*2.45));
	tmp=t2*(-249.67+t2*(-39.05+t2*(7.12+tmp)));
	tmp=t2*(-1.55+t2*(1999.25+t2*(-51.38+tmp)));
	tmp=(t2*(-4680.93+tmp))/3600.0;
	meanObliquity=(23.4392911111111+tmp)*DEG_TO_RAD;

	/* Obtain local apparent sidereal time */

	jd0=floor(jd_UT-0.5)+0.5;
	T0=(jd0-J2000)/JULIAN_DAYS_PER_CENTURY;
	secs=(jd_UT-jd0)*SECONDS_PER_DAY;
	gmst=(((((-6.2e-6*T0)+9.3104e-2)*T0)+8640184.812866)*T0)+24110.54841;
	msday=1.0+(((((-1.86e-5*T0)+0.186208)*T0)+8640184.812866)/(SECONDS_PER_DAY*JULIAN_DAYS_PER_CENTURY));
	gmst=(gmst+msday*secs)*(15.0/3600.0)*DEG_TO_RAD;
	lst=normalizeRadians(gmst+obsLon+nutLon*cos(meanObliquity+nutObl));
}

double getJulianDay(void)
{
	/* Read the system clock and return
	   the current Julian Day Number. */

	struct timeval tptr;
	double usecs, seconds;

	(void)gettimeofday(&tptr,NULL);
	usecs=0.000001*(double)tptr.tv_usec;
	seconds=usecs+(double)tptr.tv_sec;

	return (2440587.5+(seconds/86400.0));
	// return (0.352+(2440587.5+(seconds/86400.0)));
}

struct intArray getDate(double jd)
{
	/* The conversion formulas are from Meeus, Chapter 7. */

	double A, B, F, Z, exactDay, h, m;
	int a, C, D, E, day, month, year, hour, minute, second;

	struct intArray dateValues;

	Z=floor(jd+0.5);
	F=jd+0.5-Z;
	A=Z;

	if (Z>=2299161)  // WAS 2299161D
	{
		a=(int)((Z-1867216.25)/36524.25);
		A+=1+a-a/4;
	}

	B=A+1524.0;
	C=(int)((B-122.1)/365.25);
	D=(int)(C*365.25);
	E=(int)((B-D)/30.6001);

	exactDay=F+B-D-(int)(30.6001*E);
	day=(int)exactDay;
	month=(E<14) ? E-1 : E-13;
	year=C-4715;

	if (month>2)
		year--;

	h=((exactDay-day)*SECONDS_PER_DAY)/3600.0;
		
	hour=(int)h;
	m=(h-hour)*60.0;
	minute=(int)m;
	second=(int)((m-minute)*60.0);

	dateValues.var1=year;
	dateValues.var2=month;
	dateValues.var3=day;
	dateValues.var4=hour;
	dateValues.var5=minute;
	dateValues.var6=second;

	return dateValues;
}

void SunMoonCalculator(double obsLon, double obsLat)
{
	/* Performs Sun/Moon calculations. Time should be read in UTC,
	   with observer angles (Longitude and Latitude) in radians. */

	double c, x, x2, x3, x4, u, jd, ndot, tmp, c0;
	int year, month, day;
	struct intArray dateInfo;

	jd=getJulianDay();
	dateInfo=getDate(jd);

	year=dateInfo.var1;
	month=dateInfo.var2;
	day=dateInfo.var3;

	ndot=-25.858;
	c0=0.91072*(ndot+26.0);

	if (year<-500 || year>=2200)
	{
		u=(jd-2385800.5)/36525.0; // centuries since J1820
		TTminusUT=-20.0+32.0*u*u;
	}

	else
	{
		x=year+(month-1+(day-1)/30.0)/12.0;
		x2=x*x;
		x3=x2*x;
		x4=x3*x;

		if (year<1600)
			TTminusUT=10535.328003-9.9952386275*x+0.00306730763*x2-7.7634069836E-6*x3+3.1331045394E-9*x4+8.2255308544E-12*x2*x3-7.4861647156E-15*x4*x2+1.936246155E-18*x4*x3-8.4892249378E-23*x4*x4;

		else
			TTminusUT=-1027175.34776+2523.2566254*x-1.8856868491*x2+5.8692462279E-5*x3+3.3379295816E-7*x4+1.7758961671E-10*x2*x3-2.7889902806E-13*x2*x4+1.0224295822E-16*x3*x4-1.2528102371E-20*x4*x4;

	}

	c0=0.91072*(ndot+25.858);
	tmp=(jd-2435109.0)/36525.0;
	c=-c0*(tmp*tmp);

	if (year<1955 || year>2005)
		TTminusUT+=c;

	setUTDate(jd);
}

struct doubleArray getSun(void)
{
	/* Returns the ecliptic longitude and latitude,
	  the distace and the angular radius of the Sun. */

	double	L=0.0, R=0.0, t2, v, u, vp, up, lon, dlon, aberration, slongitude, slatitude,
		 sdistance, Lp=0.0, deltat=0.5, t2p;
	int i;

	struct	doubleArray sun;

	t2=t*0.01;
	t2p=(t+deltat/JULIAN_DAYS_PER_CENTURY)*0.01;

	for (i=0; i<50; i++)
	{
		v=sun_elements[i][2]+sun_elements[i][3]*t2;
		u=normalizeRadians(v);
		L=L+sun_elements[i][0]*sin(u);
		R=R+sun_elements[i][1]*cos(u);
			
		vp=sun_elements[i][2]+sun_elements[i][3]*t2p;
		up=normalizeRadians(vp);
		Lp=Lp+sun_elements[i][0]*sin(up);
	}

	lon=normalizeRadians(4.9353929+normalizeRadians(62833.196168*t2)+L/10000000.0)*RAD_TO_DEG;
	sdistance=1.0001026+R/10000000.0;
		
	/* Now subtract aberration */

	dlon=((Lp-L)/10000000.0+62833.196168*(t2p-t2))/deltat;
	aberration=dlon*sdistance*LIGHT_TIME_DAYS_PER_AU;
	lon-=aberration*RAD_TO_DEG;

	slongitude=lon*DEG_TO_RAD; // apparent longitude (error<0.001 deg)
	slatitude=0; // Sun's ecliptic latitude is always negligible

	sun.var1=slongitude;
	sun.var2=slatitude;
	sun.var3=sdistance;
	sun.var4=atan(SUN_RADIUS/(AU*sdistance));

	return sun;
}

struct doubleArray getMoon(void)
{
	/* Returns the ecliptic longitude and latitude,
	   the distance and the angular radius of the Moon. */

	double	x, l, phase, node, anomaly, sanomaly, E, latitude,
		longitude, parallax, distance;

	struct  doubleArray moon;

	/* These expansions up to t^7 for the mean elements are taken
	from S. L. Moshier, see program cmoon */

	/* Mean elongation of moon = D */

	x=(1.6029616009939659e+09*t+1.0722612202445078e+06);
	x+=(((((-3.207663637426e-013*t+2.555243317839e-011)*t+2.560078201452e-009)*t-3.702060118571e-005)*t+6.9492746836058421e-03)*t-6.7352202374457519e+00)*t*t;

	phase=normalizeRadians(ARCSEC_TO_RAD*x);

	/* Mean distance of moon from its ascending node = F */

	x=(1.7395272628437717e+09*t+3.3577951412884740e+05);
	x+=(((((4.474984866301e-013*t+4.189032191814e-011)*t-2.790392351314e-009)*t-2.165750777942e-006)*t-7.5311878482337989e-04)*t-1.3117809789650071e+01)*t*t;

	node=normalizeRadians(ARCSEC_TO_RAD*x);

	/* Mean anomaly of sun = l' (J. Laskar) */

	x=(1.2959658102304320e+08*t+1.2871027407441526e+06);

	x+=((((((((1.62e-20*t-1.0390e-17)*t-3.83508e-15)*t+4.237343e-13)*t+8.8555011e-11)*t-4.77258489e-8)*t-1.1297037031e-5)*t+8.7473717367324703e-05)*t-5.5281306421783094e-01)*t*t;

	sanomaly=normalizeRadians(ARCSEC_TO_RAD*x);

	/* Mean anomaly of moon = l */

	x=(1.7179159228846793e+09*t+4.8586817465825332e+05);
	x+=(((((-1.755312760154e-012*t+3.452144225877e-011)*t-2.506365935364e-008)*t-2.536291235258e-004)*t+5.2099641302735818e-02)*t+3.1501359071894147e+01)*t*t;

	anomaly=normalizeRadians(ARCSEC_TO_RAD*x);

	/* Mean longitude of moon, re mean ecliptic and equinox of date = L */

	x=(1.7325643720442266e+09*t+7.8593980921052420e+05);
	x+=(((((7.200592540556e-014*t+2.235210987108e-010)*t-1.024222633731e-008)*t-6.073960534117e-005)*t+6.9017248528380490e-03)*t-5.6550460027471399e+00)*t*t;

	l=normalizeRadians(ARCSEC_TO_RAD*x)*RAD_TO_DEG;

	/* Now longitude, with the three main correcting terms of
	evection, variation, and equation of year, plus other terms
	(error<0.01 deg) P. Duffet's MOON program taken as reference
	for the periodic terms */

	E=1.0-(0.002495+7.52E-06*(t+1.0))*(t+1.0);
	l+=6.28875*sin(anomaly)+1.274018*sin(2.0*phase-anomaly)+0.658309*sin(2.0*phase);
	l+=0.213616*sin(2.0*anomaly)-E*0.185596*sin(sanomaly)-0.114336*sin(2.0*node);
	l+=0.058793*sin(2.0*phase-2.0*anomaly)+0.057212*E*sin(2.0*phase-anomaly-sanomaly)+0.05332*sin(2.0*phase+anomaly);
	l+=0.045874*E*sin(2.0*phase-sanomaly)+0.041024*E*sin(anomaly-sanomaly)-0.034718*sin(phase)-E*0.030465*sin(sanomaly+anomaly);
	l+=0.015326*sin(2.0*(phase-node))-0.012528*sin(2.0*node+anomaly)-0.01098*sin(2.0*node-anomaly)+0.010674*sin(4.0*phase-anomaly);
	l+=0.010034*sin(3.0*anomaly)+0.008548*sin(4.0*phase-2.0*anomaly);
	l+=-E*0.00791*sin(sanomaly-anomaly+2.0*phase)-E*0.006783*sin(2.0*phase+sanomaly)+0.005162*sin(anomaly-phase)+E*0.005*sin(sanomaly+phase);
	l+=0.003862*sin(4.0*phase)+E*0.004049*sin(anomaly-sanomaly+2.0*phase)+0.003996*sin(2.0*(anomaly+phase))+0.003665*sin(2.0*phase-3.0*anomaly);
	l+=E*2.695E-3*sin(2.0*anomaly-sanomaly)+2.602E-3*sin(anomaly-2.0*(node+phase));
	l+=E*2.396E-3*sin(2.0*(phase-anomaly)-sanomaly)-2.349E-3*sin(anomaly+phase);
	l+=E*E*2.249E-3*sin(2.0*(phase-sanomaly))-E*2.125E-3*sin(2.0*anomaly+sanomaly);
	l+=-E*E*2.079E-3*sin(2.0*sanomaly)+E*E*2.059E-3*sin(2.0*(phase-sanomaly)-anomaly);
	l+=-1.773E-3*sin(anomaly+2.0*(phase-node))-1.595E-3*sin(2*(node+phase));
	l+=E*1.22E-3*sin(4.0*phase-sanomaly-anomaly)-1.11E-3*sin(2.0*(anomaly+node));

	longitude=l*DEG_TO_RAD;
				
	/* Moon parallax */

	parallax=0.950724+0.051818*cos(anomaly)+0.009531*cos(2.0*phase-anomaly);
	parallax+=0.007843*cos(2.0*phase)+0.002824*cos(2.0*anomaly);
	parallax+=0.000857*cos(2.0*phase+anomaly)+E*0.000533*cos(2.0*phase-sanomaly);
	parallax+=E*0.000401*cos(2.0*phase-anomaly-sanomaly)+E*0.00032*cos(anomaly-sanomaly)-0.000271*cos(phase);
	parallax+=-E*0.000264*cos(sanomaly+anomaly)-0.000198*cos(2.0*node-anomaly);
	parallax+=1.73E-4*cos(3.0*anomaly)+1.67E-4*cos(4.0*phase-anomaly);

	/* Moon distance in Earth radii is, more or less */

	distance=1.0/sin(parallax*DEG_TO_RAD);

	/* Ecliptic latitude with nodal phase (error<0.01 deg) */

	l=5.128189*sin(node)+0.280606*sin(node+anomaly)+0.277693*sin(anomaly-node);
	l+=0.173238*sin(2.0*phase-node)+0.055413*sin(2.0*phase+node-anomaly);
	l+=0.046272*sin(2.0*phase-node-anomaly)+0.032573*sin(2.0*phase+node);
	l+=0.017198*sin(2.0*anomaly+node)+0.009267*sin(2.0*phase+anomaly-node);
	l+=0.008823*sin(2.0*anomaly-node)+E*0.008247*sin(2.0*phase-sanomaly-node)+0.004323*sin(2.0*(phase-anomaly)-node);
	l+=0.0042*sin(2.0*phase+node+anomaly)+E*0.003372*sin(node-sanomaly-2.0*phase);
	l+=E*2.472E-3*sin(2.0*phase+node-sanomaly-anomaly);
	l+=E*2.222E-3*sin(2.0*phase+node-sanomaly);
	l+=E*2.072E-3*sin(2.0*phase-node-sanomaly-anomaly);

	latitude=l*DEG_TO_RAD;

	moon.var1=longitude;
	moon.var2=latitude;
	moon.var3=distance*EARTH_RADIUS/AU;
	moon.var4=atan(MOON_RADIUS/(distance*EARTH_RADIUS));

	return moon;
}

double getTwilightEvent(double celestialHoursToEarthTime, double ra, double angh)
{
	double	jdToday_UT, eventTime, eventTimePrev, eventDatePrev_UT,
		eventDate_UT, eventDatePrev_LT, eventTimeNext,
		eventDateNext_LT, eventDate_LT, jdToday_LT;

	jdToday_UT=floor(jd_UT-0.5)+0.5;
		
	eventTime=celestialHoursToEarthTime*normalizeRadians(ra+angh-lst);
	eventTimePrev=eventTime-celestialHoursToEarthTime*TWO_PI;
	eventDatePrev_UT=floor(jd_UT+eventTimePrev-0.5)+0.5;

	if (twilightMode==CLOSEST && fabs(eventTimePrev)<fabs(eventTime))
		eventTime = eventTimePrev;

	if (twilightMode==TODAY_UT)
	{
		eventDate_UT=floor(jd_UT+eventTime-0.5)+0.5;

		if (jdToday_UT!=eventDate_UT)
			eventTime=-jd_UT-1;

		if (jdToday_UT==eventDatePrev_UT)
			eventTime=eventTimePrev;
	}

	/**
	if (twilightMode==TODAY_LT)
	{
		// tz=TWILIGHT_MODE.timeZone/24.0;

		tz=-4.0/24.0;  // For TESTING purposes...
 
		jdToday_LT=floor(jd_UT+tz-0.5)+0.5;

		eventDate_LT=floor(jd_UT+tz+eventTime-0.5)+0.5;

		if (jdToday_LT!=eventDate_LT)
			eventTime=-jd_UT-1;
			
		eventDatePrev_LT=floor(jd_UT+tz+eventTimePrev-0.5)+0.5;

		if (jdToday_LT==eventDatePrev_LT)
			eventTime=eventTimePrev;
			
		eventTimeNext=celestialHoursToEarthTime*(normalizeRadians(ra+angh-lst)+TWO_PI);
		eventDateNext_LT=floor(jd_UT+tz+eventTimeNext-0.5)+0.5;

		if (jdToday_LT==eventDateNext_LT)
			eventTime=eventTimeNext;
	}
	**/

	if (twilightMode==TODAY_LT)
	{
		jdToday_LT=floor(jd_UT-0.5)+0.5;

		eventDate_LT=floor(jd_UT+eventTime-0.5)+0.5;

		if (jdToday_LT!=eventDate_LT)
			eventTime=-jd_UT-1;
			
		eventDatePrev_LT=floor(jd_UT+eventTimePrev-0.5)+0.5;

		if (jdToday_LT==eventDatePrev_LT)
			eventTime=eventTimePrev;
			
		eventTimeNext=celestialHoursToEarthTime*(normalizeRadians(ra+angh-lst)+TWO_PI);
		eventDateNext_LT=floor(jd_UT+eventTimeNext-0.5)+0.5;

		if (jdToday_LT==eventDateNext_LT)
			eventTime=eventTimeNext;
	}
		
	return jd_UT+eventTime;
}

struct Ephemeris doCalc(struct doubleArray da)
{
	/* Converts the ecliptic longitude and latitude, the distance,
	   and the angular radius of the Moon or Sun into the final
	   coordinates azimuth and elevation, including right ascension
	   (RA) and declination (DEC). */

	/* Compute the position of the body.  Arguments include the
	   ecliptic longitude, latitude, distance and so on held in the
	   doubleArray structure.  Returns the Ephemeris structure with
	   the output position. */
 
	double	x, y, z, cl, tmp, sinLat, cosLat, radiusAU, sinEcl, dist,
		cosEcl, correction[3], xtopo, ytopo, ztopo, ra, dec, h,
		angh, sinDec, cosDec, alt, azx, azy, azi, siderealDayLength,
		celestialHoursToEarthTime, transit_alt, transit, rise,
		set, ang_hor, pos[4];

	struct Ephemeris eph;
	unsigned char geocentric=0;  /* 1 for topocentric... */

	pos[0]=da.var1;
	pos[1]=da.var2;
	pos[2]=da.var3;
	pos[3]=da.var4;
	
	/* Correct for nutation in longitude */

	pos[0]=pos[0]+nutLon;

	/* Ecliptic to equatorial coordinates using true obliquity */

	cl=cos(pos[1]);
	x=pos[2]*cos(pos[0])*cl;
	y=pos[2]*sin(pos[0])*cl;
	z=pos[2]*sin(pos[1]);
	sinEcl=sin(meanObliquity+nutObl);
	cosEcl=cos(meanObliquity+nutObl);
	tmp=y*cosEcl-z*sinEcl;
	z=y*sinEcl+z*cosEcl;
	y=tmp;

	/* Obtain topocentric rectangular coordinates */

	sinLat=sin(obsLat); 
	cosLat=cos(obsLat); 
	radiusAU=geocentric ? 0 : EARTH_RADIUS/AU;

	correction[0]=radiusAU*cosLat*cos(lst);
	correction[1]=radiusAU*cosLat*sin(lst);
	correction[2]=radiusAU*sinLat;

	xtopo=x-correction[0];
	ytopo=y-correction[1];
	ztopo=z-correction[2];

	/* Obtain topocentric equatorial coordinates */

	ra=0.0;
	dec=PI_OVER_TWO;

	if (ztopo<0.0)
		dec=-dec;

	if (ytopo!=0.0 || xtopo!=0.0)
	{
		ra=atan2(ytopo,xtopo);
		dec=atan2(ztopo/hypot(xtopo,ytopo),1.0);
	}

	dist=sqrt(xtopo*xtopo+ytopo*ytopo+ztopo*ztopo);

	/* Hour angle */

	angh=lst-ra;

	/* Obtain azimuth and geometric alt */

	sinDec=sin(dec);
	cosDec=cos(dec);
	h=sinLat*sinDec+cosLat*cosDec*cos(angh);
	alt=asin(h);
	azy=sin(angh);
	azx=cos(angh)*sinLat-sinDec*cosLat/cosDec;
	azi=PI+atan2(azy,azx); // 0 = north

	if (geocentric)
	{
		eph.azimuth=azi;
		eph.elevation=alt;
		// eph.rise=-1.0;
		// eph.set=-1.0;
		eph.rise=0.0;
		eph.set=0.0;
		eph.transit=-1.0;
		eph.transitElevation=-1.0;
		eph.rightAscension=normalizeRadians(ra);
		eph.declination=dec;
		eph.distance=dist;
		eph.eclipticLongitude=pos[0];
		eph.eclipticLatitude=pos[1];
		eph.angularRadius=pos[3];

		return eph;
	}	

	/* Get apparent elevation */
	/* alt = refraction(alt); */
		
	switch (twilight)
	{
		case HORIZON_34arcmin:
			/* Rise, set, transit times, taking into account Sun/Moon angular radius (pos[3]).
			   The 34' factor is the standard refraction at horizon.
			   Removing angular radius will do calculations for the center of the disk instead
			   of the upper limb. */

			/* tmp=-(34.0/60.0)*DEG_TO_RAD-pos[3]; */
			tmp=-DEG_TO_RAD;
			break;

		case CIVIL:
			tmp=-6*DEG_TO_RAD;
			break;

		case NAUTICAL:
			tmp=-12*DEG_TO_RAD;
			break;

		case ASTRONOMICAL:
			tmp=-18*DEG_TO_RAD;
			break;
	}
		
	/* Compute cosine of hour angle */

	tmp=(sin(tmp)-sinLat*sinDec)/(cosLat*cosDec);

	/* Length of a sidereal day in days according to IERS Conventions. */

	siderealDayLength=1.00273781191135448;
	celestialHoursToEarthTime=1.0/(siderealDayLength*TWO_PI);

	/* Make calculations for the meridian*/

	transit_alt=asin(sinDec*sinLat+cosDec*cosLat);
	/* transit_alt = refraction(transit_alt); */

	/* Obtain the current transit event in time */

	transit=getTwilightEvent(celestialHoursToEarthTime,ra,0);

	/* Make calculations for rise and set */

	// rise=-1.0;
	// set=-1.0;

	rise=0.0;
	set=0.0;

	if (fabs(tmp)<=1.0)
	{
		ang_hor=fabs(acos(tmp));
		rise=getTwilightEvent(celestialHoursToEarthTime,ra,-ang_hor);
		set=getTwilightEvent(celestialHoursToEarthTime,ra,ang_hor);
	}

	eph.azimuth=azi;
	eph.elevation=alt;
	eph.rise=rise;
	eph.set=set;
	eph.transit=transit;
	eph.transitElevation=transit_alt;
	eph.rightAscension=normalizeRadians(ra);
	eph.declination=dec;
	eph.distance=dist;
	eph.eclipticLongitude=pos[0];
	eph.eclipticLatitude=pos[1];
	eph.angularRadius=pos[3];

	return eph;
}

char *Daynum2String (double daynum)
{
	/* This function takes the given Julian day number
	   and returns the corresponding date as a string
	   of the form "Tue 12Oct99 17:22:37". */

	time_t t;
	struct tm *timeptr;
	static char timestr[26];

	daynum-=2440587.5;

	t=(time_t)(86400.0*daynum);
	timeptr=gmtime(&t);
	strftime(timestr,sizeof(timestr),"%a %d%b%y %T", timeptr);

	return timestr;
}

char *eta_clock(unsigned seconds)
{
	/* Number of seconds --> HH:MM:SS (string) */

	static char output[30];
	unsigned hh, mm, ss;

	hh=seconds/3600;
	mm=(seconds%3600)/60;
	ss=seconds%60;
	
	sprintf(output,"%02u:%02u:%02u%c",hh,mm,ss,0);

	return output;
}

void TrackDataNet(int sockd, double elevation, double azimuth)
{
	int len;
	char message[20]={0};

	/* If positions are sent too often, rotctld will queue
	   them and the antenna will lag behind. Therefore, we wait
	   for confirmation from last command before sending the
	   next. */

	while (recv(sockd, message, sizeof(message), MSG_DONTWAIT) < 1);
	
	len=snprintf(message,20,"P %.2f %.2f\n", azimuth, elevation);

	if (send(sockd, message, len, 0)!=len)
	{
		fprintf(stderr,"*** Failed to send to rotctld!\n");
		exit(-1);
	}
}

void set_non_blocking_mode(void)
{
	/* Puts the keyboard into non-blocking
	   mode so that the program can respond
	   immediately a single keystroke. */

	int flags;
	struct termios ttystate;

	/* Read and save the current terminal state */

	tcgetattr(STDIN_FILENO, &ttystate);
	tcgetattr(STDIN_FILENO, &orig_state);	
    
	/* Disable canonical mode (line-buffering) and echo */

	ttystate.c_lflag &= ~ICANON;
	ttystate.c_lflag &= ~ECHO;
    
	/* Set immediate character availability */

	ttystate.c_cc[VMIN]=0;
	ttystate.c_cc[VTIME]=0;
    
	/* Apply the modified attributes */

	tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);

	/* Set stdin file descriptor to non-blocking */

	flags=fcntl(STDIN_FILENO, F_GETFL, 0);
	fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
}

char *strncpy2(char *dest, const char *src, unsigned n)
{
	unsigned i;

	for (i=0; i<n && src[i]!=0; i++)
		dest[i]=src[i];

	dest[i]=0;

	return dest;
}

char ReadQTH(char *qthfile)
{
	/* This function reads the tracking station's latitude
	   and longitude information from PREDICT's predict.qth
	   file, or any other file passed via the command line. */

	FILE *fd;
	char success=0;

	fd=fopen(qthfile,"r");

	if (fd!=NULL)
	{
		fgets(callsign,16,fd);
		callsign[strlen(callsign)-1]=0;
		fscanf(fd,"%lf", &qthlat);
		fscanf(fd,"%lf", &qthlong);
		fscanf(fd,"%d", &qthalt);

		fclose(fd);

		success=1;
	}

	return success;
}

void usage(void)
{
	/* Inform the human about how all this stuff works... */

	fprintf(stderr,"\n\t\033[93m--==[ MoonTracker %s ]==--\033[m\n",version);
	fprintf(stderr,"\n\t\033[94m   ...Available options...\033[m\n\n");
	fprintf(stderr,"\t\033[94m-h  sets an alternate hostname (localhost)\033[m\n");
	fprintf(stderr,"\t\033[94m-p  sets an alternate network port (4533)\033[m\n");
	fprintf(stderr,"\t\033[94m-q  sets an alternate qth file (predict.qth)\033[m\n");
	fprintf(stderr,"\t\033[94m-u  sets an alternate update interval (5)\033[m\n");
	fprintf(stderr,"\t\033[94m-s  track the Sun instead of the Moon\033[m\n");
	fprintf(stderr,"\t\033[94m-v  displays this information\033[m\n\n");

	fprintf(stderr,"\033[92mMoonTracker tracks the Moon (or Sun) and sends tracking data\033[m\n");
	fprintf(stderr,"\033[92mto an AZ/EL rotator using Hamlib's TCP rotator control daemon.\033[m\n\n");
	fprintf(stderr,"As such, you must run: \"rotctld\" \033[94m(plus options specific to your station)\033[m\n\n");
	fprintf(stderr,"\033[92min the background or on a separate terminal prior to starting MoonTracker.\033[m\n\n");
	fprintf(stderr,"Please refer to Hamlib's documentation for more information:\n");
	fprintf(stderr,"\thttps://github.com/Hamlib/Hamlib/wiki/Hamlib\n\n");

	fflush(stderr);
}

int main(int argc, char *argv[])
{
	int x, y, z, rotctld_socket, keystrokes;
	double jd, moon_rise, moon_rise_az, sun_rise, sun_rise_az;
	struct Ephemeris moon, sun;
	struct addrinfo hints, *servinfo, *servinfop;
	unsigned snooze, update_interval, sleep_count;
	char rotctld_host[256]={0}, rotctld_port[6]={0},
	     target[5], *env=NULL, qthfile[80], ch=0, first_move=0;

	/* Set some defaults */

	update_interval=5;
	env=getenv("HOME");
	strncpy2(target,"Moon",4);
	strncpy2(rotctld_port,"4533",4);
	strncpy2(rotctld_host,"localhost\0",10);
	snprintf(qthfile,80,"%s/.predict/predict.qth",env);

	/* Interpret any options passed via the command-line. */

	y=argc-1;

	for (x=1; x<=y; x++)
	{
		if (strcmp(argv[x],"-q")==0)
		{
			z=x+1;
			if (z<=y && argv[z][0] && argv[z][0]!='-')
				strncpy2(qthfile,argv[z],78);
		}

		if (strcmp(argv[x],"-h")==0)
		{
			z=x+1;
			if (z<=y && argv[z][0] && argv[z][0]!='-')
				strncpy2(rotctld_host,argv[z],255);
		}

		if (strcmp(argv[x],"-p")==0)
		{
			z=x+1;
			if (z<=y && argv[z][0] && argv[z][0]!='-')
				strncpy2(rotctld_port,argv[z],5);
		}

		if (strcmp(argv[x],"-u")==0)
		{
			z=x+1;
			if (z<=y && argv[z][0] && argv[z][0]!='-')
				update_interval=(unsigned)abs(atoi(argv[z]));
		}

		if (strcmp(argv[x],"-s")==0)
			strncpy2(target,"Sun",3);

		if ((strcmp(argv[x],"-v")==0) || (strcmp(argv[x],"-help")==0) || (strcmp(argv[x],"--help")==0))
		{
			usage();
			exit(0);
		}
	}

	if (ReadQTH(qthfile)==0)
	{
		fprintf(stderr,"%c*** Error: QTH file \"%s\" could not be loaded!\n",7,qthfile);
		exit(-1);
	}

	obsLat=qthlat*DEG_TO_RAD;
	obsLon=DEG_TO_RAD*(qthlong>0.0 ? 360.0-qthlong : -qthlong);

	rotctld_socket=-1;

	memset(&hints, 0, sizeof hints);
	hints.ai_family=AF_UNSPEC;
	hints.ai_socktype=SOCK_STREAM;

	/* Create the network socket and connect to rotctld. */

	if (rotctld_host[0]!=0)
	{
		if (getaddrinfo(rotctld_host, rotctld_port, &hints, &servinfo))
		{
			fprintf(stderr,"*** getaddrinfo error!\n");
			exit(-1);
		}

		for (servinfop=servinfo; servinfop!=NULL; servinfop=servinfop->ai_next)
		{
			if ((rotctld_socket=socket(servinfop->ai_family, servinfop->ai_socktype,servinfop->ai_protocol))==-1)
				continue;

			if (connect(rotctld_socket, servinfop->ai_addr, servinfop->ai_addrlen)==-1)
			{
				close(rotctld_socket);
				continue;
			}

			break;
		}

		if (servinfop==NULL)
		{
			fprintf(stderr,"*** Unable to connect to rotctld!\n");
			exit(-1);
		}

		freeaddrinfo(servinfo);

		/* TrackDataNet() will wait for confirmation of a command
		   before sending the next so we bootstrap this by asking
		   for the current position. */

		send(rotctld_socket, "p\n", 2, 0);
	}

	if (rotctld_socket!=-1)
	{
		/* We are ready to roll! :-) */

		/* If we're in an xterm, display the
		   application's name in the frame header. */

		env=getenv("TERM");

		if (env!=NULL && strncmp(env,"xterm",5)==0)
			fprintf(stdout,"\033]0;MoonTracker %s\007",version);

		/* Clear and reset the terminal */

		fprintf(stdout,"\033[H\033[2J");

		/* Put terminal (keyboard input) into non-blocking mode */

		set_non_blocking_mode();

		/* Turn the cursor off */

		fprintf(stdout,"\033[?25l");

		/* Display the banner */

		fprintf(stdout,"\n\n\n\n\n\n\033[93m\t\t    ************************************\033[m\n");
		fprintf(stdout,"\033[93m\t\t    *** Welcome to MoonTracker %s! ***\033[m\n",version);
		fprintf(stdout,"\033[93m\t\t    ************************************\033[m\n\n");

		/* Display some info */

		fprintf(stdout,"\033[96m\t    MoonTracker is connected to \"%s\" on port %s\033[m\n",rotctld_host, rotctld_port);

		if (update_interval>1)
			fprintf(stdout,"\033[96m\t   and will send rotator position updates every %u seconds",update_interval);

		else
		{
			fprintf(stdout,"\033[96m\t    and will send rotator position updates every second");
			update_interval=1;
		}

		fprintf(stdout,"\n\t  while the %s is above your horizon.  Press [ESC] to quit!\033[m\n\n",target);

		sleep_count=0;

		/**** Lunar Tracking Routines ****/

		if (target[0]=='M')
		{
			/* Detemine the Moon's current position. */

			jd=getJulianDay();
			setUTDate(jd);
			SunMoonCalculator(obsLon, obsLat);
			moon=doCalc(getMoon());

			/* If the Moon is above the horizon, find out
			   when and where (azimuth) it will set. */

			if (moon.elevation>0.0)
			{
				fprintf(stdout,"\033[94m      The Moon will set on %s UTC at ",Daynum2String(moon.set));

				/* Find the Moon's azimuth at set time */

				setUTDate(moon.set);
				moon=doCalc(getMoon());

				fprintf(stdout,"%.2f%c%c azimuth.\033[m\n\n",moon.azimuth*RAD_TO_DEG,194,176);

				/* Get things back into sync
				   with the current date/time */

				jd=getJulianDay();
				setUTDate(jd);
				SunMoonCalculator(obsLon, obsLat);
				moon=doCalc(getMoon());
			}

			/* If the Moon is below the horizon, find out
			   when and where (azimuth) it will rise. */

			if (moon.elevation<0.0)
			{
				jd=getJulianDay()+1.0;  /* Move ahead one day */
				setUTDate(jd);
				SunMoonCalculator(obsLon, obsLat);
				moon=doCalc(getMoon());
				moon_rise=moon.rise;

				fprintf(stdout,"\033[94m      The Moon will rise on %s UTC at ",Daynum2String(moon_rise));

				/* Move the clock forward to moon_rise
				   to find the Moon's azimuth at rise time. */

				setUTDate(moon_rise);
				moon=doCalc(getMoon());

				moon_rise_az=moon.azimuth*RAD_TO_DEG;

				fprintf(stdout,"%.2f%c%c azimuth.\033[m\n\n",moon_rise_az,194,176);

				/* Get things back into sync
				with the current date/time */

				jd=getJulianDay();
				setUTDate(jd);

				/* Determine how long (seconds) we
				   have to wait for the Moon to rise. */

				snooze=(unsigned)(rint((moon_rise-jd)*86400.0));

				ch=0;

				/* Remain in this loop until either 2 minutes
				   before Moon rise, or the user wants to bail. */

				while (snooze>=120 && (ch!=27 && ch!='q' && ch!='Q'))
				{
					/* "Sleep" until 2 minutes before Moon rise. */

					SunMoonCalculator(obsLon, obsLat);
					moon=doCalc(getMoon());

					fprintf(stdout,"\033[94m\t   Current Lunar coordinates are: %.2f%c%c AZ and %+.2f%c%c EL\033[m\n",moon.azimuth*RAD_TO_DEG,194,176,moon.elevation*RAD_TO_DEG,194,176);

					fprintf(stdout,"\033[94m\t  MoonTracker is waiting for the Moon to rise in %s... \033[m", eta_clock(snooze));

					fflush(stdout);

					sleep(1);

					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */
					fflush(stdout);

					snooze--;

					jd=getJulianDay();
					setUTDate(jd);

					/* Scan the keyboard */

					do
					{
						keystrokes=read(STDIN_FILENO, &ch, 1);

					} while (keystrokes && (ch!=27 &&ch!='q' && ch!='Q'));
				}

				if (snooze<120)
				{
					/* Time to wake up.  Clear the
					previous two lines of text */

					fprintf(stdout,"\n\033[2K\r"); /* Clear to the beginning of the line */
					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */
					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */
					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */

					fprintf(stdout,"\033[94m      The Moon will set on %s UTC at ",Daynum2String(moon.set));

					/* Find the Moon's azimuth at set time */

					setUTDate(moon.set);
					moon=doCalc(getMoon());

					fprintf(stdout,"%.2f%c%c azimuth.\033[m\n\n",moon.azimuth*RAD_TO_DEG,194,176);
					fflush(stdout);

					/* Move the rotator in azimuth toward the direction of
					   the rising Moon.  Set the elevation to the horizon. */

					if (first_move==0)
					{
						TrackDataNet(rotctld_socket,0.0, moon_rise_az*RAD_TO_DEG);
						first_move=1;
					}
				}
			}

			ch=0;

			while (rotctld_socket!=-1 && (ch!=27 && ch!='q' && ch!='Q') && moon.elevation>=0.0)
			{
				/* Hello Moon!  Start live tracking. */

				/* Detemine the Moon's current position. */

				jd=getJulianDay();
				setUTDate(jd);
				SunMoonCalculator(obsLon, obsLat);
				moon=doCalc(getMoon());

				/* Inform the human */

				fprintf(stdout,"\033[92m  Tracking the Moon at %.2f%c%c AZ and %+.2f%c%c EL on %s UTC \033[m",moon.azimuth*RAD_TO_DEG,194,176,moon.elevation*RAD_TO_DEG,194,176,Daynum2String(jd));
				fflush(stdout);

				/* Send live tracking data to the rotator */

				if (sleep_count>=update_interval)
				{
					TrackDataNet(rotctld_socket,moon.elevation*RAD_TO_DEG, moon.azimuth*RAD_TO_DEG);
					sleep_count=0;
				}

				sleep_count++;
				sleep(1);

				fprintf(stdout,"\033[2K\r");	/* Clear to the beginning of the line */
				fflush(stdout);

				/* Scan the keyboard for any input */

				do
				{
					keystrokes=read(STDIN_FILENO, &ch, 1);

				} while (keystrokes && (ch!=27 &&ch!='q' && ch!='Q'));
			}
		}

		/**** Solar Tracking Routines ****/

		if (target[0]=='S')
		{
			/* Detemine the Sun's current position. */

			jd=getJulianDay();
			setUTDate(jd);
			SunMoonCalculator(obsLon, obsLat);
			sun=doCalc(getSun());

			/* If the Sun is above the horizon, find out
			   when and where (azimuth) it will set. */

			if (sun.elevation>0.0)
			{
				fprintf(stdout,"\033[94m      The Sun will set on %s UTC at ",Daynum2String(sun.set));

				/* Find the Sun's azimuth at set time */

				setUTDate(sun.set);
				sun=doCalc(getSun());

				fprintf(stdout,"%.2f%c%c azimuth.\033[m\n\n",sun.azimuth*RAD_TO_DEG,194,176);

				/* Get things back into sync
				   with the current date/time */

				jd=getJulianDay();
				setUTDate(jd);
				SunMoonCalculator(obsLon, obsLat);
				sun=doCalc(getSun());
			}

			/* If the Sun is below the horizon, find out
			   when and where (azimuth) it will rise. */

			if (sun.elevation<0.0)
			{
				jd=getJulianDay()+1.0;  /* Move ahead one day */
				setUTDate(jd);
				SunMoonCalculator(obsLon, obsLat);
				sun=doCalc(getSun());
				sun_rise=sun.rise;

				fprintf(stdout,"\033[94m      The Sun will rise on %s UTC at ",Daynum2String(sun_rise));

				/* Move the clock forward to sun_rise
				   to find the Sun's azimuth at rise time. */

				setUTDate(sun_rise);
				sun=doCalc(getSun());

				sun_rise_az=sun.azimuth*RAD_TO_DEG;

				fprintf(stdout,"%.2f%c%c azimuth.\033[m\n\n",sun_rise_az,194,176);

				/* Get things back into sync
				with the current date/time */

				jd=getJulianDay();
				setUTDate(jd);

				/* Determine how long (seconds) we
				   have to wait for the Moon to rise. */

				snooze=(unsigned)(rint((sun_rise-jd)*86400.0));

				ch=0;

				/* Remain in this loop until either 2 minutes
				   before Sun rise, or the user wants to bail. */

				while (snooze>=120 && (ch!=27 && ch!='q' && ch!='Q'))
				{
					/* "Sleep" until 2 minutes before Moon rise. */

					SunMoonCalculator(obsLon, obsLat);
					sun=doCalc(getSun());

					fprintf(stdout,"\033[94m\t   Current Solar coordinates are: %.2f%c%c AZ and %+.2f%c%c EL\033[m\n",sun.azimuth*RAD_TO_DEG,194,176,sun.elevation*RAD_TO_DEG,194,176);

					fprintf(stdout,"\033[94m\t  MoonTracker is waiting for the Sun to rise in %s... \033[m", eta_clock(snooze));

					fflush(stdout);

					sleep(1);

					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */
					fflush(stdout);

					snooze--;

					jd=getJulianDay();
					setUTDate(jd);

					/* Scan the keyboard */

					do
					{
						keystrokes=read(STDIN_FILENO, &ch, 1);

					} while (keystrokes && (ch!=27 &&ch!='q' && ch!='Q'));
				}

				if (snooze<120)
				{
					/* Time to wake up.  Clear the
					previous two lines of text */

					fprintf(stdout,"\n\033[2K\r"); /* Clear to the beginning of the line */
					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */
					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */
					fprintf(stdout,"\033[1A");  /* Move up one line */
					fprintf(stdout,"\033[2K\r"); /* Clear to the beginning of the line */

					fprintf(stdout,"\033[94m      The Sun will set on %s UTC at ",Daynum2String(sun.set));

					/* Find the Sun's azimuth at set time */

					setUTDate(sun.set);
					sun=doCalc(getSun());

					fprintf(stdout,"%.2f%c%c azimuth.\033[m\n\n",sun.azimuth*RAD_TO_DEG,194,176);
					fflush(stdout);

					/* Move the rotator in azimuth toward the direction of
					   the rising Sun.  Set the elevation to the horizon. */

					if (first_move==0)
					{
						TrackDataNet(rotctld_socket,0.0, sun_rise_az*RAD_TO_DEG);
						first_move=1;
					}
				}
			}

			ch=0;

			while (rotctld_socket!=-1 && (ch!=27 && ch!='q' && ch!='Q') && sun.elevation>=0.0)
			{
				/* Here comes the Sun!  Start live tracking. */

				/* Detemine the Sun's current position. */

				jd=getJulianDay();
				setUTDate(jd);
				SunMoonCalculator(obsLon, obsLat);
				sun=doCalc(getSun());

				/* Inform the human */

				fprintf(stdout,"\033[92m  Tracking the Sun at %.2f%c%c AZ and %+.2f%c%c EL on %s UTC \033[m",sun.azimuth*RAD_TO_DEG,194,176,sun.elevation*RAD_TO_DEG,194,176,Daynum2String(jd));
				fflush(stdout);

				/* Send live tracking data to the rotator */

				if (sleep_count>=update_interval)
				{
					TrackDataNet(rotctld_socket,sun.elevation*RAD_TO_DEG, sun.azimuth*RAD_TO_DEG);
					sleep_count=0;
				}

				sleep_count++;
				sleep(1);

				fprintf(stdout,"\033[2K\r");	/* Clear to the beginning of the line */
				fflush(stdout);

				/* Scan the keyboard for any input */

				do
				{
					keystrokes=read(STDIN_FILENO, &ch, 1);

				} while (keystrokes && (ch!=27 && ch!='q' && ch!='Q'));
			}
		}
	}

	/* We're outta here! */

	/* Place the terminal (keyboard) back into its original state */

	tcsetattr(STDIN_FILENO, TCSANOW, &orig_state);

	fprintf(stdout,"\n\033[2K\r");	/* Clear to the beginning of the line */
	fprintf(stdout,"\033[1A");	/* Move up one line */
	fprintf(stdout,"\033[2K\r");	/* Clear to the beginning of the line */
	// fprintf(stdout,"\033[2K\r");	/* Clear to the beginning of the line */

	/* Turn the cursor back on and say goodbye*/

	fprintf(stdout,"\033[?25h\t\t\t\t--== 73! ==--\n\n\n\n");

	/* Close the rotator network socket */

	close(rotctld_socket);

	return 0;
}

