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

public class ArcheanApplet extends Applet implements Runnable {
    int width, height;
    int[] imageData;
    MemoryImageSource source;
    Image image;
    
    int kMaxX = 64;
    int kMaxY = 64;
    int kMaxColor = 6;
    int kMultFac = 16;
    int kShifter = 1 << 16; 
    int dist, scansize;
    
    int[][][] world;
    int[][][] back;
    
    int [][] matrix;
    
    Thread thread;
    
    Random generator;
    
    public int Rgb( int r, int g, int b )
    {
      return 0xff000000 | r << 16 | g << 8 | b;
    }
    
    public void init () {
        width = getSize ().width;
        height = getSize ().height;
        imageData = new int[kMaxX * kMaxY];
        source = new MemoryImageSource (kMaxX, kMaxY, imageData, 0, kMaxX);
        world = new int[kMaxX][kMaxY][kMaxColor];
        back = new int[kMaxX][kMaxY][kMaxColor];
        matrix = new int[kMaxColor][kMaxColor];
        generator = new Random();
        
        for( int c1=0; c1<kMaxColor; c1++)
            for( int c2=0; c2<kMaxColor; c2++)
            {
                matrix[c1][c2] = generator.nextInt(201)-100;
            }
            
        for( int x=0; x<kMaxX; x++)
            for( int y=0; y<kMaxY; y++)
                for( int c=0; c<kMaxColor; c++)
                {
                    world[x][y][c] = (generator.nextInt(21)-10)*kMultFac;
                }
        dist = generator.nextInt(4)+1;
        scansize = (dist+1)/2;
                
        source.setAnimated (true);
        source.setFullBufferUpdates (true);
        image = createImage (source);
    }
    
    public int charDefAsFloat( char ch )
    {
        String possibleValues = ")(*&^%$#@!zyxwvutsrqponmlkjihgfedcba_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        int i;
        i = possibleValues.indexOf(ch) - 26 -10 -1;
        return (100 * i)/36;
    }
    
    public synchronized void start () {
        thread = new Thread (this);
        thread.start ();
        String matrixdef = getParameter("signature");
        if(matrixdef!=null && matrixdef.length()==kMaxColor*kMaxColor+1)
        {
            int c1,c2,i;
            dist = matrixdef.charAt(0)-'0';
            if( dist<=0 || dist>6) dist=1;
            scansize = (dist+1)/2;
//            System.out.println( dist );
//            System.out.println( scansize );
            i=1;
            for( c1=0; c1<kMaxColor; c1++ )
                for( c2=0; c2   <kMaxColor; c2++ )
                {
                    matrix[c1][c2] = charDefAsFloat(matrixdef.charAt(i));
                    i++;
                }
        }
    }
    
    public synchronized void stop () {
        thread = null;
    }
    
    public void update (Graphics g) {
        paint (g);
    }
    
    public void paint (Graphics g) {
        g.drawImage (image, 0, 0, getSize ().width, getSize ().height, 
                            0, 0, kMaxX, kMaxY, this);
    }
    
    public void run () {
        Graphics g = getGraphics ();
    
        Toolkit.getDefaultToolkit ().sync ();
        
        int[] imageData = this.imageData;
        
        int width = kMaxX;
        int height = kMaxY;
        
        int red, green, blue;
        int[] cols;
        
        int[] avgcol = new int[kMaxColor];
            
        int x,y,c, c1,c2;
        int dx,dy,r, x2,y2;
        
        while( true )
            {
            for (x=0; x < kMaxX; x++)
                for (y=0; y < kMaxY; y++)
                    for (c =0; c<kMaxColor; c++)
                        back[x][y][c]=world[x][y][c];
                    
            for (x=0; x < kMaxX; x++)
                for (y=0; y < kMaxY; y++)
                {
                    for (c =0; c<kMaxColor; c++)
                        avgcol[c]=0;
                    for(dx=-scansize; dx<scansize+1; dx++)
                        for(dy=-scansize; dy<scansize+1; dy++)
                        {
                            r=Math.abs(dx)+Math.abs(dy);
                            if(r==0) continue;
                            if(r>dist) continue;
                            x2 = (dx+x+kMaxX) % kMaxX;
                            y2 = (dy+y+kMaxY) % kMaxY;
                            for(c=0; c<kMaxColor;c++)
                                avgcol[c]+=back[x2][y2][c];
                        }
                        
                    cols=world[x][y];
                    for(c1=0; c1<kMaxColor;c1++)
                    {
                        for(c2=0; c2<kMaxColor;c2++)
                            cols[c1] += avgcol[c2] * matrix[c1][c2] / kShifter;
                        if(cols[c1]<-127*kMultFac) cols[c1]=-127*kMultFac;
                        if(cols[c1]>128*kMultFac) cols[c1]=128*kMultFac;
                    }
                }
            
            for (x=0; x < kMaxX; x++)
            {
                for (y=0; y < kMaxY; y++)
                {
                    cols = world[x][y]; 
                    red   = 128 + (cols[0]*140 + cols[3]*110 + cols[4]*110)/(kMultFac*256);
                    if(red<0) red=0;
                    if(red>255) red=255;
                        
                    green = 128 + (cols[1]*140 + cols[3]*110 + cols[5]*110)/(kMultFac*256);
                    if(green<0) green=0;
                    if(green>255) green=255;
                        
                    blue  = 128 + (cols[2]*140 + cols[4]*110 + cols[5]*110)/(kMultFac*256);
                    if(blue<0) blue=0;
                    if(blue>255) blue=255;
                    imageData[x+ width * y]=0xff000000 | red << 16 | green << 8 | blue;
                }
            }
            Thread.yield ();
            source.newPixels();
            Toolkit.getDefaultToolkit ().sync ();
        }
    }
}

