// swingbyの実験

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
//import java.util.Calendar;
//ActionEvent;
//import java.awt.event.ActionListener;
//import java.io.*;

public class swingby extends Applet implements Runnable, ActionListener, ItemListener {
	private static final long serialVersionUID = 1L;	// Elicpseで警告が出ないように。
	// GUIやスレッド
	Thread th = null;
	boolean th_flag = false;
	Button bt1,bt2,bt3;
	Choice chL;
	TextArea text1;
	Graphics g;

	// 天文計算に使う変数
	double DVI     = 1.2e+9;		// 縮小倍率
	double G       = 6.672e-11;		// 重力定数
	double sun_M   = 1.981e+30;		// 太陽の質量 Kg
	double earth_M = 5.974e+24;		// 地球の質量
	double au      = 1.4959787e+11;	// AU（地球と太陽の距離）
	double m       = 1000.0;		// 衛星の質量	
	double min_dt  = 10.0*2.0;		// 最小の時間間隔(秒)

	double dt,t;					// 秒
	double earth_x,earth_y;
	double earth_vx,earth_vy;
	double x,y,vx,vy;
	double r,f,fx,fy,dx,dy,before_x,before_y;
	double min_r;
	double zoom_mul;		// 拡大表示する距離
	double L;
	double first_r,first_v;
	int d;
	int bx,by;
	int bdx[] = new int[2];
	int bdy[] = new int[2];
	int i;

	public void init() {
//		setLayout(new BorderLayout());  
		g = getGraphics();
		
		bt1 = new Button("Start");
		add(bt1);
		bt2 = new Button("Stop");
		add(bt2);
		bt3 = new Button("Clear");
		add(bt3);
/*
		text1 = new TextArea(1, 20);       // 5行×30字のテキスト領域
        text1.setEditable(false);          // テキスト枠は編集不可
        text1.setLocation(0,230);

        Panel pa = new Panel();         // 新しいパネルを作る
        add("South", pa);               // それを南側（下側）に貼る
        pa.add(new Label("位置と速度:"));
        pa.add(text1);
//      add("South",text1);
        text1.appendText("hogegegeg");    
*/        
        bt1.addActionListener(this);
        bt2.addActionListener(this);
        bt3.addActionListener(this);

		chL = new Choice();
		chL.add("地球の上からスイングバイ。地球の0.65倍の速度から");
		chL.add("地球の下からスイングバイ");
		chL.add("減速スイングバイ。上から下。地球の1.1倍の速度から");
		chL.add("減速スイングバイ。下から上");
		chL.select(0);
		chL.addItemListener(this);
		add(chL);
		
		resize(800,600);
		setBackground(Color.black);
//		setForeground(Color.green);
		initParam();

		if ( th == null ) {
			th = new Thread(this);
			th.start();
		}
	}

    public void actionPerformed(ActionEvent e) {
    	Object src = e.getSource();
    	if ( src == bt1 ) {
//			if ( !th_flag ) th.resume();
			th_flag = true;
    	}
    	if ( src == bt2 ) {
//			if ( th_flag ) th.suspend();
			th_flag = false;
    	}
    	if ( src == bt3 ) {
			initParam();
    	}
    }
    
    public void itemStateChanged(ItemEvent e) {
    	Object src = e.getSource();
//    	boolean on = e.getStateChange() == ItemEvent.SELECTED;
		if ( src == chL ) {
			initParam();
		}
	}

