/* This applet was manufactured by J. Giesen, 1998 Nov. 10 */

import java.awt.*;
import java.applet.Applet;
import java.util.Date;

public class sunrise109 extends Applet implements Runnable
{
	String versStr = "Sunrise & Sunset 1.09";
	Date dat;	
	compute comp;
	Thread myThread;
	TextField latField, longField;
	double latitude, longitude;
	String latStr, longStr;
	Double latDouble, longDouble;
	Label latLabel, longLabel;
	
			
	public void init()
	{
		dat = new Date(); // get date and time informations from system clock
		latitude = 52.51;
		longitude = -13.41; // longitude < 0 if east of Greenwich
		latStr = latStr.valueOf(latitude);
		longStr = longStr.valueOf(longitude);		
		setBackground(Color.white);		
		comp = new compute(dat, latitude, longitude);
		
		latLabel = new Label("Lat. =");
		add(latLabel);		
		latField = new TextField(latStr,6);
		add(latField);
		longLabel = new Label(" Long.=");
		add(longLabel);
		longField = new TextField(longStr,6);
		add(longField);
				
		repaint();
	}
	
	public void start()
	{
		myThread = new Thread(this);
		myThread.start();
	}
	
	public void stop( )
	{	
		myThread.stop();
	}
	
	public void run()
	{
		while (true)  // repeat forever
		{
			dat = new Date(); // get current date and time information from system clock
			
			try
			{
			latStr = latField.getText();			
			latDouble = Double.valueOf(latStr);
			latitude = latDouble.doubleValue();						
			longStr = longField.getText();
			longDouble = Double.valueOf(longStr);
			longitude = longDouble.doubleValue();
							
			comp = new compute(dat, latitude, longitude); // execute new calculatons
			repaint();
			}	
			catch (NumberFormatException e) { }
			
						
			try {Thread.sleep(1000);} // wait for 1000 milli-seconds							
			catch (InterruptedException e) { }
		}		
	} 	
	
	public void paint( Graphics g )
	{
		g.setFont(new Font("Courier", Font.PLAIN, 12));
		g.setColor(Color.red);
		g.drawString( versStr, 30, 50 );
		g.setColor(Color.black);		
		comp.update(g);
	}
}
//-------------------------------------------------------------------------

class compute extends Canvas {
		
	double DEC, RA;	
	int offset;		
	String[] str = new String[11];
	int utHours;
	Rise_Set rs;		
	
	compute (Date dat, double LAT, double LONG) {
	
		int year, month, date, hours, minutes, seconds;		
		double UT;
		double latitude, longitude;		
		String s;
						
		latitude = LAT;
		longitude = LONG;
						
		hours = dat.getHours();
		minutes = dat.getMinutes();
		seconds = dat.getSeconds();
		date = dat.getDate();
		month = dat.getMonth();
		month = month + 1; // because dat.getMonth() is zero for January
		year = dat.getYear();
		year = year + 1900;
		offset = -dat.getTimezoneOffset()/60; // time zone offset (decimal hours)
				
		UT = 1.0*(hours-offset) + minutes/60.0 + seconds/3600.0; // Universal Time
		utHours = hours - offset;
		if (utHours<0) utHours=utHours+24;
		if (utHours>24) utHours=utHours-24;
		
		rs = new Rise_Set(dat, latitude, -longitude);

		str[4] = "latitude   = " + Math.abs(latitude);
		if (latitude>0) str[4] = str[4] + " N";
		else str[4] = str[4] + " S";
		str[5] = "longitude  = " + Math.abs(longitude);
		if (longitude>0) str[5] = str[5] + " W";
		else str[5] = str[5] + " E";				
		str[6] = dat.toString();		
		str[7] = "time zone offset = " + (-dat.getTimezoneOffset()) + " min";
		if (utHours>9) s = ""; else s = "0";
		str[8]  = "GMT  " + s + utHours;
		if (minutes>9) s = ":"; else s = ":0";
		str[8]  = str[8] + s + minutes;
		if (seconds>9) s = ":"; else s = ":0";
		str[8]  = str[8] + s + seconds;
		
		str[9] = rs.rise_String();
		str[10] =  rs.set_String();
												
		repaint();
	}
	
			
	// draw data strings
	public void paint(Graphics g)
	{					
		for (int i=4; i<9; i++) g.drawString( str[i], 30,i*18 );
		g.setColor(Color.red);
		for (int i=9; i<11; i++) g.drawString( str[i], 30,i*18 );
		g.setColor(Color.blue);
		g.setFont(new Font("Courier", Font.PLAIN, 10));
		g.drawString( "© 1998-2000 J.Giesen - www.sweethome.de/giesen/", 10,205 );
		g.setColor(Color.black);
		g.clipRect(0,0,size().width,size().height);					
	}				
}
//--------------------------------------------------------------------------

