import java.lang.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.imsl.*;
import com.imsl.chart.*;
import com.imsl.math.*;

/**
 * Hilfsklasse für die Integration von OdeRungeKutta in imsl.chart
 */
class RungeKuttaData extends Data
{
    public RungeKuttaData(ChartNode parent,double[][] runge_kutta_result)
    {
	super(parent,getParam(runge_kutta_result,0),getParam(runge_kutta_result,1));
    }

    public static double[] getParam(double[][] list,int pos)
    {
	int len = list.length;
	double[] p = new double[len];
	for (int i=0; i<len; i++)
	    {
		p[i] = list[i][pos];
	    }
	return p;
    }

    public static double[][] doRungeKutta(double[] y0,double a,double b,int steps,
					  OdeRungeKutta.Function f)
	throws IMSLException
    {
	OdeRungeKutta q = new OdeRungeKutta(f);
	Vector results = new Vector();
	double h = (b-a)/steps;

	double[] y = (double[])y0.clone();
	for (double t=a; t<b; t+=h)
	    {
		results.add(y.clone());
		q.solve(t, t+h, y);
	    }
	results.add(y);

	double[][] r = new double[results.size()][];
	results.toArray(r);
	return r;
    }
}

/**
 * Hilfsklasse zum Zeichnen von Kreisen in ein imsl.chart
 */
class Circle implements ChartFunction
{
    public double xm;
    public double ym;
    public double r;
    public double s;

    public Circle(double xm_,double ym_,double r_)
    {
	xm = xm_;
	ym = ym_;
	if (r_ > 0)
	    {
		r = r_;
		s = 1;
	    }
	else
	    {
		r = -r_;
		s = -1;
	    }
    }
    
    public double f(double x)
    {
	return ym + s * Math.sqrt(r*r - Math.pow(x-xm,2));
    }

    public static void addCircle(AxisXY axis,double xm,double ym,double r,Color color,String title)
    {
	Data d;
	d = new Data(axis,new Circle(xm,ym,r),xm-r,xm+r);
        d.setTitle(title);
        d.setLineColor(color);
	d = new Data(axis,new Circle(xm,ym,-r),xm-r,xm+r);
        d.setLineColor(color);
    }
};

/**
 * Hilfsklasse für bequemere Parameter-Übergabe
 */
class Params extends Properties
{
    public void setP(String key, String value)
    {
	setProperty(key,value);
    }

    public String getP(String key)
    {
	return getProperty(key);
    }

    public int getI(String key) throws NumberFormatException
    {
	return Integer.parseInt(getP(key));
    }

    public double getD(String key) throws NumberFormatException
    {
	return Double.parseDouble(getP(key));
    }
}

/**
 * Swing-Zugang für Params
 */
class ParamsPane extends JPanel
{
    Vector formats = new Vector();
    GridLayout layout;

    public ParamsPane()
    {
	super();

	layout = new GridLayout(0,2,8,0);
	setLayout(layout);
    }

    public void add(String label,String latex_name,String name,String value)
    {
	layout.setRows(layout.getRows()+1);

	add(new Label(label+":"));
	JTextField textfield=new JTextField(value,16);
	add(textfield);

	Object[] info={name,latex_name,textfield};
	formats.add(info);
    }

    public Params getParams()
    {
	Params p = new Params();
	for (Iterator i=formats.iterator();i.hasNext();)
	    {
		Object[] info = (Object[])i.next();
		String name = (String)info[0];
		String latex_name = (String)info[1];
		JTextField textfield = (JTextField)info[2];
		p.setP(name,textfield.getText());
	    }
	return p;
    }

    public void setParams(Params p)
    {
	for (Iterator i=formats.iterator();i.hasNext();)
	    {
		Object[] info = (Object[])i.next();
		String name = (String)info[0];
		String latex_name = (String)info[1];
		JTextField textfield = (JTextField)info[2];
		textfield.setText(p.getP(name));
	    }
    }

    public String getLatex()
    {
	String s = "\\grafik{bahn-}{";
	for (Iterator i=formats.iterator();i.hasNext();)
	    {
		Object[] info = (Object[])i.next();
		String name = (String)info[0];
		String latex_name = (String)info[1];
		JTextField textfield = (JTextField)info[2];
		s += "$"+latex_name+" = "+textfield.getText()+"$, ";
	    }
	s += "}";
	return s;
    }
}

/**
 * Haupt-Klasse
 */
