import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.lang.Math;

//Lloyd Allison

public class LAllisonImplode extends Applet implements Runnable
 { Image img, pixImg;
   int h=0, w=0;
   MediaTracker tracker;
   int pause /* msec */;
   int firstStep, lastStep;


   public void init()
    { tracker = new MediaTracker(this);
      img = getImage(getDocumentBase(), getParameter("SRC"));// asynchronous!
      tracker.addImage(img,0);


							     // get parameters
      try{ pause = Integer.parseInt(getParameter("PAUSE")); }
	 catch(NumberFormatException e){ pause = 200; /* default, msec */ }
      if(pause < 30) pause=30;  if(pause > 3000) pause=3000;

      try{ firstStep = Integer.parseInt(getParameter("FROM")); }
	 catch(NumberFormatException e){ firstStep = -8; /* default */ }
      if(firstStep > 0) firstStep=0;
      if(-firstStep*pause > 10000) firstStep = -10000/pause;

      try{ lastStep = Integer.parseInt(getParameter("TO")); }
	 catch(NumberFormatException e)
	 { if( firstStep == 0 ) lastStep=8; else lastStep=0; }
      if(lastStep < 0) lastStep=0;
      if(lastStep*pause > 10000) lastStep=10000/pause;

    }//init()


   private Thread animThread;

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


   public void run() // run the animThread
    { Graphics g = this.getGraphics();   // applet Graphics
      this.showStatus("Loading image");

      try{ tracker.waitForID(0); }catch(InterruptedException e)//wait for image
	    { System.out.println(e.getMessage()); }
      if(tracker.isErrorID(0))
         { this.showStatus("error loading image, quitting"); return; }
      //else got image

      w = img.getWidth(this);
      h = img.getHeight(this);  // NB. can only count on w,h when image got!!
      resize(w, h);

      int original[] = new int[h*w];             // holds original pixel values
      PixelGrabber pg = new PixelGrabber(img, 0,0, w,h, original, 0, w);
      try{ pg.grabPixels(); } catch(InterruptedException e)
	 { System.out.println(e.getMessage()); }

      int pix[] = new int[h*w]; // allocate working pixels
      MemoryImageSource pixSrc = new MemoryImageSource(w, h, pix, 0, w);


      int numRand = 277; // generate a "few" random numbers for reuse - speed
      int rand[] = new int[numRand];
      for(int i=0; i < numRand; i++)
	 rand[i]=(int)Math.round(Math.random()*2000)-1000; // >= -1000, <= 1000

      int maxStepSqr = 1;                 // ? exploding or imploding or both ?
      if(-firstStep > maxStepSqr) maxStepSqr = -firstStep;
      if( lastStep  > maxStepSqr) maxStepSqr =  lastStep;
      maxStepSqr *= maxStepSqr;
      int nRand=0;

      for(int step=firstStep; step <= lastStep; step++)
      // produce degraded versions of img
       { int range=(h+w)/2*step*step/maxStepSqr;//range to pick pixels from
	 for(int i=0; i < h; i++)
	    for(int j=0; j < w; j++)
             { if(nRand >= numRand-2) // random restart
		  nRand = (int)Math.round(Math.random()*(numRand-10));
	       int i2 = i+rand[nRand++]*range/1000;
	       if(i2 < 0) i2=0; else if(i2 >= h) i2=h-1;
               int j2 = j+rand[nRand++]*range/1000;
	       if(j2 < 0) j2=0; else if(j2 >= w) j2=w-1;

	       pix[i*w+j] = original[i2*w+j2];  // pix = original + noise
	     }

         pixImg = createImage( pixSrc );
	 g.drawImage(pixImg, 0,0, this); repaint(30);
	 try{ animThread.sleep(pause); }catch(Exception e){ } // delay

       }//for step

    }//run()


   public void stop()
    { if(animThread != null)
       { if(animThread.isAlive()) animThread.stop();
	 pixImg = null; //free resources
	 animThread=null;
    }  }


   public void update(Graphics g)
    { if(pixImg != null) g.drawImage(pixImg, 0, 0, this); }


   public void paint(Graphics g)
    { g.drawString("Image Loading.", 50, 25);
      if(pixImg != null)
	 g.drawImage(pixImg, 0 /*x*/,  0 /*y*/, this /*ImageObserver*/);
    }

 }//class

//Lloyd Allison.
