// 
// smeg - A satellite modelling and prediction tool
// Copyright (C) 1999  Tom Rothamel
// 
// 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; see the file COPYING.  If not, write to
// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.

#include <sts2.h>
#include <stdio.h>
#include <math.h>

List<Sat> *satlist = NULL;
List<Sat> *fsatlist = NULL; /* Filtered Satlist */

Sat::Sat(SAT *ns) {
	s = ns;
	norad = s->norad;
	name = s->name;
}

void Sat::calcpos(double t) {
	int i;
	
	if (ct == t) return;
	ct = t;
	
	sgp4(s, t);

	for (i = 0; i < 3; i++) {
		x[i] = s->x[i] * R;
		dx[i] = s->dx[i] * R * SECDAY;
	}
}

int Sat::hasMagnitude() {
	return s->mode & SGP_SAT_SIZEINFO;
}

double Sat::maxMagnitude() {
	double peri;
	double mag;
		
	peri = s->semi * R * (1 - s->ecc);
	peri -= R;
	mag = s->mag0 - 15.75 + 2.5 * log10(peri * peri);
	return mag;
}

double Sat::magnitude(Site *si) {
	Azrael *a;
	double ang;
	double mag;
	double fracil;
	
	a = new Azrael(this, si, ct);
	ang = SiteSatSun(this, si, ct);

	fracil = 0.5 * (1 - cos(ang));

	mag = s->mag0 - 15.75 + 2.5 * log10(a->ra * a->ra / fracil);

	delete a;
	return mag;
}

/* Utility functions */

void LoadSats(FILE *s) {
	SAT *sat;
	Sat *sc;

	FreePassList();
	
	if (satlist) {
		if (satlist == fsatlist) fsatlist = NULL;

		satlist->reset();
		sc = satlist->next();
		if (sc) sgp_sat_list_free(sc->s);
		delete satlist;		
	}

	if (fsatlist) delete fsatlist;
	
	satlist = new List<Sat>;
	fsatlist = satlist;

	sat = sgp_sat_read(s);

	if (!sat) {
		fprintf(stderr, "Error: no elements found.\n");
	}
	
	while (sat) {
		satlist->add(new Sat(sat));
		sat = sat->next;
	}

	if (verbose) printf("Loaded %d elements.\n", satlist->count);
}

void LoadSatsFromFile(char *filename) {
	FILE *f;

	if (!filename) return;
	
	f = fopen(filename, "r");
	if (!f) {
		fprintf(stderr, "Error: Couldn't open '%s'. Aborting.\n",
			filename);
		return;
	}

	LoadSats(f);
	fclose(f);
}

void SatlistFilter(STEP *expr) {
	List<Sat> *nsatlist;
	Sat *s;
	CONTEXT c;
	
	if (!fsatlist) {
		fprintf(stderr, "Error: No satellites loaded. Use 'tle file' to load a satlist.\n");
		return;
	}

	nsatlist = new List<Sat>;
	
	fsatlist->reset();
	while (s = fsatlist->next()) {
		c.sat = s;
		c.t = sgp_now();
		if (run(&c, expr)) nsatlist->add(s);
	}

	if (fsatlist->count  == nsatlist->count) {
		if (verbose) printf("%d satellites passed filter. (unfilter first?)\n", nsatlist->count);
	} else {
		if (verbose) printf("%d satellites passed filter.\n", nsatlist->count);
	}
	if (fsatlist != satlist) delete fsatlist;
	fsatlist = nsatlist;
}

void SatlistUnfilter() {
	if (fsatlist == satlist) return;
	if (satlist == NULL) return;

	delete fsatlist;
	fsatlist = satlist;

	if (verbose) printf("Unfiltered list contains %d satellites.\n", fsatlist->count);
}

void ShowSatlist() {
	Sat *s;
	fprintf(out, "Norad # Intl Desig Name\n"
		     "------- ---------- ---------------------------------------\n");

	if (!fsatlist) return;

	fsatlist->reset();
	while (s = fsatlist->next()) {
		fprintf(out, "% 7d % 10s %s\n", s->norad, s->s->desig,
			s->name);
	}
}

void CurrentPosition(STEP *expr) {
       Sat *s;
       double now;
       LLA *lla;
       CONTEXT ct;

       now = sgp_now();
       
       fprintf(out,
	       "Norad # Name                             Lat       Lon        Alt\n"
	       "------- ------------------------------   --------  ---------  ---------\n");
       
       if (!fsatlist) return;

       fsatlist->reset();
       
       while (s = fsatlist->next()) {

	       s->calcpos(now);
	       lla = s->calclla();

	       if (expr) {
		       ct.sat = s;
		       ct.lla = lla;
		       if (!run(&ct, expr)) {
			       delete lla;
			       continue;
		       }
	       }
	       
	       fprintf(out, "% 7d %30s  % 7.3f %c % 8.3f %c  %9.0f\n",
		       s->norad, s->name,
		       fabs(lla->lat), (lla->lat > 0) ? 'N' : 'S',
		       fabs(lla->lon), (lla->lon > 0) ? 'E' : 'W',
		       lla->alt);
	       delete lla;
       }
}

void CurrentSatX() {
       Sat *s;
       double now;
       LLA *lla;

       now = sgp_now();
       
       fprintf(out,
	       "Norad # Name                            X        Y        Z\n"
	       "------- ------------------------------  -------- -------- --------\n");
       
       if (!fsatlist) return;

       fsatlist->reset();
       
       while (s = fsatlist->next()) {

	       s->calcpos(now);
	       
	       fprintf(out, "% 7d %30s  % 8.0f % 8.0f % 8.0f\n",
		       s->norad, s->name, s->x[0], s->x[1], s->x[2]);
       }
}

extern double lat;
extern double lon;
extern double alt;

void CurrentLook(STEP *expr) {
       Sat *s;
       Site *si;
       double now;
       CONTEXT ct;
       Azrael *azrael;

       
       now = sgp_now();
       si = new Site(lat, lon, alt);

       
       fprintf(out,
	       "Norad # Name                             Azimuth     Elev     Range\n"
	       "------- ------------------------------   ----------  -------  ---------\n");
       
       if (!fsatlist) return;

       fsatlist->reset();
       
       while (s = fsatlist->next()) {
	       azrael = new Azrael(s, si, now); 
	       
	       /*
	       if (expr) {
		       ct.sat = s;
		       if (!run(&ct, expr)) {
			       continue;
		       }
	       }
	       */
	       
	       fprintf(out, "% 7d %30s  % 8.3f %s  % 7.3f  %.0f\n",
		       s->norad, s->name,
		       azrael->az, CompassDir(azrael->az),
		       azrael->el, azrael->ra);
	       delete azrael;
       }

       delete si;
}