class Rise_Set

{
	Date dat;
	int date, month, year;
	int HOUR;
	double latitude, longitude;
	double Y0, yPlus, yMinus, YE, DX;
	int NZ;
	boolean RISE, SETT, ABOVE;
	double UTRISE, UTSET, hRise, hSet;
	int locOffset;
	String  riseStr, setStr;
	double zero1, zero2;

	public Rise_Set (Date myDat, double myLat, double myLong) {
					
		dat = myDat;
		date = dat.getDate();
		month = dat.getMonth();
		year = dat.getYear();
		
		latitude = myLat;
		longitude = myLong;

		locOffset = -dat.getTimezoneOffset()/60;
					
		RISE = false;
		SETT = false;
			
		for (int i=-locOffset; i<-locOffset+24; i++) { // i=GMT
						
			riseset(date, month+1, year+1900, i*1.0);
							
			if (RISE && SETT)  break;			
		}
		
				
		if (RISE || SETT)
		{
			if (RISE) {UTRISE=UTRISE + locOffset;if (UTRISE>24) UTRISE = UTRISE-24;if (UTRISE<0) UTRISE = UTRISE+24;}
			if (SETT) {UTSET=UTSET + locOffset;if (UTSET>24) UTSET = UTSET-24;if (UTSET<0) UTSET = UTSET+24;}
			
	
				if (RISE) hRise = UTRISE;
				if (SETT) hSet = UTSET;					
				
				if (RISE)
				{																																
					riseStr = makeTimeString("Rise ", hRise);
				}
				else
				{
					if (ABOVE) {riseStr = "Visible all day"; setStr="Visible all day";}
					else {riseStr = "Unvisible all day"; setStr="Unvisible all day";}
				}
															
				if (SETT)						
				{																							
					setStr         = makeTimeString("Set  ", hSet);
				}						
				else	
				{
					if (ABOVE) {riseStr = "Visible all day"; setStr="Visible all day";}
					else {riseStr = "Unvisible all day"; setStr="Unvisible all day";}
				}	
										
		} //(RISE || SETT)
		else
		{			
					if (ABOVE) {riseStr = "Visible all day"; setStr="Visible all day";}
					else {riseStr = "Unvisible all day"; setStr="Unvisible all day";}				
		}						
	}
	
	String rise_String()
	{
		return riseStr;
	}
	
	String set_String()
	{
		return setStr;
	}	
	
