import java.lang.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.applet.Applet;
import java.util.*;

public class plaslet extends Applet
    implements MouseListener, KeyListener, Runnable {


 static int pinkfilt[] = new int[32];
 {
//  // Initialize inverted parabolic values for pink filter
//  for(int i=32;--i>=0;)
//   pinkfilt[i]=16*16-(16-i)*(16-i);

  for(int i=11;--i>=0;) {
   pinkfilt[i]=i*i;
   pinkfilt[30-i]=i*i;
   pinkfilt[i+10]= 10*10+5*5-(i-5)*(i-5);
  }

  //Normalize to fixed point values shifted by 16
  int total=0;
  for(int i=32;--i>=0;) total+=pinkfilt[i];
  for(int i=32;--i>=0;) pinkfilt[i]=(pinkfilt[i]<<16)/total;
 }
 static int pfa[] = new int[256];
 static int pfb[] = new int[256];
 static int pfc[] = new int[256];
 static int pfd[] = new int[256];
 {
  // Initialize lookup tables for fast pink filter calculation
  for(int i=256;--i>=0;) {
   pfa[i]=0;
   pfb[i]=0;
   pfc[i]=0;
   pfd[i]=0;
   for(int bit=8;--bit>=0;)
    if((i&(1<<bit))==0) {
     pfa[i]-=pinkfilt[bit];
     pfb[i]-=pinkfilt[bit+8];
     pfc[i]-=pinkfilt[bit+16];
     pfd[i]-=pinkfilt[bit+24];
    } else {
     pfa[i]+=pinkfilt[bit];
     pfb[i]+=pinkfilt[bit+8];
     pfc[i]+=pinkfilt[bit+16];
     pfd[i]+=pinkfilt[bit+24];
    } // end of bit crawling loop
  } // end of main for loop
 }

 public static final int AM=255<<24; // Alpha channal mask

 public static final int YS=8;  // Amount to shift Y by
 public static final int XMAX=1<<YS;
 public static final int YMAX=XMAX;

 public static final int SF=4; // Scaling factor power of 2
 public static final int XMAXSF=(XMAX>>SF)+2+2;
 public static final int YMAXSF=(YMAX>>SF)+2+2;

 final static int PELSIZE=YMAX<<YS;
 int pel[];
 MemoryImageSource pelMemoryImageSource;
 Image pelImage;

 public final synchronized void update (Graphics g) { paint(g); }

 public void paint(Graphics g) {
  g.drawImage(pelImage,0,0,null);
 }

 Random rng;

 int white[];
 int pink[];

 static int colmap[]=new int[256];
 {
  for(int i=256;--i>=0;) {

   double bangle=(i-128F)*(0.65F*3.1415926F/128F);
   double angle=(i-128F)*(5.5F*3.1415926F/128F);
   double x=Math.cos(angle)*Math.cos(bangle)*.69F;
   double y=Math.sin(angle)*Math.cos(bangle)*.99F;
   double z=Math.sin(bangle);
   double r=(z-x)/Math.sqrt(3)+y/Math.sqrt(2);
   double g=(z+x)/Math.sqrt(3);
   double b=(z-x)/Math.sqrt(3)-y/Math.sqrt(2);
   int ir=((int)Math.round(r*140)+128)<<0;
       ir=(ir<0?0:(ir>255?255:ir));
   int ig=((int)Math.round(g*140)+128)>>0;
       ig=(ig<0?0:(ig>255?255:ig));
   int ib=((int)Math.round(b*140)+128)<<0;
       ib=(ib<0?0:(ib>255?255:ib));
   colmap[i]=AM|ir<<16|ig<<8|ib;

//   if(i>=123)
//     colmap[i]=AM|i<<16|i<<8;
//    else
//     colmap[i]=AM|i;

  }
 }

 Thread mainThread;
 public boolean alive=true;
 public boolean snooze=false;
 public void run() {
  while (alive) {
   if(snooze) {
    try {Thread.sleep(10000);} catch(InterruptedException e) { }
   } else {
    shiftwhite();
    dopink();
//    for(int y=YMAX;--y>=0;)
//     for(int x=XMAX;--x>=0;) {
//      int amp=128+(pink[x+(y<<YS)]>>8);
//  //    amp=(amp<0?0:(amp>255?255:amp));
//      amp=((amp&-256)==0? amp : (amp<0?0:255));
//      pel[x+(y<<YS)]=colmap[amp];
//     }
    for(int i=YMAX<<YS;--i>=0;) {
     int amp=128+(pink[i]>>8);
     amp=((amp&-256)==0? amp : (amp<0?0:255));
     pel[i]=colmap[amp];
    }

    pelMemoryImageSource.newPixels(0,0,XMAX,YMAX);
    repaint();
    try {Thread.sleep(10);} catch(InterruptedException e) { }
   }
  }
 }

 public void init() {
  pel = new int[PELSIZE];
  for(int i=PELSIZE;--i>=0;) pel[i]=0;
  pelMemoryImageSource = new MemoryImageSource(XMAX,YMAX,pel,0,XMAX);
  pelMemoryImageSource.setAnimated(true);
  pelImage = createImage(pelMemoryImageSource);

  rng = new Random();

  white = new int[PELSIZE];
  for(int i=PELSIZE;--i>=0;) white[i]=rando();

  pink = new int[PELSIZE];

  mainThread=new Thread(this);
  mainThread.start();
  this.addMouseListener(this);
  this.addKeyListener(this);
 }

 public void mouseClicked(MouseEvent e) {
  snooze = !snooze;
  if(mainThread != null)mainThread.interrupt();
 }

 public void mousePressed(MouseEvent e) { }
 public void mouseReleased(MouseEvent e) { }
 public void mouseEntered(MouseEvent e) { }
 public void mouseExited(MouseEvent e) { }

 public void keyPressed(KeyEvent e) { }
 public void keyReleased(KeyEvent e) { }
 public void keyTyped(KeyEvent e) {
  int temp;
  char thekey=e.getKeyChar();
  switch (thekey) {
   case 's':
   case 'S':
    //start
    snooze = false;
    if(mainThread != null)mainThread.interrupt();
    break;
   case 'p':
   case 'P':
    //pause
    snooze = true;
    break;
  }
  repaint();
 } // end of keyTyped method

// public void start() { }

 public void stop() {
  snooze = true;
 } // end of stop

 public void destroy() {
  alive=false;
 } // end of destroy

 void shiftwhite() {
  for(int y=YMAXSF;--y>=0;)
   for(int x=XMAXSF;--x>=0;) {
    int i=x+(y<<YS);
    white[i]=(white[i]<<1)|(1&(rando()>>>15));
   }
 }

 void dopink() {
  // Filter in Z
  for(int y=YMAXSF;--y>=0;)
   for(int x=XMAXSF;--x>=0;) {
    int i=x+(y<<YS);
    int w=white[i];
    pink[i]=pfa[w&255]+pfb[(w>>8)&255]+pfc[(w>>16)&255]+pfd[(w>>24)&255];
   }

  // Filter in X
  for(int y=YMAXSF;--y>=0;) {
   int xy=y<<YS;
   int stop=xy+XMAXSF-2;
   for(;xy<stop;xy++) {
    pink[xy]=(pink[xy]+(pink[xy+1]<<1)+pink[xy+2]);
   }
  }
  // Filter in Y
  for(int x=XMAXSF-2;--x>=0;) {
   int xy=x;
   int stop=xy+((YMAXSF-2)<<YS);
   for(;xy<stop;xy+=XMAX) {
    pink[xy]=(pink[xy]+(pink[xy+XMAX]<<1)+pink[xy+(XMAX<<1)])>>3;
   }
  }

/* 
***********************************************************************
  // Filter in X
  for(int y=YMAXSF;--y>=0;) {
   int offA=(y<<YS);
   int offB=offA+10;
   int offC=offA+20;
   int offD=offA+30;
   int pos=0;
   int vel=0;
   int acc=0;
   for(int x=-30;x<-20;x++) {
    acc+=pink[offD+x];
    vel+=acc; pos+=vel;
   }
   for(int x=-20;x<-10;x++) {
    acc+=pink[offD+x]-3*pink[offC+x];
    vel+=acc; pos+=vel;
   }
   for(int x=-10;x<0;x++) {
    acc+=pink[offD+x]-3*(pink[offC+x]-pink[offB+x]);
    vel+=acc; pos+=vel;
   }
   for(int x=0;x<XMAXSF-30;x++) {
    acc+=pink[offD+x]-3*(pink[offC+x]-pink[offB+x])-pink[offA+x];
    vel+=acc; pos+=vel;
    pink[offA+x]=pos>>8;
   }
  } // end of filter in X

  // Filter in Y
  for(int x=XMAXSF-30;--x>=0;) {
   int offA=x;
   int offB=offA+(10<<YS);
   int offC=offA+(20<<YS);
   int offD=offA+(30<<YS);
   int pos=0;
   int vel=0;
   int acc=0;
   for(int y=-30;y<-20;y++) {
    int yys=y<<YS;
    acc+=pink[offD+yys];
    vel+=acc; pos+=vel;
   }
   for(int y=-20;y<-10;y++) {
    int yys=y<<YS;
    acc+=pink[offD+yys]-3*pink[offC+yys];
    vel+=acc; pos+=vel;
   }
   for(int y=-10;y<0;y++) {
    int yys=y<<YS;
    acc+=pink[offD+yys]-3*(pink[offC+yys]-pink[offB+yys]);
    vel+=acc; pos+=vel;
   }
   for(int y=0;y<YMAXSF-30;y++) {
    int yys=y<<YS;
    acc+=pink[offD+yys]-3*(pink[offC+yys]-pink[offB+yys])-pink[offA+yys];
    vel+=acc; pos+=vel;
    pink[offA+yys]=pos>>8;
   }
  } // end of filter in Y
***********************************************************************
*/

  // Now do interpolation steps
  for(int scale=SF;--scale>=0;) {
   int size=XMAX;
   if(scale>0) size=(XMAX>>scale)+2;

   // First expand in Y direction
   for(int x=(size>>1);--x>=0;) {
    int oldv=0; int oldvm=0;
    int newv=0; int newvm=0;
    int dest=x+(size<<YS);
    for(int source=x+((size>>1)<<YS);(source-=XMAX)>=x;) {
     oldv=newv; oldvm=newvm;
     newv=pink[source];
     newvm=newv+newv+newv;
     dest-=XMAX; pink[dest]=(oldvm+newv)>>4;
     dest-=XMAX; pink[dest]=(oldv+newvm)>>4;
    }
   } // end of expand in Y

   // Second expand in X direction
   for(int y=size;--y>=0;) {
    int oldv=0; int oldvm=0;
    int newv=0; int newvm=0;
    int yys=y<<YS;
    int dest=size+yys;
    for(int source=(size>>1)+yys;--source>=yys;) {
     oldv=newv; oldvm=newvm;
     newv=pink[source];
     newvm=newv+newv+newv;
     pink[--dest]=(oldvm+newv);
     pink[--dest]=(oldv+newvm);
    }
   } // end of expand in X

  } // end of interpolation

 } // end of dopink


 int rando() {
  int num=rng.nextInt();
  for(int i=((num>>13)&255)/23;--i>=0;)
   num=(num<<i)^(num>>>(32-i))^rng.nextInt();
  return num;
 }

} //end of class plaslet
