// 
// 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 <ncurses.h>

char *status = "";

void Status() {
	move(LINES-1, 0);
	printw("%s", status);
}

void HideCursor() {
	move (LINES-1, COLS-1);
}

void StartCurses() {
	initscr();
	halfdelay(10);
	noecho();
	nonl();
	intrflush(stdscr, FALSE);
	keypad(stdscr, TRUE);
}

void EndCurses() {
	endwin();
}

void Header(Sat *s, double now) {
	char buf[100];

	printw("-- SMEG - Live Display -------------------------------------------------------\n");

	printw("\n");
	strfsgptime(buf, 100, "%Y%m%d %H:%M:%S ", now);
        printw("                                                      %s\n", buf);
	strfsgptime(buf, 100, "%I:%M:%S %p %Z", now);
        printw("                                                            %s\n", buf);
	printw("         Name: %s\n", s->s->name);
	printw(" Norad Number: %d\n", s->s->norad);
	printw("International: % 8s\n", s->s->desig);
	printw("\n");
}

void ECIVectors(Sat *s, double now) {
	s->calcpos(now);
	printw("   X: % 11.3f  Y: %11.3f  Z: %11.3f\n",
	       s->x[0], s->x[1], s->x[2]);
	printw("  dX: % 11.3f dY: %11.3f dZ: %11.3f\n",
	       s->dx[0], s->dx[1], s->dx[2]);
	printw("\n");
}

void LookLLA(Sat *s, Site *si, double now) {
	Azrael *a;
	LLA *lla;

	a = new Azrael(s, si, now);
	s->calcpos(now); /* Redundant, but what the smeg? */
	lla = s->calclla();
	
	printw("   Azimuth: %8.3f %s    Latitude: %9.3f %s\n",
	       a->az, CompassDir(a->az), fabs(lla->lat),
	       (lla->lat > 0) ? "N" : "S");
	printw(" Elevation: %11.3f   Longitude: %9.3f %s\n",
	       a->el, fabs(lla->lon), (lla->lon > 0) ? "E" : "W");
	printw("     Range: %11.3f    Altitude: %11.3f\n",
	       a->ra, lla->alt);
	printw("                              Speed: %11.3f\n",
	       /* RangeRate(s, site) */  len(s->dx));
	printw("\n");
}



void Visual(Sat *s, Site *si, double now) {
	int lit;

	s->calcpos(now);
	
	mvprintw(6, 55, "Visual");
	if (!s->hasMagnitude()) {
		mvprintw(8, 55,"No Information", s->magnitude(si));
	}

	lit = isLit(s, now);
	
	if (lit) {
		mvprintw(8, 55, "Sat in Daylight");
	} else {
		mvprintw(8, 55, "Sat in Darkness");
	}

	mvprintw(9, 55,  "Sun Elevation: %.2f", Elevation(theSun, si, now));
	mvprintw(11, 55, "Intrinsic Mag: %.1f", s->s->mag0);	
	mvprintw(12, 55, "      Perigee: %.0f km",
		 s->s->semi * R * (1 - s->s->ecc) - R);
	mvprintw(13, 55, "  Minimum Mag: %.1f", s->maxMagnitude());
	if (lit) {
		mvprintw(14, 55, "  Current Mag: %.1f", s->magnitude(si));
	} else {
		mvprintw(14, 55, "  Current Mag: Not Lit");
	}		
}
	

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

extern List<Sat> *fsatlist;

void LiveSatlist() {
	Sat *s;
	Site *site;
	double now;
	double timewarp = 0;
	
	if (!fsatlist) return;

	fsatlist->buildprev();
	fsatlist->reset();
	s = fsatlist->next();
	if (!s) {
		fprintf(stderr, "Error: The satlist is empty.\n");
		return;
	}

	site = new Site(lat, lon, alt);
	
	StartCurses();
	status = "Displaying live satlist.";
	
	while (1) {
		now = sgp_now() + timewarp;
		
		erase();
		move(0, 0);
		Header(s, now);
		ECIVectors(s, now);
		LookLLA(s, site, now);
		Visual(s, site, now);
		Status();

		HideCursor();
		
		switch(getch()) {
		case ERR:
			break; /* Just a timeout. */
		case 'w':
			/* Let's do the time warp again! */
			timewarp += 60 * SECDAY;
			break;
		case 'n':
		case 'N':
		case KEY_DOWN:
		case KEY_RIGHT:
			if (fsatlist->nextp()) {
				s = fsatlist->next();
				status = "Displaying next satellite.";
				break;
			}

			status = "At end of list.";
			break;
		case 'p':
		case 'P':
		case KEY_LEFT:
		case KEY_UP:
			if (fsatlist->prevp()) {
				s = fsatlist->prev();
				status = "Displaying previous satellite.";
				break;
			}

			status = "At start of list.";
			break;
		case KEY_HOME:
		case '<':
			fsatlist->reset();
			s = fsatlist->next();
			status = "Jumped to start of list.\n";
			break;
		case KEY_END:
		case '>':
			fsatlist->reset();
			s = fsatlist->prev();
			status = "Jumped to end of list.\n";
			break;
		case 'Q':
		case 'q':
			goto bailout;
		default:
			status = "Invalid keypress.";
		}
	}

 bailout:
			
	EndCurses();
	delete site;

}

