// sattool - visual satellite tracking and prediction tool.
// Copyright 2000 Tom Rothamel <tom-idbg@onegeek.org>
//
// 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 "sattool.h"

// The following files only contain templates, so we'll #include them.
#include "fminbr.cc"
#include "zeroin.cc"

Pass::Pass() {}

Pass::Pass(Sat *insat, Object *insite, double inmaxel, double inmin0,
	   double inmax, double inmin1, double inmmt, double inminmag) {

	sat = insat;
	site = insite;
	maxel = inmaxel;
	min0 = inmin0;
	max = inmax;
	min1 = inmin1;
	mmt = inmmt;
	minmag = inminmag;

	_object = insat;
	_sat = insat;
	_time = max;
	
	lock(sat);
	lock(site);
}
	

void Pass::write(FILE *f, int d) {
	pad(f, d);
	fprintf(f, "(pass\n");
	sat->write(f, d+1);
	site->write(f, d+1);
	pad(f, d+1);
	fprintf(f, "%f %f %f %f %f %f\n", maxel,  min0, max, min1, mmt, minmag);
	pad(f, d);
	fprintf(f, ")\n", mmt, minmag);
}

Pass::~Pass() {
	unlock(sat);
	unlock(site);
}


// Used in minimizing the magnitude.
struct PassVisualInfo {
	Encounter *e;
	Sat *sat;
	Object *site;
};

// Returns the magnitude. (Used in minimizing the magnitude.)
double mag(double t, PassVisualInfo *pvi) {
	pvi->e->calc(pvi->sat, pvi->site, t);
	return pvi->sat->calcmag(pvi->e);
}	
	
// This method finds the minimum magnitude and the time of the minimum
// magnitude of the pass.
void Pass::visual(double step) {
	PassVisualInfo *pvi;

	if (!sat->hasmag()) return;

	pvi = new PassVisualInfo;
	pvi->sat = sat;
	pvi->site = site;
	pvi->e = new Encounter;

	mmt = fminbr(min0, min1, pvi, mag, step * SECDAY);
	minmag = mag(mmt, pvi);

	delete pvi->e;
	delete pvi;
}

// Used in min/maxing the elevation.
struct PredictInfo {
	Encounter *e;
        Sat *sat;
	Object *site;
	double minelev;
};

// The negative elevation.
double negele(double t, PredictInfo *pi) {
	return -pi->e->calc(pi->sat, pi->site, t);
}

// The positive elevation.	
double ele(double t, PredictInfo *pi) {
	return pi->e->calc(pi->sat, pi->site, t);
}

// The offset elevation.
double eleoff(double t, PredictInfo *pi) {
	return pi->e->calc(pi->sat, pi->site, t) - pi->minelev;
}


// This creates predictions for a satellite. It will create Pass objects,
// and add them to the List.
void PredictSat(List *l, Sat *s, Object *site,
		double start, double end,
		double bigstep, double minelev) {
	double min;
	double max;
	double bigsteps;
	Pass *p;
	PredictInfo *pi;
	
	pi = new PredictInfo;
	pi->sat = s;
	pi->site = site;
	pi->e = new Encounter;
	pi->minelev = minelev;
	
	bigsteps = bigstep * SECDAY;

	min = fminbr(start - 2 * M_PI / (s->mm(start)), start, pi, ele, bigsteps); 
	max = min;
	
	while (max < end) {
		double mm = s->mm(min);
		max = fminbr(min, min + 2 * M_PI / mm, pi, negele, bigsteps);

		if (max < end && max > start && ele(max, pi) > minelev) {
			p = new Pass;

			p->maxel = pi->e->elevation;

			p->_sat = s;
			p->_object = s;
			p->sat = s;
			lock(p->sat);
			
			p->site = site;
			lock(p->site);

			p->max = max;
			p->_time = max;
			p->min0 = zeroin(max - 1 * M_PI / (s->mm(max)),
					 max, pi, eleoff, bigsteps);
			p->min1 = zeroin(max, max + 1 * M_PI / (s->mm(max)),
					 pi, eleoff, bigsteps);

			p->mmt = HUGE_VAL;
			p->minmag = HUGE_VAL;
			
			if (p->min0 < start) p->min0 = start;
			if (p->min1 > end) p->min1 = end;

			l->add(p);			
		}

		min = fminbr(max, max + 2 * M_PI / mm, pi, ele, bigsteps);
	}	

	delete pi->e;
	delete pi;
}

