/*
 * NewJApplet.java
 *
 * Created on April 21, 2008, 5:49 PM
 */

import java.awt.*;
import java.awt.event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import java.awt.Graphics2D;
import java.awt.geom.*;
import java.text.*;
import java.awt.image.BufferedImage;

/**
 *
 * @author  root
 */
public class NewJApplet extends javax.swing.JApplet
        implements Runnable {

    private volatile Thread calculatorThread;
    DecimalFormat df, df1;
    BufferedImage image;
    Graphics2D gb;
    Point point1, point2;
    double[][] history;
    double[] predict;
    double[] deriv;
    double[] current;
    double[] lastcoor;
    int maxorder = 8;
    double deltat = 0.01;
    double time;
    double[] exact;
    double totalerror;
    int method = 0;
    int mymethod = 0;
    double totaltime = 5.0;
    double mytotaltime = 5.0;
    int ybas = 50;

    /** Initializes the applet NewJApplet */
    public void init() {
        try {
            java.awt.EventQueue.invokeAndWait(new Runnable() {

                public void run() {
                    initComponents();
                }
            });
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        init_variables();
        reset();
    }

    public void run() {
        Thread thisThread = Thread.currentThread();
        while (calculatorThread == thisThread) {
            try {
                thisThread.sleep(1);
            } catch (InterruptedException e) {
            }
            mymethod = method;
            mytotaltime = totaltime;
            scan();
            stop();
        }
    }

    public void start() {
        if (calculatorThread == null) {
            calculatorThread = new Thread(this);
            calculatorThread.start();
        }
    }

    public void stop() {
        Thread tmpcalculatorThread = calculatorThread;
        calculatorThread = null;
        if (tmpcalculatorThread != null) {
            tmpcalculatorThread.interrupt();
        }
    }

    /** This method is called from within the init() method to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        jPanel1 = new myPanel();
        jComboBox1 = new javax.swing.JComboBox();
        jSlider1 = new javax.swing.JSlider();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();

        jButton1.setText("STOP");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jPanel1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanel1MouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                jPanel1MousePressed(evt);
            }
        });
        jPanel1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                jPanel1MouseDragged(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 467, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 474, Short.MAX_VALUE)
        );

        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Euler", "ab2", "ab3", "ab4", "ab5", "ab6", "ab7", "verlet" }));
        jComboBox1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jComboBox1ActionPerformed(evt);
            }
        });

        jSlider1.setMinimum(1);
        jSlider1.setValue(50);
        jSlider1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jSlider1MouseReleased(evt);
            }
        });
        jSlider1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                jSlider1MouseDragged(evt);
            }
        });

        jLabel1.setText("total time = 5.0");

        jLabel2.setText("jLabel2");

        jLabel3.setText("prefactor");

        jLabel4.setText("slope");

        jLabel5.setText("click and draw a line");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jButton1)
                    .addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1)
                    .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel3)
                    .addComponent(jLabel4)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(12, 12, 12)
                        .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(jLabel5))
                .addContainerGap(293, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(21, 21, 21)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(20, 20, 20)
                        .addComponent(jLabel2)
                        .addGap(18, 18, 18)
                        .addComponent(jButton1)
                        .addGap(31, 31, 31)
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(57, 57, 57)
                        .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(65, 65, 65)
                        .addComponent(jLabel3)
                        .addGap(42, 42, 42)
                        .addComponent(jLabel4)
                        .addGap(37, 37, 37)
                        .addComponent(jLabel5))
                    .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(79, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        stop();       // TODO add your handling code here:
    }//GEN-LAST:event_jButton1ActionPerformed

    private void jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jComboBox1ActionPerformed
        stop();
        method = jComboBox1.getSelectedIndex();
        gb.clearRect(0, 0, 550, 650);
        reset();
        start();// TODO add your handling code here:
    }//GEN-LAST:event_jComboBox1ActionPerformed

    private void jSlider1MouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jSlider1MouseDragged
        jLabel1.setText("total time =" + df1.format(jSlider1.getValue() * 0.1));  // TODO add your handling code here:
    }//GEN-LAST:event_jSlider1MouseDragged

    private void jSlider1MouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jSlider1MouseReleased
        stop();
        totaltime = jSlider1.getValue() * 0.1;
        jLabel1.setText("total time =" + df1.format(totaltime));
        gb.clearRect(0, 0, 550, 650);
        reset();
        start();
    // TODO add your handling code here:
    }//GEN-LAST:event_jSlider1MouseReleased

    private void jPanel1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPanel1MouseClicked
    // TODO add your handling code here:
    }//GEN-LAST:event_jPanel1MouseClicked

    private void jPanel1MouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPanel1MouseDragged
        double x, y, x0, y0, slope, pref;
        Graphics g = jPanel1.getGraphics();
        Graphics2D g2 = (Graphics2D) g;
        point2 = jPanel1.getMousePosition();
        x = point2.getX() / 50.0;
        y = (point2.getY() - ybas) / 20;

        x0 = point1.getX() / 50.0;
        y0 = (point1.getY() - ybas) / 20;



        g2.drawImage(image, 0, 0, null);
        g2.drawLine((int) point1.getX(), (int) point1.getY(), (int) point2.getX(), (int) point2.getY());

        if (Math.abs(x - x0) > 0.01) {
            slope = (y - y0) / (x - x0);
            pref = y - x * slope;
            jLabel3.setText("prefactor=" + df1.format(pref));
            jLabel4.setText("slope=" + df1.format(slope));
        }

    /// TODO add your handling code here:
    }//GEN-LAST:event_jPanel1MouseDragged

    private void jPanel1MousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPanel1MousePressed
        double x, y;
        //stop();
        point1 = jPanel1.getMousePosition();
        point2 = point1;

        x = point1.getX() / 50.0;
        y = (point1.getY() - ybas) / 20;

    //x=Math.pow(-point1.getX()/50,10);
    //y=(point1.getY()-ybas)/20;
    //y=Math.pow(-y,10);




    // TODO add your handling code here:
    }//GEN-LAST:event_jPanel1MousePressed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JComboBox jComboBox1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JSlider jSlider1;
    // End of variables declaration//GEN-END:variables
    void init_variables() {
        history = new double[4][maxorder];
        current = new double[4];
        predict = new double[4];
        deriv = new double[4];
        exact = new double[4];
        lastcoor = new double[2];
        df = new DecimalFormat("0.000000E00");
        df1 = new DecimalFormat("0.0");
        point1 = new Point(0, 0);
        point2 = new Point(0, 0);

        image =
                new BufferedImage(550, 650, BufferedImage.TYPE_INT_RGB);
        gb = (Graphics2D) image.createGraphics();
        gb.setBackground(Color.white);
        gb.clearRect(0, 0, 550, 650);

    }

    void reset() {
        int i;




        // calculate starting history x=cos t  y=sin t
        // vx=-sin t  vy=cos t  ax=-cos t ay=-sin t

        for (i = 1; i < maxorder; i++) {

            history[0][i - 1] = -Math.sin(-i * deltat);
            history[1][i - 1] = Math.cos(-i * deltat);
            history[2][i - 1] = -history[1][i - 1];
            history[3][i - 1] = history[0][i - 1];


        }

        lastcoor[0] = Math.cos(-deltat);
        lastcoor[1] = Math.sin(-deltat);

        current[0] = 1;
        current[1] = 0;
        current[2] = 0;
        current[3] = 1;

        time = 0;


    }

    void calc_forces() {

        double r, r2, x, y, vx, vy;

        x = current[0];
        y = current[1];
        vx = current[2];
        vy = current[3];

        r2 = (x * x + y * y);
        r = Math.sqrt(r2);
        deriv[2] = -x / (r * r2);
        deriv[3] = -y / (r * r2);
        deriv[0] = vx;
        deriv[1] = vy;
    }

    void cycle(int norder) {
        int i, j;

        for (j = 0; j < 4; j++) {
            for (i = norder - 1; i >= 0; i--) {
                history[j][i + 1] = history[j][i];

            }
            history[j][0] = deriv[j];
        }



    }

    void exact_values() {

        exact[0] = Math.cos(time);
        exact[1] = Math.sin(time);

        exact[2] = -exact[1];
        exact[3] = exact[0];


    }

    void advance() {

        calc_forces();




        switch (mymethod) {
            case 0:
                Euler();
                break;
            case 1:
                ab2();
                break;
            case 2:
                ab3();
                break;
            case 3:
                ab4();
                break;
            case 4:
                ab5();
                break;
            case 5:
                ab6();
                break;
            case 6:
                ab7();
                break;
            case 7:
                verlet();
                break;
            default:
                break;
        }

        time += deltat;



    }

    void verlet() {
        int i;
        double newval;

        for (i = 0; i < 2; i++) {

            newval = 2 * current[i] - lastcoor[i] + deriv[i + 2] * deltat * deltat;
            lastcoor[i] = current[i];
            current[i] = newval;

        }

    }

    void ab7() {
        int i;
        cycle(7);
        for (i = 0; i < 4; i++) {

            current[i] += (deltat * (198721 * history[i][0] - 447288 * history[i][1] + 705549 * history[i][2] - 688256 * history[i][3] + 407139 * history[i][4] - 134472 * history[i][5] + 19087 * history[i][6]) / 60480);


        }
    }

    void ab6() {
        int i;
        cycle(6);
        for (i = 0; i < 4; i++) {

            current[i] += (deltat * (4277 * history[i][0] - 7923 * history[i][1] + 9982 * history[i][2] - 7298 * history[i][3] + 2877 * history[i][4] - 475 * history[i][5]) / 1440);


        }



    }

    void ab5() {
        int i;
        cycle(5);
        for (i = 0; i < 4; i++) {

            current[i] += (deltat * (1901 * history[i][0] - 2774 * history[i][1] + 2616 * history[i][2] - 1274 * history[i][3] + 251 * history[i][4]) / 720);


        }



    }

    void ab4() {
        int i;
        cycle(4);
        for (i = 0; i < 4; i++) {

            current[i] += (deltat * (55 * history[i][0] - 59 * history[i][1] + 37 * history[i][2] - 9 * history[i][3]) / 24);


        }



    }

    void ab3() {
        int i;
        cycle(3);
        for (i = 0; i < 4; i++) {

            current[i] += (deltat * (23 * history[i][0] - 16 * history[i][1] + 5 * history[i][2]) / 12);

        }

    }

    void ab2() {
        int i;

        cycle(2);
        for (i = 0; i < 4; i++) {

            current[i] = current[i] + 0.5 * deltat * (3 * history[i][0] - history[i][1]);


        }

    }

    void Euler() {

        int i;
        for (i = 0; i < 4; i++) {

            current[i] = current[i] + deltat * deriv[i];

        }
    }

    void calc_error() {
        int i;

        exact_values();
        totalerror = 0;
        for (i = 0; i < 4; i++) {
            totalerror += Math.abs(current[i] - exact[i]);
        }

    }

    void calc_error_v() {
        int i;

        exact_values();
        totalerror = 0;
        for (i = 0; i < 2; i++) {
            totalerror += Math.abs(current[i] - exact[i]);
        }

    }

    void scan() {
        int k, i, j, nsteps;
        int iy0, iy1, ix0, ix1;
        double yc;



        Graphics g = jPanel1.getGraphics();

        Graphics2D g2 = (Graphics2D) g;

        gb.setColor(Color.black);

        yc = 1.0;
        for (i = 0; i < 16; i++) {
            hline(yc);
            yc *= 0.1;

        }
        yc = 0.1;
        for (i = 1; i < 16; i += 2) {
            hlab(i, yc);
            yc *= 0.01;

        }



        yc = 0.1;
        for (i = 0; i < 8; i++) {
            vline(yc);
            vlab(i + 1, yc);
            yc *= 0.1;


        }
        gb.drawString("time step", 200, 400);
        gb.drawString("sum of absolute coordinate errors", 100, 20);
        gb.setColor(Color.red);

        deltat = 0.1;
        for (k = 1; k < 40; k++) {

            jLabel2.setText("" + (k + 1) + " of 40");

            reset();
            nsteps = (int) (mytotaltime / deltat);

            for (i = 0; i < nsteps; i++) {
                advance();


                if (Thread.interrupted()) {
                    //We've been interrupted: no more crunching.
                    return;

                }
            }
            if (mymethod == 7) {
                calc_error_v();
            } else {
                calc_error_v();
            }

            ix0 = -(int) (Math.log10(deltat) * 50);
            iy0 = ybas - (int) (Math.log10(totalerror) * 20);
            gb.fillOval(ix0 - 4, iy0 - 4, 8, 8);
            g2.drawImage(image, 0, 0, null);
            g2.drawLine((int) point1.getX(), (int) point1.getY(), (int) point2.getX(), (int) point2.getY());

            deltat = deltat * 0.7;
            
           

        }



    }

    void hline(double y) {
        int iy0;
        iy0 = ybas - (int) (Math.log10(y) * 20);
        gb.drawLine(50, iy0, 400, iy0);


    }

    void hlab(int om, double y) {
        int ix0, iy0;
        iy0 = ybas - (int) (Math.log10(y) * 20);
        ix0 = 20;
        gb.drawString("10", ix0 - 10, iy0 + 5);
        gb.drawString("-" + om, ix0 + 5, iy0);

    }

    void vline(double x) {
        int ix0;
        ix0 = -(int) (Math.log10(x) * 50);
        gb.drawLine(ix0, ybas, ix0, 360);
    }

    void vlab(int om, double x) {
        int ix0, iy0;
        ix0 = -(int) (Math.log10(x) * 50);
        iy0 = 380;
        gb.drawString("10", ix0 - 10, iy0);
        gb.drawString("-" + om, ix0 + 5, iy0 - 5);

    }

    public class myPanel extends javax.swing.JPanel {

        int iy0, iy1, ix0, ix1;

        public void paint(Graphics g) {
            int k, i, j, nsteps;

            Graphics2D g2 = (Graphics2D) g;

            super.paintComponent(g);
            g2.drawImage(image, 0, 0, null);



        }
    }
}