	// 変数を初期化
	public void initParam() {
		t = 0;
		dt = 1.0;				// 時間間隔 1 day (sec)
		earth_x = 0.0;
		earth_y = au; 
		earth_vx = Math.sqrt( sun_M*G /earth_y);
		earth_vy = 0.0;
		min_r = +1.0e+100;			// 地球と衛星の最接近距離（地球の半径以下だとぶつかるよ）
//		L = 8.64e+5 * earth_vx;		// 10日後に遭遇
		zoom_mul = 1.0;		// 拡大表示する距離
		count = 0;


		x = 0;
		y = -earth_y*0.6;		// 地球の反対側にいて、短半径が2/3ぐらい。
		vx = -earth_vx*1.45;		// その時の速度 
		vy = 0;

		x = 800000.0e+3;
		y = earth_y + 10000.0e+3;	// 3000でかなり加速。7000で16.843Km/s から 24Km/s。10000で21Km/s。11000で20Km。15000で18Km/s。
		vx = earth_vx*0.65;	// 0.65で16.843Km/s。地球の公転速度よりも65%遅い。1.45倍だと太陽系を脱出する
		vy = 0.0;

//		if ( 1 ) { earth_vx = -earth_vx; earth_y = -earth_y; }
//		if ( 1 ) { earth_vy = -earth_vx; earth_x = earth_y; earth_vx = 0; earth_y = 0; }	// 地球の初期位置を90度ずらす

		System.out.println("first earth_v =" + earth_vx);
		first_v = Math.sqrt(vx*vx+vy*vy);
		System.out.println("first       v = "+ Math.sqrt(vx*vx+vy*vy));

		dx = earth_x - x;
		dy = earth_y - y;
		first_r = Math.sqrt(dx*dx + dy*dy);
		System.out.println("r=" + first_r);

  		int n = chL.getSelectedIndex();

  		if ( n==0 || n==1 ) {	// 加速スイングバイ
//			earth_x=-117833854.190165; earth_y=-92815828.853086; earth_vx=-16.033974; earth_vy= 20.356091; x= 75764172.152060;
//			vx=6.044614; vy=-27.023199;
		} else {				// 減速
//			earth_x= 125988448.051653; earth_y= 81406061.966557; earth_vx= 14.062747; earth_vy=-21.764299; x= 93438565.991703;
//			vx=-16.720636; vy=-10.341181;
			zoom_mul = 0.4;
		}
		
		switch (n) { // 地球のどっちからスイングバイするか
		case 0:
			// 加速。65%の速度。上から下
			earth_x=-111406235087.274780; earth_y=-99840373228.224380; earth_vx=-19837.560341; earth_vy=22135.751364; x=72910181164.012268; 
			y=89733884187.145081; vx=9141.560711; vy=-28470.700662;
			break;
		case 1:
			// 加速。65%の速度。下から上
			earth_x=-123769904210.748320; earth_y=-84026508726.694382; earth_vx=-16695.451442; earth_vy=24592.324538; x=77436481403.747726;
			y=68787042693.976227; vx=4028.675953; vy=-33816.287379;
			break;
		case 2:					
			// 減速。110%の速度。上から下
			earth_x=148554342825.622280; earth_y=17641084915.031414; earth_vx=3505.064825; earth_vy=-29516.585777; x=43089485381.746483; 
			y=-219191851606.345610; vx=-21167.689920; vy=-5422.105523;
			break;
		case 3:					
			// 減速。110%の速度。下から上
			earth_x=104838664515.603160; earth_y=106716717641.045460; earth_vx=21203.737284; earth_vy=-20830.644058; x=110938227219.430730; y=-185172904392.540920; vx=-17838.946068; vy=-14137.652650;
			break;
		}

//		g.dispose();
		repaint();
	}

	public void run() {
		try {
			while (true) {
				if ( th_flag ) {
					DrawSwingby();
				} else {
					Thread.sleep(10);
				}
//				repaint();
				if ( (count&0xfff)==0 ) Thread.sleep(10);			// 1.1 ではsleep(1)とかが正しく動作しない。5以上ぐらい？
				if ( fZoom && (count&0x1ff)==0) Thread.sleep(10);
			}
		}
		catch (Exception err) {
		}
	}

