import java.awt.*;
import java.applet.*;
import java.awt.image.*;
import java.util.Hashtable;

public class Fuego extends Applet
                   implements Runnable,
                              ImageConsumer
{
   int vLx = 122;
   int vLy = 202;
   byte[] pix;
   Thread hilo = null;
   ColorModel modColor;
   ImageProducer imgOrig;
   MemoryImageSource imgFinal = null;
   Image imagen = null;
   volatile boolean animacion = true;
   volatile boolean[] vEst = {true,true,true,true,false,true};
   volatile int nEst = 41;
   volatile int nAct = 5;
   boolean error = false;

   public void init( )
   {
      String fichImagen = getParameter("imagen");
      String cad = getParameter("ancho");
      try {
        vLx = Integer.parseInt(cad)+2;
      } catch( Exception e ) { }
      cad = getParameter("alto");
      try {
        vLy = Integer.parseInt(cad)+2;
      } catch( Exception e ) { }
      pix = new byte[vLx*vLy];
      imgOrig = getImage(getCodeBase(),fichImagen).getSource();
      imgOrig.startProduction(this);
   }

   public void start( )
   {
      if( (hilo == null) || !hilo.isAlive() ) {
        hilo = new Thread(this);
        animacion = true;
        hilo.start();
      }
   }

   public void stop( )
   {
      if( hilo == null ) return;
      animacion = false;
      while( hilo.isAlive() ) Thread.yield();
      hilo = null;
   }

   public void run( )
   {
      while(animacion) {
        if(imagen==null) {
          Thread.yield();
        } else {
          procesaPixels();
          imgFinal.newPixels();
        }
      }
   }

   public void paint( Graphics g )
   {
      if( imagen != null ) {
        g.drawImage(imagen,0,0,this);
      } else {
        String cad1 = ((error) ? "Error al cargar" : "Cargando");
        String cad2 = ((error) ? "la imagen" : "la imagen...");

        g.setColor(Color.yellow);
        g.fillRect(0,0,vLx,vLy);
        int lx = g.getFontMetrics().stringWidth(cad1);
        int ly = g.getFont().getSize();
        g.setColor(Color.black);
        g.drawString(cad1,(vLx-lx)/2,vLy/2-ly);
        lx = g.getFontMetrics().stringWidth(cad2);
        g.drawString(cad2,(vLx-lx)/2,vLy/2+ly);
      }
   }

   public void update( Graphics g ) { paint(g); }

   public Dimension getPreferredSize( )
   {
      return( new Dimension(vLx,vLy) );
   }

   public boolean mouseDown( Event evt, int x, int y )
   {
      // Algoritmo basado en el codigo Gray.
      nEst++;
      if(nEst>63) nEst = 1;
      showStatus("Pasamos al estado "+nEst);
      int flag = 32;
      int vAnt = 0;
      int vAct;
      for(int i=5; i>=0; i--, flag /= 2) {
        vAct = (((nEst & flag) > 0) ? 1 : 0);
        vEst[i] = (vAct ^ vAnt) == 1;
        vAnt = vAct;
      }
      nAct = 0;
      for(int i=0; i<6; i++) if(vEst[i]) nAct++;
      return(true);
   }

   /* *** Interfaz ImagenConsumer *** */

   public void setHints( int hintflags ) { }
   public void setProperties( Hashtable props ) { }

   public void setDimensions( int width, int height )
   {
     if( (width+2 != vLx) || (height+2 != vLy) )
     {
        vLx = width+2;
        vLy = height+2;
        pix = new byte[vLx*vLy];
        resize(vLx,vLy);
     }
   }

   public void setColorModel( ColorModel model )
   {
     modColor = model;
   }

   public void setPixels( int x, int y, int w, int h, ColorModel model,
                          byte[] pixels, int off, int scansize )
   {
      if( modColor == null ) modColor = model;
      for( int i = 0; i < h; i++ ) {
        int pf = i*scansize + x + off;
        int pd = (y+1+i)*vLx + x + 1;
        for( int j = 0; j < w; j++ ) { pix[pd+j] = pixels[pf+j]; }
      }
   }

   public void setPixels( int x, int y, int w, int h, ColorModel model,
                          int[] pixels, int off, int scansize )
   {
      error = true;
   }

   public void imageComplete( int status )
   {
/*
      if( ((status & ImageConsumer.IMAGEERROR)>0) ||
          ((status & ImageConsumer.IMAGEABORTED)>0) || error ) {
         error = true;
         System.out.println("Se ha completado: "+status);
         return;
      }
*/
      // Bordes de la imagen a cero
      int n = vLx*vLy;
      for(int i=0; i<vLx; i++) { pix[i] = 11; }
      for(int i=n-vLx; i<n; i++) { pix[i] = 11; }
      for(int i=0; i<n; i += vLx) { pix[i] = 11; }
      for(int i=vLx-1; i<n; i += vLx) { pix[i] = 11; }

      error = false;
      imgFinal = new MemoryImageSource(vLx,vLy,modColor,pix,0,vLx);
      imgFinal.setAnimated(true);
      imagen = createImage(imgFinal);
      imgOrig.removeConsumer(this);
      repaint();
   }

   /* *** Aqui esta la chicha - modificar la imagen *** */

   protected void vecinos( byte[] p, int n )
   {
      if(pix[n]==10) {
        if(Math.random()>0.9) pix[n] = -11;
        return;
      }
      if(pix[n]==-11) {
        if(Math.random()>0.9) pix[n] = 10;
        return;
      }

      int sum = 0;
      if(vEst[0]) sum += ((p[n+vLx-1]<0) ? 256+p[n+vLx-1] : p[n+vLx-1]);
      if(vEst[1]) sum += ((p[n+vLx]  <0) ? 256+p[n+vLx]   : p[n+vLx]);
      if(vEst[2]) sum += ((p[n+vLx+1]<0) ? 256+p[n+vLx+1] : p[n+vLx+1]);
      if(vEst[3]) sum += ((p[n-1]    <0) ? 256+p[n-1]     : p[n-1]);
      if(vEst[4]) sum += ((p[n]      <0) ? 256+p[n]       : p[n]);
      if(vEst[5]) sum += ((p[n+1]    <0) ? 256+p[n+1]     : p[n+1]);
      sum /= nAct;
      pix[n] = (byte) ((sum>127) ? sum-256 : sum);
      if(pix[n]==10) { pix[n] = 11; } else if(pix[n]==-11) { pix[n] = -12; }
   }

   protected void procesaPixels( )
   {
      int off = vLx;
      for( int y = 2; y < vLy; y++ ) {
        for( int x = 2; x < vLx; x++, off++ ) vecinos(pix,off);
        off += 2;
      }

      // Copiar los bordes
      int n = vLx*vLy;
      System.arraycopy(pix,vLx+1,pix,n-vLx+1,vLx-2);
      System.arraycopy(pix,1,pix,n-2*vLx+1,vLx-2);
      for( off = vLx; off < n; off += vLx ) {
        pix[off+vLx-2] = pix[off];
        pix[off+1] = pix[off+vLx-1];
      }
   }
}

