/*********************************************************************************************/
/*                                                                                           */
/*  Java Image Demo - Animated Spiral Pattern                                                */
/*  Auth: bkenwright@xbdev.net                                                               */
/*  URL: www.xbdev.net                                                                       */
/*                                                                                           */
/*********************************************************************************************/

import java.awt.image.*;
import java.awt.*;
import java.applet.*;


class physics 
{
	public double x, y;    // position
	public double vx, vy;  // velocity
	public double mass;    // make use this ain't zero
	public double fx, fy;  // accumulated forces

	/** Apply a force to the unit. **/
	public void applyForce( double fx, double fy ) 
        {
		this.fx += fx;
		this.fy += fy;
	}

	/** Integrate using basic euler method. **/
	public void integrate( double dt ) 
        {
		// update position given current velocity
		// using euler
		x = x + dt*vx;
		y = y + dt*vy; // calculate acceleration caused by forces
		// uses newtons second law f = ma
		double ax = fx/mass;
		double ay = fy/mass;

		// update the velocities given accelerations
		// again using euler
		vx = vx + dt*ax;
		vy = vy + dt*ay;

                //capspeed( 100.0 );
		// then best to deal with friction (see "jitters")
		// ...
		//////////////// // then cancel out the accumulated forces
		// as they have been used up for this timestep
		fx = 0;
		fy = 0;
	}

        void capspeed(double MAX_SPEED)
        {
                // vx, vy are velocities in x and y directions
                double MAX_SPEED_SQUARED = MAX_SPEED*MAX_SPEED;
                double speedSquared = vx*vx + vy*vy;
                if ( speedSquared > MAX_SPEED_SQUARED ) 
                {
	           // calculate the direction vector of the velocity
	           double speed = Math.sqrt( speedSquared );
	           double dx = vx/speed;
	           double dy = vy/speed;
	           // then adjust velocity so it has same direction
	           // but is moving at max speed
	           vx = dx*MAX_SPEED;
	           vy = dy*MAX_SPEED;
                }//End if
        }// End capspeed()
}


class ball extends physics
{
   public ball( ball p )
   {
      x = p.x;
      y = p.y;
      vx = p.vx;
      vy = p.vy;
      fx = p.fx;
      fy = p.fy;
      w  = p.w;
      h  = p.h;
      mass = p.mass;
   }
   public ball(){ x = y = vx = vy = fx = fy = 0; }
   public float w, h;
}//End class ball


public class bouncingball extends Applet implements Runnable
{
	private Thread m_thread        = null;
	// Screen width and height
	int w, h;

        ball b = new ball();

        public void init()
        {
           w = getSize().width;
           h = getSize().height;

           b.x = w/2;
           b.y = 50;
           b.mass  = 3.0f;
           b.w = 30;
           b.h = 30;

        }//End init()

        
        double col_check( double dtt, int depth)
        {
           ball btemp = new ball(b);
           
           btemp.integrate(dtt);
           int col = collisioncheck(btemp);
           if( col == 1 )
           {
              if( depth > 2 )
              {
                 return dtt;
              }
              else
              {
                 //System.out.println("depth++: " + depth + " dt/2:" + dtt );
                 return col_check(dtt/2, depth++);
              }
              
           }
           
           return dtt;

        }//End col_check(..)
        

        double fg = 9.8;
	public synchronized void update(Graphics g)
	{
            /* gravity 9.8 m/s */
            //double fg = 9.8;

            b.applyForce(0, fg);
            double dt = 0.5;
            
            double v = col_check(dt, 1);
            b.integrate(v);

            System.out.println("vel: " + b.vy);
            if( Math.abs(b.vy) < 10 )
            {
               if( collisioncheck(b) == 1 )
               {
                 b.vy=0;
                 v=dt;
                }
            }

            if( v< dt/2 ) //collisioncheck(b) == 1 )
            {
               damp_inverse(b);
            }


            //b.integrate(dt);
            //collisioncheck(b);
            //damp_inverse(b);
                        
            clearscreen(g);
            drawBall(g);
	}// End update(..)

    
        public int collisioncheck(ball bb)
        {
           //double k = 0.6; // damping coeficient
           if( (bb.y + bb.h) >= h )
           {
              //System.out.println( "vy: " + bb.vy );
              //if( bb.vy < 20.0 ) bb.vy = bb.vy * 0.7;
              //if( bb.vy < 4.0 ) bb.vy = 0;

              //bb.vy = -bb.vy * k;
              //bb.y = h - bb.h;

              return 1;
           }
           return 0;
        }//End collisioncheck()

        public void damp_inverse(ball bb)
        {
            double k = 0.8; // damping coeficient

            bb.vy = -bb.vy * k;
            //bb.y = h - bb.h;
        }//damp_inverse(..)

        public void drawBall(Graphics g)
        {
            g.setColor(Color.blue);
            g.fillOval( (int)b.x, (int)b.y, (int)b.w, (int)b.h);

        }//End drawBall(..)


        public void clearscreen(Graphics g)
        {
            g.setColor( Color.white );
            g.fillRect( 0, 0, w, h );

        }//End clearscreen(..)

        public void destroy()
        {
            bRun = false;
            m_thread = null;
        }

        boolean bRun = true;
        public void run()
	{
             // Remember the starting time
             long thenTime = System.currentTimeMillis();
             while (bRun) 
             {
                   long nowTime = System.currentTimeMillis();
                   long difTime = nowTime - thenTime;
			    
                   // I've set the delay to 0, so its pushing for the MAX fps, you would
                   // set a value in there to limit for example to 25-50 fps refresh rate
                   if( difTime > 45 )
                   {
                        thenTime = nowTime;
                        // This method provides better updates, instead of filling the
                        // message queue up
                        Graphics g=this.getGraphics();
                        update(g);
                   }
                   try{
                   m_thread.sleep(10);
                   }catch (InterruptedException e){}
             }// end while loop
	}// End of run() method
	
	
	public void start()
	{
		if(m_thread == null)
                {
			m_thread = new Thread(this);
			//m_thread.setPriority(Thread.MAX_PRIORITY);
			m_thread.start();
		}
		System.out.println( "Starting Bouncing Ball Graphics Demo\n" );
	}// End of start()
	
}// End of Applet