	public void riseset(int date, int month, int year, double HOUR)
	{
	
	final double K = Math.PI/180.0;
	double sh = Math.sin(-K*0.8333);	
	double JD = Jul_Date(date, month, year, HOUR);
	double dec = sunDecRA(1,JD);
	double ra = sunDecRA(2,JD);
	Y0 = sin_elev(JD, latitude, -longitude, dec, ra) - sh;	
	double jdPlus = Jul_Date(date, month, year, HOUR+1.0);
	dec = sunDecRA(1,jdPlus);
	ra = sunDecRA(2,jdPlus);	
	yPlus = sin_elev(jdPlus, latitude, -longitude, dec, ra) - sh;	
	double jdMinus = Jul_Date(date, month, year, HOUR-1.0);
	dec = sunDecRA(1,jdMinus);
	ra = sunDecRA(2,jdMinus);
	yMinus = sin_elev(jdMinus, latitude, -longitude, dec, ra) - sh;
	
	ABOVE = (yMinus>0.0);

	QUAD();
	switch (NZ)
	{
		case 0: break;
		case 1:		
			if (yMinus<0.0) {UTRISE = HOUR+zero1; RISE=true;}
			else {UTSET = HOUR+zero1; SETT=true;}
			break;		
		case 2:		
			if (YE<0.0) {UTRISE = HOUR+zero2; UTSET=HOUR+zero1;}
			else {UTRISE = HOUR+zero1; UTSET=HOUR+zero2;}
			RISE=true;
			SETT=true;
			break;					
	}
		
}
//---------------------------------------------
public void QUAD()
{
	NZ = 0;
	double XE;
	double A = 0.5*(yMinus+yPlus) - Y0;
	double B = 0.5*(yPlus-yMinus);
	double C = Y0;
	XE = -B/(2.0*A);
	YE = (A*XE+B)*XE + C;
	double DIS = B*B - 4.0*A*C;
	if (DIS>=0) 
	{
		DX = 0.5*Math.sqrt(DIS)/Math.abs(A);
		zero1 = XE - DX;
		zero2 = XE + DX;
		if (Math.abs(zero1)<=1.0) NZ = NZ + 1;
		if (Math.abs(zero2)<=1.0) NZ = NZ + 1;
		if (zero1<-1.0) zero1=zero2;
	}
}
//------------------------------------------------------
double sunDecRA (int what, double JD) 
	{
		final double PI2 = 2.0*Math.PI;
		final double cos_eps = 0.917482;
		final double sin_eps = 0.397778;				
		double M, DL, L, SL, X, Y, Z, R;
		double T;
		double DEC, RA;
		
		T = (JD - 2451545.0) / 36525.0;	// number of Julian centuries since Jan 1, 2000, 0 GMT						
		
		M = PI2*frac(0.993133 + 99.997361*T);
		DL = 6893.0*Math.sin(M) + 72.0*Math.sin(2.0*M);
		L = PI2*frac(0.7859453 + M/PI2 + (6191.2*T+DL)/1296.0E3);
		SL = Math.sin(L);
		X = Math.cos(L);
		Y = cos_eps*SL;
		Z = sin_eps*SL;
		R = Math.sqrt(1.0-Z*Z);
		DEC = (360.0/PI2)*Math.atan(Z/R);
		RA = (48.0/PI2)*Math.atan(Y/(X+R));
		if (RA<0) RA = RA + 24.0;
		if (what==1)
			return DEC;
		else
			return RA;			
	}
	
// returns sinus of elevation of the sun on the horizon
	double sin_elev (double JD, double LAT, double LONG, double DEC, double RA)
	{	
		final double K = Math.PI/180.0;
		double tau;								
		tau = 15.0*(LM_Sidereal_Time(JD, LONG) - RA);
		if (tau < 0) tau = tau + 360.0;		
		return  Math.cos(K*LAT)*Math.cos(K*DEC)*Math.cos(K*tau) + Math.sin(K*LAT)*Math.sin(K*DEC);
	}
	
//------------------------
public String makeTimeString(String whatStr, double time)
{
			String str="?";
			double diff;
			int min;
			//hRise = hRise + locOffset;
			if (time<0) time = time + 24.0;
			if (time>24) time = time - 24.0;					
			diff = time - (int)time;	
			min = (int)Math.round(diff*60);
			if (min==60) {min=0; time=time+1.0;}
			if (min>9) str = ":"; else str = ":0";		
			str = str.valueOf((int)time + str + min);
			if (time<10) str= "0" + str;
			return whatStr + "  " + str;	
}
//-------------------------
double Jul_Date (int date, int month, int year, double ut)
	{		
		double A, B, MJD;
									
		A = 10000.0*year + 100.0*month + date;
		if (month<=2) {month=month+12; year=year-1;}
		if (A<=15821004.1) 
			B = -2 + (int)((year+4716)/4) - 1179;
		else
			B = (int)(year/400) - (int)(year/100) +(int)(year/4);			
		A = 365.0*year - 679004.0;
		MJD = A + B + (int)(30.6001*(month+1)) + date + ut/24.0;
		return MJD + 2400000.5;			
	}
//--------------------------------
	double frac(double x) {	
		x = x - (int)x;
		if (x<0) x = x + 1.0;
		return x;		
	}
// returns local mean sidereal time
	double LM_Sidereal_Time (double JD, double LONG)
	{
		double GMST = GM_Sidereal_Time (JD);			
		return  24*frac((GMST - LONG/15.0) / 24.0);
	}
// compute Greenwich mean sidereal time		
	double GM_Sidereal_Time (double JD) 
	{	
		double t_eph;
		double ut;
		long MJD0;
		double MJD;
				
		MJD = JD - 2400000.5;		
		MJD0 = (long)MJD;
		ut = (MJD - (long)MJD0)*24.0;		
		t_eph  = (MJD0-51544.5)/36525.0;			
		return  6.697374558 + 1.0027379093*ut + (8640184.812866 + (0.093104 - 0.0000062*t_eph)*t_eph)*t_eph/3600.0;		
	}	

}