	int count;
	boolean fZoom = false;
	int sx = 200;
	int sy = 250;
	public void DrawSwingby() {
		dx = earth_x - x;			// 地球と衛星の(x,y)座標の距離
		dy = earth_y - y;
		r = Math.sqrt(dx*dx + dy*dy);	// 地球と衛星の距離

		dt = r / 400000e+3;	// 距離が近いほど、ゆっくり観測する
		if ( dt > min_dt ) dt = min_dt;
//		dt = 10;
//		dt = -dt;	// 時間を逆に進めるテスト
//		dt /= 2;

		// 衛星の重力が地球に及ぼす加速度
		f = G * m * earth_M / (r*r);	// 万有引力。f(m/(s*s)) = G * m * M / (r*r)
		fx = -f*dx/r/earth_M;
		fy = -f*dy/r/earth_M;
		earth_vx += fx*dt;
		earth_vy += fy*dt;

		// 太陽の重力が地球に及ぼす加速度
		r = Math.sqrt(earth_x*earth_x + earth_y*earth_y);
		f = G * sun_M * earth_M / (r*r);
		fx = -f*earth_x/r/earth_M;
		fy = -f*earth_y/r/earth_M;
		earth_vx += fx*dt;
		earth_vy += fy*dt;
	
//		System.out.println("f=%g,x=%g,y=%g,vx=%g,vy=%g,r=%g\n",f,x,y,vx,vy,r);
//		System.out.println("x=%g\n",x);

		// 太陽が衛星に与える加速度
		r = Math.sqrt(x*x + y*y);
		f = G * sun_M * m / (r*r);
		fx = -f*x/r/m;
		fy = -f*y/r/m;
		vx += fx*dt;
		vy += fy*dt;
	
		dx = x - earth_x;
		dy = y - earth_y;
		r = Math.sqrt(dx*dx + dy*dy);

		if ( min_r > r ) min_r = r;
		
		if ( ((++count)&0x3fff)==0 || (fZoom&&(count&0x7ff)==0) ) {
			double vr = Math.sqrt(vx*vx+vy*vy);
			double ep = -G * sun_M / Math.sqrt(x*x + y*y);
			double ev = (vx*vx+vy*vy)/2.0;

			int vri = (int)(vr / 1000.0);
			int ri  = (int)(r / 1000.0);
			double eD = 1.0e+7;
			int iep = (int)(ep / eD);
			int iev = (int)(ev / eD);
			
//			String str1 = "人工衛星の速度= " + vr + "[Km/s]," + "  地球との距離= " + r + ", count= " + count;  
			String str1 = "人工衛星の速度 = " + vri + " Km/s," + "  地球との距離 = ";
			if ( ri > 100000 ) str1 +=     ri/10000 + " 万Km";  
			else           str1 += (int)ri + " Km";  
//			String str2 = "位置E=" + ep + ",運動E=" + ev + ",合計=" + (ep+ev);
			String str2 = "位置E = " + iep + " ,運動E = " + iev + " ,合計 = " + (iep+iev);// + " [x10000000]";
//			System.out.println(str1 + "ep="+ep+", ev="+ev+" ,ep+ev="+(ep+ev)+ " ,min_r=" + min_r/1000.0);
	        int tx = 10;
	        int ty = 50;
			int fy = 14;
			g.setColor(Color.black);
	        g.fillRect(tx,ty-fy,800,fy*2+2);
			g.setColor(Color.white);
			g.setFont(new Font("Serif", Font.PLAIN, fy));
//          String s1 = Float.toString((REPORTFRAMES/(rel/1000.0f)));
//          s1 = (s1.length() < 4) ? s1.substring(0,s1.length()) : s1.substring(0,4);
//			Float.toString()
//			Double.toString()
//			str2 = vr;
//			Stringstr2.intValue();
//			f = Double.valueOf(str2).floatValue();
//			str2 = String.valueOf(vr);
//		    len = Integer.valueOf(str2.substring(j+1)).intValue();
			g.drawString(str1,tx,ty);
	        g.drawString(str2,tx,ty+fy);
			g.setColor(Color.white);
			drawPixel(370 + count/10000.0, 400 - vr*3.0/1000.0);;
	        g.drawString("速度の変化",500,110);
			g.setColor(Color.orange);
	        g.drawString("位置＋運動エネルギーの変化（地球からの位置エネルギーは無視）",380,90);
			drawPixel(370 + count/10000.0, 50 - (ep+ev) / (2.0*1000.0*1000.0) );;
		}

		// 地球が衛星に与える加速度
		f = G * m * earth_M / (r*r);
		fx = -f*dx/r/m;
		fy = -f*dy/r/m;
		vx += fx*dt;
		vy += fy*dt;

		x += vx*dt;
		y += vy*dt;
		earth_x += earth_vx*dt;
		earth_y += earth_vy*dt;
		t += dt;
//		if ( x*x + y*y >= au*au ) { 
//			System.out.println("t="+t+" ,x=" + x + " ,y="+y + " ,vx=" + vx + " ,vy=" +vy);
//		}
		if ( (count&0x1ff)!=0 ) return;

		fZoom = false;
		if ( r < 80000.0e+3*zoom_mul ) {	// 距離が近づいたら拡大して別の場所に表示
			fZoom = true;
			double mul = 2000;	// 拡大倍率
			int ssx =  70;
			int ssy = 500;
//			setpixel(hDC, sx+(earth_x/DVI)*mul, sy+(start_y-(earth_y/DVI)*mul), rgbGreen );
//			setpixel(hDC, sx+(      x/DVI)*mul, sy+(start_y-(      y/DVI)*mul), rgbRed   );

			dx = earth_x - before_x;
			dy = -earth_y + before_y;
//			g.setColor(Color.green);
//			drawPixel( sx+(dx/DVI)*mul,sy+(dy/DVI)*mul );
			int xx = (int)(ssx+(dx/DVI)*mul);
			int yy = (int)(ssy+(dy/DVI)*mul);
			int d = 10;
			g.setColor(Color.black);
			g.drawOval( bx-d,by-d,d*2,d*2);
			g.setColor(Color.green);
			g.drawOval( xx-d,yy-d,d*2,d*2);
			bx = xx;
			by = yy;
			dx =  x - before_x;
			dy = -y + before_y;
			g.setColor(Color.red);
			drawPixel(ssx+(dx/DVI)*mul,ssy+(dy/DVI)*mul );

//			System.out.println("dx="+dx+",dy="+dy);
		}
		else {
			g.setColor(Color.green);
			drawPixel( sx+(earth_x/DVI),sy -(earth_y/DVI)*1 );
			g.setColor(Color.red);
			drawPixel( sx+(      x/DVI),sy -(      y/DVI)*1 );
			before_x = earth_x;
			before_y = earth_y;
		}
	}
	
	public void drawPixel(double x,double y) {
		int xx = (int)x;
		int yy = (int)y;
		int n = -1;
		Color col = g.getColor();
		if ( col == Color.red   ) n = 1;
		if ( col == Color.green ) n = 0;
		if ( n < 0 ) {
			g.drawLine(xx,yy,xx,yy);
			return;
		}
		if ( bdx[n] == xx && bdy[n] == yy ) {
			g.setColor(Color.white);
			g.drawLine(xx,yy,xx,yy);
		} else {
			g.drawLine(bdx[n],bdy[n],bdx[n],bdy[n]);
		}
		bdx[n] = xx;
		bdy[n] = yy;
	}

	public void paint(Graphics g) {
		d = 8;
		g.setColor(Color.white);
		g.fillOval(sx-d,sy-d,d*2,d*2);	// 太陽をオーバーに書く
	}
	
	public void stop() {
		if ( th != null ) {
			th.stop();
			th = null;
		}
	}
}