public class a5 extends JFrame
{
    public static class TestDGL implements OdeRungeKutta.Function
	{
	    public void f(double t, double y[], double yprime[])
	    {
		yprime[0] = 2. * y[0] * (1-y[1]);
		yprime[1] = -y[1] * (1-y[0]);
	    }
        };

    /**
     * Unsere gegebene DGL
     */
    public static class SatellitenDGL implements OdeRungeKutta.Function
	{
	    public double mu = 0.0;

	    public void f(double t, double y[], double yprime[])
	    {
		double x1 = y[0];
		double x2 = y[1];
		double x1p = y[2];
		double x2p = y[3];
		double muq = 1-mu;
		double n1 = Math.pow(Math.pow(x1+mu,2)+x2*x2,1.5);
		double n2 = Math.pow(Math.pow(x1-muq,2)+x2*x2,1.5);

		yprime[0] = x1p;
		yprime[1] = x2p;
		yprime[2] = x1 + 2*x2p - muq*(x1+mu)/n1 - mu*(x1-muq)/n2;
		yprime[3] = x2 - 2*x1p - muq*x2/n1 - mu*x2/n2;
	    }
        };

    /**
     * Malen der Grafik
     */
    public static void showSatellit(Params p)
	throws IMSLException, NumberFormatException
    {
	double[] y0 = {p.getD("x1"),p.getD("x2"),p.getD("x1p"),p.getD("x2p")};
	SatellitenDGL f = new SatellitenDGL();
	f.mu = p.getD("mu");
	double[][] res = RungeKuttaData.doRungeKutta(y0,p.getD("a"),p.getD("b"),p.getI("steps"),f);

        JFrameChart frame = new JFrameChart();
        frame.setSize(800,600);
        frame.getChart().getLegend().setPaint(true);
        AxisXY axis = new AxisXY(frame.getChart());

	Data d = new RungeKuttaData(axis,res);
        d.setTitle("Satellitenbahn");
        d.setLineColor(Color.magenta);

	Circle.addCircle(axis,-f.mu,0,p.getD("r_erde"),Color.blue,"Erde");

	Circle.addCircle(axis,1-f.mu,0,p.getD("r_mond"),Color.gray,"Mond");

        frame.setVisible(true);
    }

    /**
     * Hauptfenster
     */
    public ParamsPane p;

    public a5()
    {
	super("Aufgabe 1 - Satellitenbahn");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	Container c = getContentPane();
	c.setLayout(new BorderLayout());

	p = new ParamsPane();
	c.add(BorderLayout.CENTER,p);
	p.add("x1",                     "x_1",           "x1",     "0.994");
	p.add("x1'",                    "x_1'",          "x1p",    "0");
	p.add("x2",                     "x_2",           "x2",     "0");
	p.add("x2'",                    "x_2'",          "x2p",    "-2.001585106");
	p.add("a",                      "a",             "a",      "0");
	p.add("b",                      "b",             "b",      "17.1");
	p.add("Schrittanzahl",          "Schrittanzahl", "steps",  "10000");
	p.add("µ",                      "\\mu",          "mu",     "0.012277471");
	p.add("rel. Radius der Erde",   "r_{Erde}",      "r_erde", "0.016574");
	p.add("rel. Radius des Mondes", "r_{Mond}",      "r_mond", "0.004521");

	Box box = new Box(BoxLayout.X_AXIS);
	c.add(BorderLayout.SOUTH,box);

	JButton b;

	b = new JButton("Satellitenbahn anzeigen");
	box.add(BorderLayout.SOUTH,b);
	b.addActionListener(new ActionListener(){
		public void actionPerformed(ActionEvent ev)
		{
		    try
			{
			    showSatellit(p.getParams());
			}
		    catch (Exception e)
			{
			    System.err.println(e);
			}
		}
	    });

	b = new JButton("LaTeX-Code");
	box.add(BorderLayout.SOUTH,b);
	b.addActionListener(new ActionListener(){
		public void actionPerformed(ActionEvent ev)
		{
		    System.out.println(p.getLatex());
		}
	    });


	b = new JButton("Beenden");
	box.add(BorderLayout.SOUTH,b);
	b.addActionListener(new ActionListener(){
		public void actionPerformed(ActionEvent ev)
		{
		    System.exit(0);
		}
	    });

	pack();
        setVisible(true);
    }


    /**
     * Hauptprogramm
     */
    public static void main(String[] args)
	throws IMSLException, NumberFormatException
    {
	new a5();
    }
}
