/*
 ** Grabity.class - by Daniel Piron (Queens College Nucleus)
 ** -------------------------------------------------------------------------
 ** This class is where it all comes together. (more details later)
 */

import java.applet.Applet;
import java.awt.*;

public class Grabity extends Applet implements Runnable {

   private Graphics    offScreen;
   private Image       doubleBuffer;

   private final int   screenX = 400;
   private final int   screenY = 280;

   private Thread      letsgo;

   private SolarSystem solar;

   private boolean     clicked;
   private int         lastX;

   private final int   CREATEBODY = 1;
   private final int   MOVEBODY = 2;
   private final int   MOVEVIEW = 3;
   private final int   ZOOMVIEW = 4;
   private final int   LOCKBODY = 5;

   private int         controlMode;

   float   oldZoom;
   float   oldXoff;
   float   oldYoff;

   int     oldMuseX;
   int     oldMuseY;
   int     museX, museY;
   CelestialBody sun;

   public void init() {

     CelestialBody body;

     doubleBuffer = createImage(screenX, screenY);
     offScreen = doubleBuffer.getGraphics();

     solar = new SolarSystem(.08f);
     solar.setViewSpace(screenX, screenY);

     body = new CelestialBody(0, 0, 0, 0, 1200, 15);
     body.setColor(Color.white);

     solar.insertHead(body);

     sun = body;

     // set the focus to the sun

     solar.insertHead(new CelestialBody((float)(Math.random() * screenX) - (screenX / 2), (float)(Math.random() * screenY) - (screenY / 2),
                                        (float)(Math.random() * 3.0) - 1.5f, (float)(Math.random() * 3.0) - 1.5f, 35, 3));

     solar.insertHead(new CelestialBody((float)(Math.random() * screenX) - (screenX / 2), (float)(Math.random() * screenY) - (screenY / 2),
                                        (float)(Math.random() * 3.0) - 1.5f, (float)(Math.random() * 3.0) - 1.5f, 30, 3));
  
     body = new CelestialBody((float)(Math.random() * screenX) - (screenX / 2), (float)(Math.random() * screenY) - (screenY / 2),
                              (float)(Math.random() * 3.0) - 1.5f, (float)(Math.random() * 3.0) - 1.5f, 70, 5);

     solar.insertHead(body);

     solar.insertHead(new CelestialBody((float)body.getXPos() + 13, body.getYPos(),
                                        body.getXVel(),body.getYVel() + .7f, 5, 2));

     /*

     solar.insertHead(new CelestialBody((float)body.getXPos() - 13, body.getYPos(),
                                        body.getXVel(),body.getYVel() - .7f, 5, 2));

     solar.insertHead(new CelestialBody((float)(Math.random() * screenX) - (screenX / 2), (float)(Math.random() * screenY) - (screenY / 2),
                                        (float)(Math.random() * 3.0) - 1.5f, (float)(Math.random() * 3.0) - 1.5f, 40, 2));

     solar.insertHead(new CelestialBody((float)(Math.random() * screenX) - (screenX / 2), (float)(Math.random() * screenY) - (screenY / 2),
                                        (float)(Math.random() * 3.0) - 1.5f, (float)(Math.random() * 3.0) - 1.5f, 20, 3));

     body = new CelestialBody((float)(Math.random() * screenX) - (screenX / 2), (float)(Math.random() * screenY) - (screenY / 2),
                              (float)(Math.random() * 3.0) - 1.5f, (float)(Math.random() * 3.0) - 1.5f, 60, 4);

     solar.insertHead(body);   


     solar.insertHead(new CelestialBody((float)body.getXPos() - 13, body.getYPos(),
                                        body.getXVel(),body.getYVel() + .6f, 2.5f, 1.5f));

     */
     clicked = false;

     requestFocus();

     } // ends method init

   public boolean mouseUp(Event evt, int x, int y) {

      CelestialBody body;
      float xv, yv;
      float mass;

      clicked = false;

      switch(controlMode) {

         case CREATEBODY:
           xv = (float)(oldMuseX - museX) * .09f;
           yv = (float)(oldMuseY - museY) * .09f;

           mass = (float)Math.random() * 15 + 5;
           solar.createBody(oldMuseX, oldMuseY, xv, yv, mass , 2, true);
 
//         solar.insertHead(body);
           break;
         case LOCKBODY:
           body = solar.catchBody(oldMuseX, oldMuseY, museX, museY);
           if(body != null) solar.setFocus(body);
           break;

         } // ends switch

      return true;

      } // ends


   public boolean mouseDown(Event evt, int x, int y) {

      CelestialBody body;

      museX = oldMuseX = x;
      museY = oldMuseY = y;

      oldXoff = solar.xView;
      oldYoff = solar.yView;

      oldZoom = solar.zoomScale;

      clicked = true;

      return true;

      } // ends
/*
   public boolean mouseMove(Event evt, int x, int y) {

    museX = x;
    museY = y;

    return true;

    }
  */

   public boolean keyDown(Event evt, int k) {

     if(k == '1') controlMode = CREATEBODY;
     else if(k == '2') controlMode = ZOOMVIEW;
     else if(k == '3') { controlMode = MOVEVIEW; solar.setFocus(null); }
     else if(k == '4') controlMode = LOCKBODY;
     else if(k == 'S' || k == 's') solar.setFocus(sun);
     else if(k == 'F' || k == 'f') solar.setFocus(null);

     showStatus("Control Mode set to: " + (char)k);

     return true;

     }

   public boolean mouseDrag(Event evt, int x, int y) {
                
      // solar.zoomScale += ((float)(lastX - x)) * .1f;

      museX = x;
      museY = y;

      return true;

      }

   public void paint(Graphics g) {

      g.drawImage(doubleBuffer, 0, 0, this);

      } // ends paint method.

   public void update(Graphics g) {

      paint(g);

      } // ends update

   public void run() {

      controlMode = CREATEBODY;

      while(true) {

         offScreen.setColor(Color.black);
         offScreen.fillRect(0, 0, screenX, screenY);

         solar.update();

         solar.draw(offScreen);

         if(clicked) {
           switch(controlMode) {
             case CREATEBODY:
                offScreen.setColor(Color.yellow);
                offScreen.drawLine(oldMuseX, oldMuseY, museX, museY);
                break;
             case ZOOMVIEW:
                solar.zoomScale = oldZoom + (float)((oldMuseX - museX) * .01f);
                break;
             case MOVEVIEW:
                solar.setView((oldMuseX - museX) + oldXoff, (oldMuseY - museY) + oldYoff);
                break;
             case LOCKBODY:
                offScreen.setColor(Color.yellow);
                offScreen.drawRect(oldMuseX, oldMuseY, museX - oldMuseX, museY - oldMuseY);
                break;
             }
           }


         showStatus("Celestial Body Count: " + solar.getCount());

         try {
             Thread.sleep(16);       // 16 millisecond sleep time.
             } catch (InterruptedException e) {}                         

         repaint();

         } // ends infinite while loop

      } // ends method run

   // Start up the thread.
   public void start() {

      if(letsgo == null) {
         letsgo = new Thread(this);
         letsgo.setPriority(letsgo.MIN_PRIORITY); // We don't want this interfering
                                                  // with any other more important processes.

         letsgo.start();
         } // ends if

      } // ends start

   public void stop(){

      if(letsgo != null) letsgo.stop();  // if the applet viewer becomes
                                        // an inactive window, stop the Thread.
      } // ends stop


   } // ends class Grabity