extern List<Pass> *fpasslist;
extern Site *psite;

#define stb(x, y) strfsgptime(sgptb, 100, x, y)

char timel[100];
char *compt(double until, double now) {
       int t =  sgp_unix(now) - sgp_unix(until);
       snprintf(timel, 100, "%c%d:%02d:%02d",
		(t < 0) ? '-' : '+',
		abs(t / 3600),
		abs(t / 60) % 60,
		abs(t) % 60);
       return timel;
}

void CursePass(Pass *p, double now) {
	char sgptb[100];

	stb("%Y%m%d %H:%M:%S", p->min0);
	printw("  Pass Start: %s (%s)\n", sgptb, compt(p->min0, now));
	stb("%Y%m%d %H:%M:%S", p->max);
	printw("Pass Maximum: %s (%s)\n", sgptb, compt(p->max, now));
	stb("%Y%m%d %H:%M:%S", p->min1);
	printw("    Pass End: %s (%s)\n", sgptb, compt(p->min1, now));
	printw("\n");
}

void LivePasslist() {
	Pass *p;
	Sat *s;
	Site *site;
	double now;
	double realnow;
	double timewarp = 0;
	int when = 0;
	
	if (!fpasslist) return;
	site = psite;

	fpasslist->buildprev();
	fpasslist->reset();
	p = fpasslist->next();
	if (!p) {
		fprintf(stderr, "Error: The passlist is empty.\n");
		return;
	}

	StartCurses();
	status = "Displaying live passes.";

	p->state = 0;
	
	while (1) {
		realnow = now = sgp_now() + timewarp;

		if (p->state == 0 && now > p->min0) {
			/* Pass has started */
			p->state == 1;
		}

		if (p->state == 1 && now > p->min1) {
			/* Pass has ended */
			p->state = 2;
			while (fpasslist->nextp()) {
				p = fpasslist->next();
				if (p->min1 > now) break;
				status = "Automatically skipping to next pass.";
			}
		}
			

		switch(when) {
		case 1:
			now = p->min0;
			break;
		case 2:
			now = p->max;
			break;
		case 3:
			now = p->min1;
			break;
		}
		
		s = p->s;
		
		erase();
		move(0, 0);
		Header(s, now);
		ECIVectors(s, now);
		LookLLA(s, site, now);
		CursePass(p, now);
		Visual(s, site, now);
		Status();

		HideCursor();
		
		switch(getch()) {
		case ERR:
			break; /* Just a timeout. */
		case '1':
			when = 1;
			status = "Fixing time at pass start.";
			break;
		case '2':
			when = 2;
			status = "Fixing time at pass maximum.";
			break;
		case '3':
			when = 3;
			status = "Fixing time at pass end.";
			break;
		case '0':
			when = 0;
			status = "Unfixing time.";
			break;
			

		case 'w':
                        /* Let's do the time warp again! */
			timewarp += 60 * SECDAY;
			break;
		case 'n':
		case 'N':
		case KEY_DOWN:
		case KEY_RIGHT:
			if (fpasslist->nextp()) {
				p = fpasslist->next();
				status = "Displaying next pass.";
				break;
			}

			status = "At end of list.";
			break;
		case ' ':
			if (!fpasslist->nextp()) {
				status = "At end of list.";
				break;
			}
			p = fpasslist->next();
			while (now > p->min1) {
				if (!fpasslist->nextp()) {
						break;
				}
				p = fpasslist->next();
			}
			if (p->min1 < now) {
				status = "No more passes.";
			} else {
				status = "Jumped to next unexpired pass.";
			}
			break;
		case 'p':
		case 'P':
		case KEY_LEFT:
		case KEY_UP:
			if (fpasslist->prevp()) {
				p = fpasslist->prev();
				status = "Displaying previous pass.";
				break;
			}

			status = "At start of list.";
			break;
		case KEY_HOME:
		case '<':
			fpasslist->reset();
			p = fpasslist->next();
			status = "Jumped to start of list.\n";
			break;
		case KEY_END:
		case '>':
			fpasslist->reset();
			p = fpasslist->prev();
			status = "Jumped to end of list.\n";
			break;
		case 'Q':
		case 'q':
			goto bailout;
		default:
			status = "Invalid keypress.";
		}

		now = realnow;
		
		p->state = 0;
				
		if (p->state == 0 && now > p->min0) {
			p->state = 1;
		}

		if (p->state == 1 && now > p->min1) {
			p->state = 2;
		}
			
	}

 bailout:
			
	EndCurses();
}

	
