/*
 *   Copyright (C) 1991-2000 by Jonathan Naylor HB9DRD/G4KLX
 *
 *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>

#include <gtk/gtk.h>

#include "global.h"

static double Track_Day_Time;
static double Elapsed_Time;
static struct tm Current_Time;

static double Azimuth;
static double Elevation;
static double Range;
static double Half_Angle;
static double SSP_Lat;
static double SSP_Long;
static double Orbit_No;
static double SMA;
static double Height;
static double Arg_Of_Perigee;
static double Mean_Anomoly;
static double RAAN;
static int    MA;
static char   Mode[6];
static double Squint;

static double Precession;
static double Station_Earth_X;
static double Station_Earth_Y;
static double Station_Earth_Z;
static double Sidereal_Epoch;
static double Sidereal_Constant;

static void Calculate_Initial_Data(void);
static void Calculate_Times(long);
static void Calculate_Satellite_Position(void);
static void Display_Track_Data(void);
static void Display_List_Data(GtkWidget *);
static int  Year_Conversion(int);

void Track_Satellite(time_t Track_Time)
{
	Calculate_Initial_Data();

	Calculate_Times(Track_Time);

	Calculate_Satellite_Position();

	Display_Track_Data();
}

void List_Satellite(time_t Start, time_t End, int Step, double Min_Elevation)
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *listlist, *listwin;
	GtkWidget *separator;
	GtkWidget *bbox;
	GtkWidget *button[2];
	char *title[10];
	time_t Track_Time;

	window = gtk_window_new(GTK_WINDOW_DIALOG);

	gtk_window_set_title(GTK_WINDOW(window), "Tabular Track");
	gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH);

	vbox = gtk_vbox_new(FALSE, BORDER_WIDTH);
	gtk_container_add(GTK_CONTAINER(window), vbox);

	title[0] = " Date                ";
	title[1] = " Time        ";
	title[2] = " Azimuth ";
	title[3] = " Elevation ";
	title[4] = " Range ";
	title[5] = " MA ";
	title[6] = " Mode ";
	title[7] = " Squint ";
	title[8] = " SSP        ";
	title[9] = NULL;
	listlist = gtk_clist_new_with_titles(9, (gchar **)title);
	gtk_widget_set_usize(listlist, TRACK_WIDTH, TRACK_HEIGHT);
	gtk_clist_column_titles_passive(GTK_CLIST(listlist));

	listwin = gtk_scrolled_window_new(NULL, NULL);
	gtk_container_add(GTK_CONTAINER(listwin), listlist);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(listwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_container_set_border_width(GTK_CONTAINER(listwin), BORDER_ITEM);
	gtk_box_pack_start(GTK_BOX(vbox), listwin, TRUE, TRUE, 0);

	separator = gtk_hseparator_new();
	gtk_box_pack_start(GTK_BOX(vbox), separator, TRUE, TRUE, 0);

	bbox = gtk_hbutton_box_new();
	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
	gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
	gtk_box_pack_end(GTK_BOX(vbox), bbox, TRUE, TRUE, 0);

	button[0] = gtk_button_new_with_label("Cancel");
	button[1] = gtk_button_new_with_label("Help");

	gtk_container_add(GTK_CONTAINER(bbox), button[0]);
	gtk_container_add(GTK_CONTAINER(bbox), button[1]);

	gtk_signal_connect_object(GTK_OBJECT(button[0]), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
        gtk_signal_connect(GTK_OBJECT(button[1]), "clicked", GTK_SIGNAL_FUNC(HelpCb), (gpointer)10);

	GTK_WIDGET_SET_FLAGS(button[0], GTK_CAN_DEFAULT);
	GTK_WIDGET_SET_FLAGS(button[1], GTK_CAN_DEFAULT);
	gtk_widget_grab_default(button[0]);

	gtk_clist_freeze(GTK_CLIST(listlist));

	Calculate_Initial_Data();

	for (Track_Time = Start; Track_Time <= End; Track_Time += Step) {
		Calculate_Times(Track_Time);

		Calculate_Satellite_Position();

		if (Elevation >= Min_Elevation)
			Display_List_Data(listlist);
	}

	gtk_clist_thaw(GTK_CLIST(listlist));

	gtk_widget_show(button[0]);
	gtk_widget_show(button[1]);
	gtk_widget_show(bbox);
	gtk_widget_show(separator);
	gtk_widget_show(listlist);
	gtk_widget_show(listwin);
	gtk_widget_show(vbox);
	gtk_widget_show(window);
}

static void Calculate_Initial_Data(void)
{
	double Earth_Radius;
	double Eccentricity;
	double Latitude;
	double Longitude;
	double QTH_Height;
	double Mean_Motion;
	double L8;

	Latitude   = RAD(User_Data.Latitude);
	Longitude  = RAD(User_Data.Longitude);
	QTH_Height = User_Data.Height;

	Eccentricity  = Sat_Chosen->Eccentricity;
	Mean_Motion   = Sat_Chosen->Mean_Motion;

	SMA = R * pow(107.08816036 / (2.0 * PI * Mean_Motion), 2.0 / 3.0);

	Precession = 9.95 * pow(R / SMA, 3.5) / pow(1.0 - pow(Eccentricity, 2.0), 2.0);

	Earth_Radius = R * (1.0 - (F / 2.0) * (cos(2.0 * Latitude) - 1.0)) + QTH_Height / 1000.0;

	L8 = atan((1.0 - F) * (1.0 - F) * sin(Latitude) / cos(Latitude));

	Station_Earth_Z = Earth_Radius * sin(L8);
	Station_Earth_X = Earth_Radius * cos(L8) * cos(Longitude);
	Station_Earth_Y = Earth_Radius * cos(L8) * sin(-Longitude);
}

static void Calculate_Times(time_t Track_Time)
{
	double Epoch_Day_Time;
	struct tm *Time_Struct;
	double Temp;

	Time_Struct = gmtime(&Track_Time);

	Current_Time = *Time_Struct;
	Current_Time.tm_mon++;
	Current_Time.tm_yday++;

	Track_Day_Time = (double)Year_Conversion(Current_Time.tm_year + 1900) +
			 (double)Current_Time.tm_yday +
			 (double)Current_Time.tm_hour / 24.0  +
			 (double)Current_Time.tm_min / 1440.0 +
			 (double)Current_Time.tm_sec / (60.0 * 1440.0);

	Epoch_Day_Time = (double)Year_Conversion(Sat_Chosen->Epoch_Year) +
			 Sat_Chosen->Epoch_Day;

	Elapsed_Time = Track_Day_Time - Epoch_Day_Time;

	Sidereal_Epoch = (double)((int)(365.25 * (double)(Current_Time.tm_year - 81)) + 366);

	Temp = ((double)Sidereal_Epoch + 29218.5) / 36525.0;
	Sidereal_Constant = (6.6460656 + Temp * (2400.051262 + Temp * 2.581e-5)) / 24.0 - (double)Current_Time.tm_year;
}

static void Calculate_Satellite_Position(void)
{
	double Earth_X, Earth_Y, Earth_Z;
	double Orbit_X, Orbit_Y;
	double Stars_X, Stars_Y, Stars_Z;
	double Station_X, Station_Y, Station_Z;
	double X8, Y8, Z8;
	double Alat;
	double Alon;
	double C[3][2];
	double Denom;
	double Drag;
	double Drag_Term;
	double Eccentricity;
	double Epoch_A_O_P;
	double Epoch_Eccen;
	double Epoch_MA;
	double Epoch_Orbit;
	double Epoch_RAAN;
	double G7;
	double Inclination;
	double Increment;
	double Integer_Part;
	double Latitude;
	double Longitude;
	double Mean_Motion;
	double Orbital_Phase;
	int i;

	Latitude  = RAD(User_Data.Latitude);
	Longitude = RAD(User_Data.Longitude);

	Drag        = Sat_Chosen->Drag;
	Inclination = RAD(Sat_Chosen->Inclination);
	Epoch_Orbit = (double)Sat_Chosen->Epoch_Orbit;
	Epoch_A_O_P = Sat_Chosen->Arg_Of_Perigee;
	Epoch_Eccen = Sat_Chosen->Eccentricity;
	Epoch_MA    = Sat_Chosen->Mean_Anomoly;
	Epoch_RAAN  = Sat_Chosen->RAAN;
	Mean_Motion = Sat_Chosen->Mean_Motion;

	RAAN = RAD(Epoch_RAAN - Elapsed_Time * Precession * cos(Inclination));

	Arg_Of_Perigee = RAD(Epoch_A_O_P + Elapsed_Time * Precession * (2.5 * pow(cos(Inclination), 2.0) - 0.5));

	C[0][0] =  cos(Arg_Of_Perigee) * cos(RAAN) - sin(Arg_Of_Perigee) * sin(RAAN) * cos(Inclination);
	C[0][1] = -sin(Arg_Of_Perigee) * cos(RAAN) - cos(Arg_Of_Perigee) * sin(RAAN) * cos(Inclination);
	C[1][0] =  cos(Arg_Of_Perigee) * sin(RAAN) + sin(Arg_Of_Perigee) * cos(RAAN) * cos(Inclination);
	C[1][1] = -sin(Arg_Of_Perigee) * sin(RAAN) + cos(Arg_Of_Perigee) * cos(RAAN) * cos(Inclination);
	C[2][0] =  sin(Arg_Of_Perigee) * sin(Inclination);
	C[2][1] =  cos(Arg_Of_Perigee) * sin(Inclination);

	Drag_Term = (((Drag / Mean_Motion) / 3.0) * Elapsed_Time) / 2.0;

	Orbital_Phase = Mean_Motion * Elapsed_Time * (1.0 + 3.0 * Drag_Term) + (Epoch_MA / 360.0) + Epoch_Orbit;

	Orbital_Phase = modf(Orbital_Phase, &Orbit_No);

	MA = (int)(Orbital_Phase * 256.0);

	Mean_Anomoly = 2.0 * PI * Orbital_Phase;

	Eccentricity = Mean_Anomoly + Epoch_Eccen * (sin(Mean_Anomoly) + 0.5 * Epoch_Eccen * sin(Mean_Anomoly * 2.0));

	do {
		Denom     = 1.0 - Epoch_Eccen * cos(Eccentricity);
		Increment = Eccentricity - Epoch_Eccen * sin(Eccentricity) - Mean_Anomoly;

		Eccentricity -= Increment / Denom;
	} while (fabs(Increment) > 0.00001);

	Orbit_X = SMA * (cos(Eccentricity) - Epoch_Eccen) * (1.0 - 4.0 * Drag_Term);
	Orbit_Y = SMA * sqrt(1.0 - Epoch_Eccen * Epoch_Eccen) * sin(Eccentricity) * (1.0 - 4.0 * Drag_Term);
	Height  = SMA * Denom * (1.0 - 4.0 * Drag_Term);

	Stars_X = Orbit_X * C[0][0] + Orbit_Y * C[0][1];
	Stars_Y = Orbit_X * C[1][0] + Orbit_Y * C[1][1];
	Stars_Z = Orbit_X * C[2][0] + Orbit_Y * C[2][1];

	G7 = 2.0 * PI * modf((Track_Day_Time - Sidereal_Epoch) * 1.0027379 + Sidereal_Constant, &Integer_Part);

	Earth_X = Stars_X *  cos(G7) - Stars_Y * -sin(G7);
	Earth_Y = Stars_X * -sin(G7) + Stars_Y *  cos(G7);
	Earth_Z = Stars_Z;

	Station_X = Earth_X - Station_Earth_X;
	Station_Y = Earth_Y - Station_Earth_Y;
	Station_Z = Earth_Z - Station_Earth_Z;

	Range = sqrt(Station_X * Station_X + Station_Y * Station_Y + Station_Z * Station_Z);

	Z8 =  Station_X * cos(Longitude) * cos(Latitude) + Station_Y * sin(-Longitude) * cos(Latitude) + Station_Z * sin(Latitude);
	X8 = -Station_X * cos(Longitude) * sin(Latitude) - Station_Y * sin(-Longitude) * sin(Latitude) + Station_Z * cos(Latitude);
	Y8 =  Station_Y * cos(Longitude) - Station_X * sin(-Longitude);

	Azimuth   = DEG(atan(Y8 / X8));
	Elevation = DEG(asin(Z8 / Range));

	if (X8 < 0.0)       Azimuth += 180.0;
	if (Azimuth < 0.0)  Azimuth += 360.0;

	Half_Angle = DEG(acos(R / Height));
	SSP_Lat    = DEG(asin(Earth_Z / Height));
	SSP_Long   = DEG(-atan(Earth_Y / Earth_X));

	if (Earth_X < 0.0)  SSP_Long += 180.0;
	if (SSP_Long < 0.0) SSP_Long += 360.0;

	strcpy(Mode, "    ");

	for (i = 0; i < Sat_Chosen->No_Modes; i++) {
		if (Current_Time.tm_wday + 1000 == Sat_Chosen->MA_Day[i])
			strcpy(Mode, Sat_Chosen->Mode[i]);

		if (MA >= Sat_Chosen->MA_Day[i])
			strcpy(Mode, Sat_Chosen->Mode[i]);
	}

	if (Sat_Chosen->Aflag) {
		Alon = RAD(Sat_Chosen->Alon);
		Alat = RAD(Sat_Chosen->Alat);

		Orbit_X = -cos(Alat) * cos(Alon);
		Orbit_Y = -cos(Alat) * sin(Alon);

		Stars_X = Orbit_X * C[0][0] + Orbit_Y * C[0][1];
		Stars_Y = Orbit_X * C[1][0] + Orbit_Y * C[1][1];
		Stars_Z = Orbit_X * C[2][0] + Orbit_Y * C[2][1];

		Earth_X = Stars_X *  cos(G7) - Stars_Y * -sin(G7);
		Earth_Y = Stars_X * -sin(G7) + Stars_Y *  cos(G7);
		Earth_Z = Stars_Z;		

		Squint = DEG(acos(-((Station_X / Range) * Earth_X +
				    (Station_Y / Range) * Earth_Y +
				    (Station_Z / Range) * Earth_Z)));
	} else {
		Squint = 90.0 - Elevation - DEG(acos(sin(Latitude) * sin(RAD(SSP_Lat)) + cos(Latitude) * cos(RAD(SSP_Lat)) * cos(Longitude - RAD(SSP_Long))));
	}

	if (Squint < 0.0) Squint += 180.0;
}

static void Display_Track_Data(void)
{
	static double Prev_Range        = 0.0;
	static double Prev_Elapsed_Time = 0.0;
	static double Prev_SSP_Long     = -1.0;
	static double Prev_SSP_Lat      = -1.0;
	static double Prev_Half_Angle   = -1.0;
	double Change_Range;
	double Change_Time;
	double Fraction;
	char Buffer[41];

	Clear_Text();

	sprintf(Buffer, "Sat: %s", Sat_Chosen->Name);
	Write_Text(TEXT_SAT, Buffer);

	switch (User_Data.Date_Format) {
		case DATE_FORMAT_DDMMYYYY:
			sprintf(Buffer, "Date/Time: %02d-%02d-%04d %02d:%02d:%02d UTC",
								Current_Time.tm_mday,
							        Current_Time.tm_mon,
							        Current_Time.tm_year + 1900,
								Current_Time.tm_hour,
							        Current_Time.tm_min,
							        Current_Time.tm_sec);
			break;
		case DATE_FORMAT_MMDDYYYY:
			sprintf(Buffer, "Date/Time: %02d/%02d/%04d %02d:%02d:%02d UTC",
								Current_Time.tm_mon,
							        Current_Time.tm_mday,
							        Current_Time.tm_year + 1900,
								Current_Time.tm_hour,
							        Current_Time.tm_min,
							        Current_Time.tm_sec);
			break;
		default:
			g_error("mtrack: unknown date format %d\n", User_Data.Date_Format);
			break;
	}
	Write_Text(TEXT_DATETIME, Buffer);

	sprintf(Buffer, "Az: %.0f deg", Azimuth);
	Write_Text(TEXT_AZIMUTH, Buffer);

	sprintf(Buffer, "El: %.0f deg", Elevation);
	Write_Text(TEXT_ELEVATION, Buffer);

	sprintf(Buffer, "MA: %03d", MA);
	Write_Text(TEXT_MA, Buffer);

	sprintf(Buffer, "Mode: %s", Mode);
	Write_Text(TEXT_MODE, Buffer);

	sprintf(Buffer, "Range: %.0f kms", Range);
	Write_Text(TEXT_RANGE, Buffer);

	sprintf(Buffer, "Orbit: %.0f", Orbit_No);
	Write_Text(TEXT_ORBIT, Buffer);

	sprintf(Buffer, "Squint: %.0f deg", Squint);
	Write_Text(TEXT_SQUINT, Buffer);

	Change_Range = Range - Prev_Range;
	Change_Time  = (Elapsed_Time - Prev_Elapsed_Time) * 86400.0;

	Fraction = 1.0 - (Change_Range / Change_Time) / 299792.0;

	if (Sat_Chosen->Frequency1 != 0.0) {
		sprintf(Buffer, "Frequency 1: %.4f MHz", Fraction * Sat_Chosen->Frequency1);
		Write_Text(TEXT_FREQ1, Buffer);
	} else {
		Write_Text(TEXT_FREQ1, "");
	}

	if (Sat_Chosen->Frequency2 != 0.0) {
		sprintf(Buffer, "Frequency 2: %.4f MHz", Fraction * Sat_Chosen->Frequency2);
		Write_Text(TEXT_FREQ2, Buffer);
	} else {
		Write_Text(TEXT_FREQ2, "");
	}

	if (Sat_Chosen->Frequency3 != 0.0) {
		sprintf(Buffer, "Frequency 3: %.4f MHz", Fraction * Sat_Chosen->Frequency3);
		Write_Text(TEXT_FREQ3, Buffer);
	} else {
		Write_Text(TEXT_FREQ3, "");
	}

	Prev_Range        = Range;
	Prev_Elapsed_Time = Elapsed_Time;

	if (fabs(Prev_SSP_Lat -  SSP_Lat)  > 1.0 ||
	    fabs(Prev_SSP_Long - SSP_Long) > 1.0 ||
	    fabs(Prev_Half_Angle - Half_Angle) > 1.0) {
		Plot_Satellite(SSP_Lat, SSP_Long, Half_Angle);

		Prev_SSP_Lat    = SSP_Lat;
		Prev_SSP_Long   = SSP_Long;
		Prev_Half_Angle = Half_Angle;
	}

	Refresh_Text();
}

static void Display_List_Data(GtkWidget *list)
{
	char DateBuffer[12];
	char TimeBuffer[12];
	char AzBuffer[12];
	char ElBuffer[12];
	char RaBuffer[12];
	char MaBuffer[12];
	char SqBuffer[12];
	char SspBuffer[12];
	double Number;
	gchar *data[9];

	switch (User_Data.Date_Format) {
		case DATE_FORMAT_DDMMYYYY:
			sprintf(DateBuffer, "%02d-%02d-%04d", Current_Time.tm_mday,
							      Current_Time.tm_mon,
							      Current_Time.tm_year + 1900);
			break;
		case DATE_FORMAT_MMDDYYYY:
			sprintf(DateBuffer, "%02d/%02d/%04d", Current_Time.tm_mon,
							      Current_Time.tm_mday,
							      Current_Time.tm_year + 1900);
			break;
		default:
			g_error("mtrack: unknown date format %d\n", User_Data.Date_Format);
			break;
	}

	sprintf(TimeBuffer, "%02d:%02d:%02d", Current_Time.tm_hour,
					      Current_Time.tm_min,
					      Current_Time.tm_sec);

	sprintf(AzBuffer, "%.0f", Azimuth);

	sprintf(ElBuffer, "%.0f", Elevation);

	sprintf(RaBuffer, "%.0f", Range);

	sprintf(MaBuffer, "%03d", MA);

	sprintf(SqBuffer, "%.0f", Squint);

	Number = -SSP_Long;
	if (Number < 180.0)
		Number += 360.0;
	else if (Number > 180.0)
		Number -= 360.0;

	sprintf(SspBuffer, "%.0f/%.0f", Number, SSP_Lat);

	data[0] = DateBuffer;
	data[1] = TimeBuffer;
	data[2] = AzBuffer;
	data[3] = ElBuffer;
	data[4] = RaBuffer;
	data[5] = MaBuffer;
	data[6] = Mode;
	data[7] = SqBuffer;
	data[8] = SspBuffer;

	gtk_clist_append(GTK_CLIST(list), data);
}

static int Year_Conversion(int Year)
{
	int i;
	int Day = 0;

	for (i = 1980; i < Year; i++)
		Day += 365 + (i % 4 == 0 && (i % 100 != 0 || i % 400 == 0));

	return Day;
}

double RAD(double angle)
{
	return (angle / 180.0) * PI;
}


double DEG(double angle)
{
	return (angle / PI) * 180.0;
}

void Show_Elements(void)
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *list;
	GtkWidget *button[2];
	GtkWidget *separator;
	GtkWidget *bbox;
	gchar *title[4];
	gchar *data[3];
	double Number;
	char Buffer[20];

	window = gtk_window_new(GTK_WINDOW_DIALOG);

	gtk_window_set_title(GTK_WINDOW(window), "Updated Elements");
	gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH);

	vbox = gtk_vbox_new(FALSE, BORDER_WIDTH);
	gtk_container_add(GTK_CONTAINER(window), vbox);

	title[0] = " Parameter          ";
	title[1] = " Value                 ";
	title[2] = " Units            ";
	title[3] = NULL;
	list = gtk_clist_new_with_titles(3, (gchar **)title);
	gtk_widget_set_usize(list, ELEM_WIDTH, ELEM_HEIGHT);
	gtk_clist_column_titles_passive(GTK_CLIST(list));
	gtk_box_pack_start(GTK_BOX(vbox), list, TRUE, TRUE, 0);

	separator = gtk_hseparator_new();
	gtk_box_pack_start(GTK_BOX(vbox), separator, TRUE, TRUE, 0);

	bbox = gtk_hbutton_box_new();
	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
	gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
	gtk_box_pack_end(GTK_BOX(vbox), bbox, TRUE, TRUE, 0);

	button[0] = gtk_button_new_with_label("Cancel");
	button[1] = gtk_button_new_with_label("Help");

	gtk_container_add(GTK_CONTAINER(bbox), button[0]);
	gtk_container_add(GTK_CONTAINER(bbox), button[1]);

	gtk_signal_connect_object(GTK_OBJECT(button[0]), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
	gtk_signal_connect(GTK_OBJECT(button[1]), "clicked", GTK_SIGNAL_FUNC(HelpCb), (gpointer)8);

	GTK_WIDGET_SET_FLAGS(button[0], GTK_CAN_DEFAULT);
	GTK_WIDGET_SET_FLAGS(button[1], GTK_CAN_DEFAULT);
	gtk_widget_grab_default(button[0]);

	gtk_clist_freeze(GTK_CLIST(list));

	data[0] = "Epoch Date";
	sprintf(Buffer, "%.6f",
		 (double)Current_Time.tm_year * 1000.0 + 1900000.0 +
		 (double)Current_Time.tm_yday +
		 (double)Current_Time.tm_hour / 24.0  +
		 (double)Current_Time.tm_min / 1440.0 +
		 (double)Current_Time.tm_sec / (60.0 * 1440.0));
	data[1] = Buffer;
	data[2] = "";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "SMA";
	sprintf(Buffer, "%.4f", SMA);
	data[1] = Buffer;
	data[2] = "kms";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "Inclination";
	sprintf(Buffer, "%.4f", Sat_Chosen->Inclination);
	data[1] = Buffer;
	data[2] = "deg";
	gtk_clist_append(GTK_CLIST(list), data);

	Number = RAAN;
	if (Number < 0.0)  Number += 360.0;

	data[0] = "RAAN";
	sprintf(Buffer, "%.4f", Number);
	data[1] = Buffer;
	data[2] = "deg";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "Eccentricity";
	sprintf(Buffer, "%.7f", Sat_Chosen->Eccentricity);
	data[1] = Buffer;
	data[2] = "";
	gtk_clist_append(GTK_CLIST(list), data);

	Number = Arg_Of_Perigee;
	if (Number < 0.0)  Number += 360.0;

	data[0] = "Arg of Perigee";
	sprintf(Buffer, "%.4f", Number);
	data[1] = Buffer;
	data[2] = "deg";
	gtk_clist_append(GTK_CLIST(list), data);

	Number = DEG(Mean_Anomoly);
	if (Number < 0.0)  Number += 360.0;

	data[0] = "Mean Anomoly";
	sprintf(Buffer, "%.4f", Number);
	data[1] = Buffer;
	data[2] = "deg";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "Mean Motion";
	sprintf(Buffer, "%.8f", Sat_Chosen->Mean_Motion);
	data[1] = Buffer;
	data[2] = "revs/day";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "Decay Rate";
	sprintf(Buffer, "%E", Sat_Chosen->Drag);
	data[1] = Buffer;
	data[2] = "revs/day/day";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "Epoch Rev";
	sprintf(Buffer, "%.0f", Orbit_No);
	data[1] = Buffer;
	data[2] = "";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "Catalogue No";
	sprintf(Buffer, "%ld", Sat_Chosen->Catalogue_No);
	data[1] = Buffer;
	data[2] = "";
	gtk_clist_append(GTK_CLIST(list), data);

	Number = -SSP_Long;
	if (Number < -180.0)
		Number += 360.0;
	else if (Number > 180.0)
		Number -= 360.0;

	data[0] = "SSP Longitude";
	sprintf(Buffer, "%.1f", Number);
	data[1] = Buffer;
	data[2] = "deg East";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "SSP Latitude";
	sprintf(Buffer, "%.1f", SSP_Lat);
	data[1] = Buffer;
	data[2] = "deg North";
	gtk_clist_append(GTK_CLIST(list), data);

	data[0] = "Half Angle";
	sprintf(Buffer, "%.0f", Half_Angle);
	data[1] = Buffer;
	data[2] = "deg";
	gtk_clist_append(GTK_CLIST(list), data);

	gtk_clist_thaw(GTK_CLIST(list));

	gtk_widget_show(button[0]);
	gtk_widget_show(button[1]);
	gtk_widget_show(bbox);
	gtk_widget_show(separator);
	gtk_widget_show(list);
	gtk_widget_show(vbox);
	gtk_widget_show(window);
}

void Show_Locations(void)
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *listlist, *listwin;
	GtkWidget *separator;
	GtkWidget *bbox;
	GtkWidget *button[2];
	char *title[5];
	double Half_Angle;
	double Rad_SSP_Lat;
	double Rad_SSP_Long;
	double Azimuth;
	double Elevation;
	double Range;
	double Latitude;
	double Longitude;
	char   AzBuffer[15];
	char   ElBuffer[15];
	char   RaBuffer[15];
	gchar *data[4];
	GSList *Loc;
	struct Loc_Struct *Data;

	if (Loc_List == NULL) {
		Warning_Box("No Locations loaded");
		return;
	}

	window = gtk_window_new(GTK_WINDOW_DIALOG);

	gtk_window_set_title(GTK_WINDOW(window), "Visibility");
	gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH);

	vbox = gtk_vbox_new(FALSE, BORDER_WIDTH);
	gtk_container_add(GTK_CONTAINER(window), vbox);

	title[0] = " Location                                               ";
	title[1] = " Azimuth ";
	title[2] = " Elevation ";
	title[3] = " Range ";
	title[4] = NULL;
	listlist = gtk_clist_new_with_titles(4, (gchar **)title);
	gtk_widget_set_usize(listlist, LOC_WIDTH, LOC_HEIGHT);
	gtk_clist_column_titles_passive(GTK_CLIST(listlist));

	listwin = gtk_scrolled_window_new(NULL, NULL);
	gtk_container_add(GTK_CONTAINER(listwin), listlist);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(listwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_container_set_border_width(GTK_CONTAINER(listwin), BORDER_ITEM);
	gtk_box_pack_start(GTK_BOX(vbox), listwin, TRUE, TRUE, 0);

	separator = gtk_hseparator_new();
	gtk_box_pack_start(GTK_BOX(vbox), separator, TRUE, TRUE, 0);

	bbox = gtk_hbutton_box_new();
	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
	gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
	gtk_box_pack_end(GTK_BOX(vbox), bbox, TRUE, TRUE, 0);

	button[0] = gtk_button_new_with_label("Cancel");
	button[1] = gtk_button_new_with_label("Help");

	gtk_container_add(GTK_CONTAINER(bbox), button[0]);
	gtk_container_add(GTK_CONTAINER(bbox), button[1]);

	gtk_signal_connect_object(GTK_OBJECT(button[0]), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window));
        gtk_signal_connect(GTK_OBJECT(button[1]), "clicked", GTK_SIGNAL_FUNC(HelpCb), (gpointer)9);

	GTK_WIDGET_SET_FLAGS(button[0], GTK_CAN_DEFAULT);
	GTK_WIDGET_SET_FLAGS(button[1], GTK_CAN_DEFAULT);
	gtk_widget_grab_default(button[0]);

	Rad_SSP_Lat  = RAD(SSP_Lat);
	Rad_SSP_Long = RAD(SSP_Long);

	gtk_clist_freeze(GTK_CLIST(listlist));

	Loc = Loc_List;

	while (Loc != NULL) {
		Data = (struct Loc_Struct *)Loc->data;

		Latitude  = RAD(Data->Latitude);
		Longitude = RAD(Data->Longitude);

		Half_Angle = acos(sin(Latitude) * sin(Rad_SSP_Lat) + cos(Latitude) * cos(Rad_SSP_Lat) * cos(Longitude - Rad_SSP_Long));
		Azimuth    = DEG(acos((sin(Rad_SSP_Lat) - sin(Latitude) * cos(Half_Angle)) / (cos(Latitude) * sin(Half_Angle))));
		Elevation  = DEG(atan((Height * cos(Half_Angle) - R) / (Height * sin(Half_Angle))));
		Range      = sqrt(Height * Height + R * R - 2.0 * R * Height * cos(Half_Angle));

		if (sin(Longitude - Rad_SSP_Long) < 0.0)
			Azimuth = 360.0 - Azimuth;

		data[0] = Data->QTH;

		sprintf(AzBuffer, "%.0f", Azimuth);
		data[1] = AzBuffer;

		sprintf(ElBuffer, "%.0f", Elevation);
		data[2] = ElBuffer;

		sprintf(RaBuffer, "%.0f", Range);
		data[3] = RaBuffer;

		gtk_clist_append(GTK_CLIST(listlist), data);

		Loc = g_slist_next(Loc);
	}

	gtk_clist_thaw(GTK_CLIST(listlist));

	gtk_widget_show(button[0]);
	gtk_widget_show(button[1]);
	gtk_widget_show(bbox);
	gtk_widget_show(separator);
	gtk_widget_show(listlist);
	gtk_widget_show(listwin);
	gtk_widget_show(vbox);
	gtk_widget_show(window);
}
