package Mechanics;

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.image.*;
import JSci.physics.*;
import java.util.*;
/**
 * Angular momentum simulator.
 * @author Mark Hale
 * @version 1.0
 */
public final class Rotation_4 extends Frame implements Runnable {
    //private RigidBody2D body=new RigidBody2D();
    //private RigidBody2D body1=new RigidBody2D();
    private RigidBody2D[] objects = new RigidBody2D[3];
    private Display display=new Display();
    
    public static void main(String arg[]) {
        Frame app = new Rotation_4();
        app.setSize(1000,1000);
        app.setVisible(true);
    }
    public Rotation_4() {
        super("Rotation11111!");
        add(display,"Center");
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                dispose();
                System.exit(0);
            }
        });
        objects[0] = new RigidBody2D();
        objects[0].setMass(200000);
        objects[0].setMomentOfInertia(5.1);
        objects[0].setAngularVelocity(0.4);
        objects[0].setVelocity(20,0);
        objects[0].setPosition(200,200);
        
        objects[1] = new RigidBody2D();
        objects[1].setMass(200000);
        objects[1].setMomentOfInertia(5.1);
        objects[1].setAngularVelocity(0.2);
        objects[1].setVelocity(-20,0);
        objects[1].setPosition(200,400);

        objects[2] = new RigidBody2D();
        objects[2].setMass(200000);
        objects[2].setMomentOfInertia(5.1);
        objects[2].setAngularVelocity(1.6);
        objects[2].setVelocity(30,30);
        objects[2].setPosition(300,300);
 
        
        Thread thr=new Thread(this);
        thr.start();
    }
    public void run() {
        double width,height;
        double x,y;
        while(true) {
            display.repaint();
            try {
                Thread.sleep(20);
            } catch(InterruptedException e) {}
        }
    }
    private final class Display extends Canvas {
        private boolean firstTime = true;
        BufferedImage bi;
        Graphics2D big;
        Area[] shapes = new Area[3];
        GradientPaint gradient;
        Area tmpShape = new Area();
        AffineTransform[] af = new AffineTransform[3];
        boolean[] firstCollide = new boolean[3];
        AffineTransform tmpAf = new AffineTransform();
        Rectangle2D area;
        double eps = 0.00000000000001;
        double dt = 0.1;
        
        public void paint(Graphics g) {
            update(g);
        }
        
        public void update(Graphics g) {
            
            Graphics2D g2 = (Graphics2D)g;
            
            if(firstTime){
                Dimension dim = getSize();
                int w = dim.width;
                int h = dim.height;
                area = new Rectangle2D.Double(0,0,1000,1000);
                
                bi = (BufferedImage)createImage(w, h);
                big = bi.createGraphics();
                big.setColor(Color.white);
                big.fill(area);
                //big.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
                
                
                for(int i=0;i<objects.length;i++) {
                    //Ellipse2D e2D = new Ellipse2D.Double(-50,-50,100,100);
                    
                    shapes[i] = new Area( new Rectangle2D.Double(-20,-20,40,40) );
                    
                    //shapes[i] = AffineTransform.getRotateInstance(objects[i].getAngle()).createTransformedArea(shapes[i]);
                    af[i] = new AffineTransform();
                    af[i].rotate(objects[i].getAngle());
                    af[i].translate(objects[i].getXPosition(),objects[i].getYPosition());
                    shapes[i] = shapes[i].createTransformedArea(af[i]);

                }
                firstTime = false;
            }
            
            
            long sTime = System.currentTimeMillis();
            
            objects[1].gravitate(objects[0], dt);
            objects[2].gravitate(objects[1], dt);
            objects[2].gravitate(objects[0], dt);

            big.setColor(Color.white);
            big.fill(area);
            //big.draw(shapes[i]);

            
            for(int i=0;i<objects.length;i++) {
                //big.setColor(Color.white);
                //big.fill(shapes[i]);
                //big.draw(shapes[i]);
                af[i].setToIdentity();//.setTransform(tmpAf);
                
                //af[i].setToTranslation(objects[i].getXVelocity()*dt,objects[i].getYVelocity()*dt);
                //af[i].translate(objects[i].getXVelocity()*dt,objects[i].getYVelocity()*dt);
                //shapes[i].transform(af[i]);
                
                af[i].rotate(objects[i].getAngularVelocity()*dt,objects[i].getXPosition(),objects[i].getYPosition());//,0,0);
                af[i].translate(objects[i].getXVelocity()*dt,objects[i].getYVelocity()*dt);
                //af[i].rotate(objects[i].getAngularVelocity()*dt);//,0,0);
                shapes[i] = shapes[i].createTransformedArea(af[i]);
                objects[i].move(dt);
                
                Area tmpShape1 = new Area(shapes[i]);
                for( int j=0;j<i;j++) {
                    tmpShape.reset();
                    tmpShape = new Area(shapes[j]);
                    tmpShape.intersect( tmpShape1 );
                    if ( !tmpShape.isEmpty() && firstCollide[i] == false) {
                        
                        double x1 = objects[i].getXPosition() - objects[j].getXPosition();
                        double y1 = objects[i].getYPosition() - objects[j].getYPosition();
                        double x2 = objects[i].getXVelocity() - objects[j].getXVelocity(); 
                        double y2 = objects[i].getYVelocity() - objects[j].getYVelocity(); 

                        
                        double cos = (x1*x2+y1*y2)/( Math.sqrt(x1*x1+y1*y1)* Math.sqrt(x2*x2+y2*y2) ); 
                        if (cos>1) cos=1;
                        if (cos<-1) cos=-1;
                        double theta = Math.PI + Math.acos(cos );
                        objects[i].collide(objects[j],theta,1);
                        objects[i].angularCollide(objects[j],1);
                        firstCollide[i] = true;
                    }else if ( !tmpShape.isEmpty() ) {
                        
                    }else{
                        firstCollide[i] = false;
                    }
                    
                }
                
                //objects[i].move(dt);
                
                big.setColor(Color.red);
                /*
                gradient =  new GradientPaint(
                (int)objects[i].getXPosition(), (int)objects[i].getYPosition(), Color.red,
                (int)(objects[i].getXPosition() + Math.sin(objects[i].getAngle())*50),
                (int)( objects[i].getYPosition() + Math.cos(objects[i].getAngle())*50 ), Color.yellow,true); // true means to repeat pattern
                big.setPaint(gradient);
                 */
                big.fill(shapes[i]);
            }
            
            
            
            // objects[2].move(dt);
            
            for(int i=0;i<objects.length;i++) {
                Line2D l2d = new Line2D.Double(
                objects[i].getXPosition(),objects[i].getYPosition(),
                objects[i].getXPosition()+ objects[i].getXVelocity(),objects[i].getYPosition()+objects[i].getYVelocity()
                );
                big.setColor(Color.black);
                big.draw(l2d);
                
            }
            long eTime = System.currentTimeMillis();
            
            g2.drawImage(bi, 0, 0, this);
            long dTime = System.currentTimeMillis();
            System.out.println( (eTime-sTime) + " " + ( dTime-eTime) );
            
        }
    }
}


