/***********************************************************
  Applet Select : displays the dynamical systems found
  by program ufattr.
  Copyright 1998 : Zito Giuseppe
***********************************************************/

import java.awt.*;
import java.awt.image.*;
import java.io.DataInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.util.StringTokenizer;
import java.applet.*;

public class Select extends Applet implements Runnable {

  URL theURL;
  Thread runner;
  TextArea ta = new TextArea("Getting text...",30,20);
  Formula form = new Formula();
  int maxcol = 160;
  int ncolr = 30;
  byte redm[] = new byte[maxcol];
  byte greenm[] = new byte[maxcol];
  byte bluem[] = new byte[maxcol];
  byte b255 = (byte)255;
  IndexColorModel icm;
  boolean debug = false;
  boolean test = false;
  boolean same = false;
  boolean random = false;
  Dr1basin basin;
  Dr1attr attr;
  Dr1global global;
  Panel imagePanel;
  Panel controlPanel;
  Panel buttonPanel;
  Panel textPanel;
  Panel modcPanel;
  TextField f1;
  TextField f2;
  int nfor = 0;
  TextField dvar;
  String var = "c0";
  TextField dvari;
  int vari = 0;
  TextField dvarj;
  int varj = 0;
  TextField dnewval;
  double newval;
  TextField doldval;
  double oldval;

  public void init() {
    int i; 
       
    UserParameters();
    if (debug) System.out.println ("Starting init...");
    redm[0] = 0; greenm[0] = 0; bluem[0] = 0;
    redm[1] = b255; greenm[1] = b255; bluem[1] = b255;
    redm[2] = b255; greenm[2] = 0; bluem[2] = 0;
    redm[3] = 0; greenm[3] = b255; bluem[3] = 0;
    redm[4] = 0; greenm[4] = 0; bluem[4] = b255;
    redm[5] = b255; greenm[5] = b255; bluem[5] = 0;
    redm[6] = b255; greenm[6] = 0; bluem[6] = b255;
    redm[7] = 0; greenm[7] = b255; bluem[7] = b255;
    redm[8] = 0; greenm[8] = (byte)254; bluem[8] = (byte)254;
    redm[9] = 0; greenm[9] = (byte)253; bluem[9] = (byte)253;
    for (i=0;i<ncolr;i++) {
      redm[i+10] = interp(255,255,i/(double)(ncolr-1.));
      greenm[i+10] = interp(0,255,i/(double)(ncolr-1.));
      bluem[i+10] = interp(0,0,i/(double)(ncolr-1.));
    }
    for (i=0;i<ncolr;i++) {
      redm[i+ncolr+10] = interp(255,0,i/(double)(ncolr-1.));
      greenm[i+ncolr+10] = interp(255,255,i/(double)(ncolr-1.));
      bluem[i+ncolr+10] = interp(0,0,i/(double)(ncolr-1.));
    }
    for (i=0;i<ncolr;i++) {
      redm[i+2*ncolr+10] = interp(0,0,i/(double)(ncolr-1.));
      greenm[i+2*ncolr+10] = interp(255,255,i/(double)(ncolr-1.));
      bluem[i+2*ncolr+10] = interp(0,255,i/(double)(ncolr-1.));
    }
    for (i=0;i<ncolr;i++) {
      redm[i+3*ncolr+10] = interp(0,0,i/(double)(ncolr-1.));
      greenm[i+3*ncolr+10] = interp(255,0,i/(double)(ncolr-1.));
      bluem[i+3*ncolr+10] = interp(255,255,i/(double)(ncolr-1.));
    }
    for (i=0;i<ncolr;i++) {
      redm[i+4*ncolr+10] = interp(0,255,i/(double)(ncolr-1.));
      greenm[i+4*ncolr+10] = interp(0,0,i/(double)(ncolr-1.));
      bluem[i+4*ncolr+10] = interp(255,255,i/(double)(ncolr-1.));
    }
    icm = new IndexColorModel(8,maxcol,redm,greenm,bluem);
    String url = "ufattrou";
    try { this.theURL = new URL(getDocumentBase(),url); 
    }catch ( MalformedURLException e) {
      System.out.println("Bad URL: " + theURL);
    }
    setLayout(new BorderLayout());
    imagePanel = new Panel();
    imagePanel.setLayout(null);
    add("Center", imagePanel);
    basin = new Dr1basin();
    global = new Dr1global();
    //imagePanel.add(basin);
    imagePanel.add(global);
    global.reshape(10,10,520,520);
    imagePanel.add(basin);
    basin.reshape(10,530,220,220);
    attr = new Dr1attr("strange attractor");
    attr.resize(500,500);
    attr.move(50,50);
    attr.show();
    add("East",ta);
    form.setvar(debug);
    controlPanel = new Panel();
    controlPanel.setLayout(new GridLayout(3,1));
    add("South", controlPanel);
    buttonPanel = new Panel();
    controlPanel.add  (buttonPanel);
    buttonPanel.add(new Button("Same"));
    buttonPanel.add(new Button("Next"));
    buttonPanel.add(new Button(">>"));
    buttonPanel.add(new Button("Decode"));
    textPanel = new Panel();
    f1 = new TextField("Starting",10);
    f2 = new TextField("nfor: "+nfor);
    controlPanel.add(textPanel);
    textPanel.add(f1);  
    textPanel.add(f2);
    modcPanel = new Panel();
    controlPanel.add(modcPanel);
    dvar = new TextField(var);
    modcPanel.add(dvar);
    dvari = new TextField(String.valueOf(vari),1);
    modcPanel.add(dvari);
    dvarj = new TextField(String.valueOf(varj),2);
    modcPanel.add(dvarj);
    dnewval = new TextField(String.valueOf(newval),10);
    modcPanel.add(dnewval);
    doldval = new TextField(String.valueOf(oldval),10);
    modcPanel.add(doldval);
    modcPanel.add(new Button("Random"));
    if (debug) System.out.println ("Exiting init...");
  }

  public byte interp(int a,int b,double f) {
    return (byte)(a*(1-f)+b*f);
  }
  
  private void UserParameters () {
    String parameter;

    // Get user parameters
    parameter = getParameter ("debug");
    if (parameter != null) debug = parameter.equals("true");
    parameter = getParameter ("test");
    if (parameter != null) test = parameter.equals("true");
  }

  public Insets insets() {
    return new Insets(10,10,10,10);
  }

  public void start() {
    if (runner == null) {
      runner = new Thread(this);
      runner.start();
      basin.setvar(debug,maxcol,form, icm,runner,f1);
      attr.setvar(debug,form,f1);
      global.setvar(debug,maxcol,form, icm,runner,f1);
    }
  }
  
  public void stop() {
    if (runner != null) {
      runner.stop();
      runner = null;
    }
  }

  public void update(Graphics g) {
    paint (g);
  }

  public void run() {
    if(!test && !random){
      form.read(theURL);
      nfor = nfor + 1;
      oldval = form.c[vari][varj];
      doldval.setText(String.valueOf(oldval));
      f2.setText("nfor: "+nfor);
      }
    form.print(ta);
    if(!random)form.init();
    attr.drawimage(same,form.xin,form.yin);
    global.drawimage();
    global.repaint();
    basin.drawimage();
  }

  public boolean action(Event e, Object arg) {
    String button_name;
    int nskip,nfor1;

    if(e.target instanceof Button){
      button_name =(String)arg;
      if(button_name.equals("Next")){
        same=false;
        random = false;
        stop();
        start();
      }
      if(button_name.equals(">>")){
        same = false;
        random = false;
        stop();
        for(int i=0;i < 9;i++)form.read(theURL);
        nfor = nfor + 9;
        start();
      }
      if(button_name.equals("Same")){
        same = true;
        attr.drawimage(same,Math.random()*8.-4.,Math.random()*8.-4.);
      } 
      if(button_name.equals("Decode")){
        if(form.nsel[0]>0){
         form.decode(nfor);
         form.print(ta);
        }else f1.setText("No formula yet loaded");
      }
      if(button_name.equals("Random")){
        random = true;
        stop();
        newval = Math.random()*8.-4.;
        dnewval.setText(String.valueOf(newval));
        form.c[vari][varj] = newval;
        start();
      }
    }
    if(e.target instanceof TextField){
      if(e.target == dvar) {
        form.c[vari][varj]=oldval;
        var = dvar.getText();
        vari = 0;
        if (var.indexOf("d")==0)vari=1;
        varj=Integer.parseInt(var.substring(1));
        if(varj<0)varj=0; if(varj>49)varj=49;
        dvari.setText(String.valueOf(vari));
        dvarj.setText(String.valueOf(varj));
        oldval = form.c[vari][varj];
        doldval.setText(String.valueOf(oldval));
      }
      if(e.target == f2) {
        nfor1 = Integer.parseInt(f2.getText());
        if(nfor1 > nfor) {
           nskip = nfor1-nfor-1;
           same = false;
           random = false;
           stop();
           if(nskip > 0)for(int i=0;i < nskip;i++)form.read(theURL);
           nfor = nfor + nskip;
           start();
        }
      }
    }

    return true;
  }
  public boolean handleEvent(Event evt) {
    if (evt.id == Event.WINDOW_DESTROY) {
      System.exit(0);
      return true;
    }
    return super.handleEvent(evt);
  }

}

/*******************************************************
            Formula
*******************************************************/
class Formula {
  int nsel[]=new int[2];
  int isel[][]=new int [2][50];
  double c[][]=new double [2][50];
  double stack[]=new double[50];
  int iexe[][]=new int[2][50];
  double p[]=new double[2];
  int istack,k,numpull;
  boolean debug;
  double xin,yin;
  StringBuffer buf ;
  Fpoint fp1 = new Fpoint(0.,0.);
  int nread = 0;
  DataInputStream data;

  public Formula(){
    nsel[0] = 6; nsel[1] = 2;
    isel[0][0]=14;
    isel[0][1]=3;
    isel[0][2]=16;
    isel[0][3]=7;
    isel[0][4]=9;
    isel[0][5]=19;
    isel[1][0]=13;
    isel[1][1]=9;

    for(int j=0;j<2;j++){
      for (int i=0;i<nsel[j];i++)
        {c[j][i]=0.;
      }
    }
    c[0][1]=1.;c[0][4]=-1.4;c[1][1]=.3;
    xin=0;yin=0;
  }

  public void  setvar(boolean debug1){
    debug = debug1;
  }

  public void print(TextArea ta){
    ta.setText(buf.toString()); 
  }

  public void read(URL theURL) {
    URLConnection conn;
    String line;
    int j;
    try {
      if (nread == 0){
        conn = theURL.openConnection();
        conn.connect();
        data = new DataInputStream(new BufferedInputStream(
                     conn.getInputStream()));
      }
      nread = nread + 1;
      next();
    }
    catch (IOException e) {
      System.out.println("IO Error:" + e.getMessage());
    }
  }

    public void decode(int nfor){
    
    buf = new StringBuffer();
    double p[] = new double[2],p0[] = new double[2];
    double x0 = 0., y0 = 0.;
    int istack;
    String vname[] = new String[2];
    vname[0] = "c"; vname[1] = "d";

    p0[0] = 0.;
    p0[1] = 0.;
    buf.append("Formula"+nfor+" {; Giuseppe Zito\n z = pixel ,\n");
    for(int i=0; i< 2; i++) {
      istack = 0;
      p[i] = p0[i];
      for (int k=0; k < nsel[i]; k++) {
        switch (isel[i][k]) {
          case  1: p[i] = p[i] + x0;break;
          case  2: p[i] = p[i] + y0;break;
          case  3: p[i] = p[i] + c[i][k];buf.append(vname[i]+k+" = "+c[i][k] +"\n" );break;
          case  4: p[i] = p[i] - x0;break;
          case  5: p[i] = p[i] - y0;break;
          case  6: p[i] = p[i] - c[i][k];buf.append(vname[i]+k+" = "+c[i][k]+"\n" );break;
          case  7: p[i] = p[i] * x0;break;
          case  8: p[i] = p[i] * y0;break;
          case  9: p[i] = p[i] * c[i][k];buf.append(vname[i]+k+" = "+c[i][k]+"\n" );break;
          case 10: if(x0 == 0.) p[i] = 0.;
                else  p[i] = p[i] / x0;break;
          case 11: if(y0 == 0.) p[i] = 0.;
                else  p[i] = p[i] / y0;break;
          case 12: if(c[i][k] == 0.) p[i] = 0.;
                 else  p[i] = p[i] / c[i][k];buf.append(vname[i]+k+" = "+c[i][k] +"\n" );break;
          case 13: if(k == 0){p[i] = x0;}break;
          case 14: if(k == 0){p[i] = y0;}break;
          case 15: if(k == 0){p[i] = c[i][k];buf.append(vname[i]+k+" = "+c[i][k]+"\n" );}break;
          case 16: if(iexe[i][k] == 1){
              istack = istack + 1; stack[istack] = p[i];
              p[i] = x0; }break;
          case 17: if(iexe[i][k] == 1){
              istack = istack + 1; stack[istack] = p[i];
              p[i] = y0; }break;
          case 18: if(iexe[i][k] == 1){
              istack = istack + 1; stack[istack] = p[i];
                 p[i] = c[i][k];buf.append(vname[i]+k+" = "+c[i][k]+"\n" ); }break;
          case 19: if(istack > 0) {p[i] = p[i] + stack[istack];
                     istack = istack - 1;}break;
          case 20: if(istack > 0) {p[i] = p[i] - stack[istack];
                     istack = istack - 1;}break;
          case 21: if(istack > 0) {p[i] = p[i] * stack[istack];
                     istack = istack - 1;}break;
          case 22: if(istack > 0) {
                       if(stack[istack] == 0.)  p[i] = 0.;
                       else {
                        p[i] = p[i] / stack[istack];
                             istack = istack - 1;}}break;
        }
      }
    }
    buf.append("  : \n x = real(z), y = imag(z)\n");
    for(int i=0; i< 2; i++) {
      istack = 0;
      p[i] = 0.;
      for (int k=0; k < nsel[i]; k++) {
        switch (isel[i][k]) {
          case  1: p[i] = p[i] + x0;buf.append("s"+istack+" = "+"s"+istack + " "+"+x"+"\n" );break;
          case  2: p[i] = p[i] + y0;buf.append("s"+istack+" = "+"s"+istack +" "+"+y"+"\n" );break;
          case  3: p[i] = p[i] + c[i][k];buf.append("s"+istack+" = "+"s"+istack +" "+"+"+vname[i]+k+"\n" );break;
          case  4: p[i] = p[i] - x0;buf.append("s"+istack+" = "+"s"+istack +" "+"-x"+"\n" );break;
          case  5: p[i] = p[i] - y0;buf.append("s"+istack+" = "+"s"+istack +" "+"-y"+"\n" );break;
          case  6: p[i] = p[i] - c[i][k];buf.append("s"+istack+" = "+"s"+istack + " "+"-"+vname[i]+k+"\n" );break;
          case  7: p[i] = p[i] * x0;buf.append("s"+istack+" = "+"s"+istack +" "+"*x"+"\n" );break;
          case  8: p[i] = p[i] * y0;buf.append("s"+istack+" = "+"s"+istack +" "+"*y"+"\n" );break;
          case  9: p[i] = p[i] * c[i][k];buf.append("s"+istack+" = "+"s"+istack +" "+"*"+vname[i]+k+"\n" );break;
          case 10: if(x0 == 0.) p[i] = 0.;
              else  p[i] = p[i] / x0;buf.append("s"+istack+" = "+"s"+istack +" "+"/x"+"\n" );break;
          case 11: if(y0 == 0.) p[i] = 0.;
                else  p[i] = p[i] / y0;buf.append("s"+istack+" = "+"s"+istack +" "+"/y"+"\n" );break;
          case 12: if(c[i][k] == 0.) p[i] = 0.;
                 else  p[i] = p[i] / c[i][k];buf.append("s"+istack+" = "+"s"+istack +" "+"/"+vname[i]+k+"\n" );break;
          case 13: if(k == 0){p[i] = x0;buf.append("s"+istack+" "+"= x"+"\n" );}break;
          case 14: if(k == 0){p[i] = y0;buf.append("s"+istack+" "+"= y"+"\n" );}break;
          case 15: if(k == 0){p[i] = c[i][k];buf.append("s"+istack+" "+"="+vname[i]+k+"\n" );}break;
          case 16: if(iexe[i][k] == 1){
              istack = istack + 1; stack[istack] = p[i];
              p[i] = x0; buf.append("s"+istack+" "+"= x"+"\n" );}break;
          case 17: if(iexe[i][k] == 1){
              istack = istack + 1; stack[istack] = p[i];
              p[i] = y0; buf.append("s"+istack+" "+"= y"+"\n" );}break;
          case 18: if(iexe[i][k] == 1){
              istack = istack + 1; stack[istack] = p[i];
                 p[i] = c[i][k];buf.append("s"+istack+" "+"="+vname[i]+k+"\n" ); }break;
          case 19: if(istack > 0) {p[i] = p[i] + stack[istack];
                     istack = istack - 1;buf.append("s"+istack+" = "+"s"+istack +" "+"+s"+(istack+1)+"\n" );}break;
          case 20: if(istack > 0) {p[i] = p[i] - stack[istack];
                     istack = istack - 1;buf.append("s"+istack+" = "+"s"+istack +" "+"-s"+(istack+1)+"\n" );}break;
          case 21: if(istack > 0) {p[i] = p[i] * stack[istack];
                     istack = istack - 1;buf.append("s"+istack+" = "+"s"+istack +" "+"*s"+(istack+1)+"\n" );}break;
          case 22: if(istack > 0) {
                       if(stack[istack] == 0.)  p[i] = 0.;
                       else {
                        p[i] = p[i] / stack[istack];
                             istack = istack - 1;}buf.append("s"+istack+" = "+"s"+istack +" "+"/s"+(istack+1)+"\n" );}break;
        }
      }
      if(i==0)buf.append("newx = s0 \n");
      if(i==1)buf.append("newy = s0 \n");
    }
    buf.append("z = newx + flip(newy)\n newx < 4 && newx > -4 && newy < 4 && newy > -4 \n}\n");
  }

  void next(){
    int numlin =0;
    String line;
    int j;

    buf = new StringBuffer();
    try { 
      while ((line = data.readLine()) != null) {
        buf.append(line + "\n");
        numlin = numlin + 1;
        if (debug) System.out.println(numlin+" "+line);
        StringTokenizer st = new StringTokenizer(line);
        if(numlin == 1) {
          st.nextToken();
          nsel[0] = Integer.valueOf(st.nextToken()).intValue();
          if(debug)System.out.println("nsel[0] ="+nsel[0]);
          nsel[1] = Integer.valueOf(st.nextToken()).intValue();
          if(debug)System.out.println("nsel[1] ="+nsel[1]); 
        }   
        if(numlin > 1 && numlin < 7){
          j = (numlin-2)*10;
          for(int i =0;i<10;i++){
            isel[0][j]=Integer.valueOf(st.nextToken()).intValue();
            if(debug)System.out.println("isel ="+isel[0][j]);j++;
          }
        }
        if(numlin > 6 && numlin < 12){
          j = (numlin-7)*10;
          for(int i =0;i<10;i++){
            isel[1][j]=Integer.valueOf(st.nextToken()).intValue();
            if(debug)System.out.println("isel ="+isel[1][j]);j++;
          }
        }
        if(numlin > 11 && numlin < 17){
          j = (numlin-12)*10;
          for(int i =0;i<10;i++){
            c[0][j]=Double.valueOf(st.nextToken()).doubleValue();
            if(debug)System.out.println("c ="+c[0][j]);j++;
          }
        }
        if(numlin > 16 && numlin < 22){
          j = (numlin-17)*10;
          for(int i =0;i<10;i++){
            c[1][j]=Double.valueOf(st.nextToken()).doubleValue();
            if(debug)System.out.println("c ="+c[1][j]);j++;
          }
        }
        if(numlin == 22){
          xin = Double.valueOf(st.nextToken()).doubleValue();
          yin = Double.valueOf(st.nextToken()).doubleValue();
          if(debug)System.out.println("x0,y0= "+xin+yin);
          break;
        }
      }
    }
    catch (IOException e) {
      System.out.println("IO Error:" + e.getMessage());
    }
  }    

  public void init(){
  if (debug) System.out.println("Computing iexe");
  /* This is to speed up formula computation */
  for(int i=0; i < 2; i++)for(int j=0; j < nsel[i]; j++) iexe[i][j] = 1;
  for (int j=0; j < 2; j++) {
    for (int i=0; i < nsel[j]; i++) {
      if(isel[j][i] > 15 && isel[j][i] < 19) {
        numpull = 0;
        if((i+1) < nsel[j]) {
          for(k = i+1; k < nsel[j]; k++) {
            if(isel[j][k] > 15 && isel[j][k] < 19)numpull = numpull - 1;
            if(isel[j][k] > 18 && isel[j][k] < 23)numpull = numpull + 1;
            if(numpull == 1) break;
          }
        }
        if(numpull != 1) iexe[j][i] = 0;
      }
    }
  }
}

public Fpoint compute(Fpoint fp0){
  double x0,y0;

  x0 = fp0.x; y0 = fp0.y;
  p[0] = 0.; p[1] = 0.;
  for(int i=0; i< 2; i++) {
    istack = 0;
    for (int k=0; k < nsel[i]; k++) {
      switch (isel[i][k]) {
        case  1: p[i] = p[i] + x0;break;
        case  2: p[i] = p[i] + y0;break;
        case  3: p[i] = p[i] + c[i][k];break;
        case  4: p[i] = p[i] - x0;break;
        case  5: p[i] = p[i] - y0;break;
        case  6: p[i] = p[i] - c[i][k];break;
        case  7: p[i] = p[i] * x0;break;
        case  8: p[i] = p[i] * y0;break;
        case  9: p[i] = p[i] * c[i][k];break;
        case 10: if(x0 == 0.) p[i] = 0.;else  p[i] = p[i] / x0;break;
        case 11: if(y0 == 0.) p[i] = 0.;else  p[i] = p[i] / y0;break;
        case 12: if(c[i][k] == 0.) p[i] = 0.;else  p[i] = p[i] / c[i][k];break;
        case 13: if(k == 0)p[i] = x0;break;
        case 14: if(k == 0)p[i] = y0;break;
        case 15: if(k == 0)p[i] = c[i][k];break;
        case 16: if(iexe[i][k] == 1){
                   istack = istack + 1; 
                   stack[istack] = p[i];
                   p[i] = x0;
                 }
                 break;
        case 17: if(iexe[i][k] == 1){
                   istack = istack + 1; 
                   stack[istack] = p[i];
                   p[i] = y0;
                 }
                 break;
        case 18: if(iexe[i][k] == 1){
                   istack = istack + 1; 
                   stack[istack] = p[i];
                   p[i] = c[i][k];
                 }
                 break;
        case 19: if(istack > 0) {
                   p[i] = p[i] + stack[istack];
                   istack = istack - 1;
                 }
                 break;
        case 20: if(istack > 0) {
                   p[i] = p[i] - stack[istack];
                   istack = istack - 1;
                 }
                 break;
        case 21: if(istack > 0) {
                   p[i] = p[i] * stack[istack];
                   istack = istack - 1;
                 }
                 break;
        case 22: if(istack > 0) {
                    if(stack[istack] == 0.)  p[i] = 0.;
                    else {
                      p[i] = p[i] / stack[istack];
                      istack = istack - 1;
                    }
                 }
                 break;
      }
//      if(debug)System.out.println("p[i]= "+p[i]);
    }
//    if(debug)System.out.println("i,p[i]= "+i+" "+p[i]);
  }
  fp1.x=p[0];fp1.y=p[1];
//  if(debug)System.out.println("fp1= "+fp1.x+" "+fp1.y);
  return(fp1);
  }
}

/*******************************************************
            Fpoint
*******************************************************/

class Fpoint{
  public double x;
  public double y;

  public Fpoint(double x0,double y0){
    x=x0; y=y0;
  }
}

/*******************************************************
            Dr1basin
*******************************************************/

class Dr1basin extends Canvas {
  boolean debug;
  int hh=200;
  int width=200;
  int maxcol;
  Thread runner;
  Formula form;
  byte data[] ;
  Image img;
  IndexColorModel icm;
  TextField f1;

  public void  setvar(boolean debug1,int maxcol1,
               Formula form1, IndexColorModel icm1, 
               Thread runner1, TextField f){
    debug = debug1;
    maxcol=maxcol1;
    runner=runner1;
    form = form1;
    data = new byte[hh*width];
    icm=icm1;
    img = createImage(new  MemoryImageSource(width,hh,icm,data,0,width));
    f1 = f;
  }

  public  void drawimage() {
    int Xscreen =hh ,Yscreen=width;
    int Nxpixel=hh,Nypixel=width;
    double Left= -4.,Right= 4.,Bottom= -4.,Top= 4.;
    int numcol = maxcol;
    int maxiter = 160;
    double x,y,x0,y0,xp,yp,Deltax,Deltay;
    Fpoint fp0 =new Fpoint(0.,0.);
    Fpoint fp1 =new Fpoint(0.,0.);
    int i,j,iter,ic,l,j1;

    /* Main loop on image pixels */
    Deltax = (Right - Left) / Xscreen;
    Deltay = (Top - Bottom) / Yscreen;
    for (j=0; j < Yscreen; j++) {
      f1.setText("Iteration "+j);
      try { runner.sleep(100);}
      catch (InterruptedException e) { }
      for (l=0;l < Xscreen; l++) {
        xp = l*Deltax + Left;
        yp = j*Deltay + Bottom;
        x0 = xp ;
        y0 = yp;
        x = xp;
        y = yp;
        iter = 1;
        while(iter <= maxiter){
          fp0.x = x0;
          fp0.y = y0;
          fp1 = form.compute(fp0);
          x = fp1.x;
          y = fp1.y;
          if(debug)System.out.println("x,y,x0,y0 = "+x+" "+y+" "+x0+" "+y0);
          if(Math.abs(x) > 10000f || Math.abs(y) > 10000f)break;
          iter = iter + 1;
          x0 = x;
          y0 = y;
        }
        ic = (iter % numcol) + 1;
        if(debug) System.out.println("pixel "+l+" "+j+" has color "+ic);
        data[l+(Yscreen-1-j) *width] = (byte)ic;
      }
      img.flush();
      img = null;
      img = createImage( new MemoryImageSource(width,hh,icm,data,0,width));
      repaint();
    }
  }

  public void paint(Graphics g){
    if(img != null)g.drawImage(img,0,10,this);
  }

  public void update (Graphics g) {
    paint(g);
  }
}

/*******************************************************
            Dr1global
*******************************************************/

class Dr1global extends Canvas{
  int Npix = 500;
  double Left = -4.;
  double Right = 4.;
  double Bottom =-4.;
  double Top = 4.;
  boolean debug;
  int maxcol;
  Thread runner;
  Formula form;
  byte data[] ;
  Image img;
  IndexColorModel icm;
  TextField f1;

  public void  setvar(boolean debug1,int maxcol1,
                Formula form1, IndexColorModel icm1, 
                Thread runner1, TextField f){
    debug = debug1;
    maxcol=maxcol1;
    runner=runner1;
    form = form1;
    data = new byte[Npix*Npix];
    icm=icm1;
    img = createImage(new  MemoryImageSource(Npix,Npix,icm,data,0,Npix));
    f1 = f;
  }

  public void drawimage() {
    double dx = (Right -Left)/Npix;
    double dy = (Top - Bottom)/Npix;
    int ine[][] = new int[Npix][Npix];
    int jne[][] = new int[Npix][Npix];
    int i,j,ncy,i0,j0,lcy,i1,j1,ntotcy1,ntotcy2,ncol;
    int icy[][] = new int[Npix][Npix];
    Fpoint fp0 =new Fpoint(0.,0.);
    Fpoint fp1 =new Fpoint(0.,0.);

    if(debug)System.out.println("First phase");
    f1.setText("First phase");
    try { runner.sleep(100);}
    catch (InterruptedException e) { }
    for ( i=0;i<Npix;i++){
      double x0 = Left + i*dx+dx/2.;
      for ( j=0;j<Npix;j++){
        double y0 = Bottom + j*dy+dy/2.;
        double x1,y1; 
        icy[i][j] = 0;
        fp0.x = x0;
        fp0.y = y0;
        fp1 = form.compute(fp0);
        x1 = fp1.x;
        y1 = fp1.y;
        if ((y1>4)||(x1>4)||(x1<-4)||(y1<-4)) {
          icy[i][j]=-1000000;
        } else {
          ine[i][j]=(int)((x1-Left)/(Right-Left)*Npix);
          jne[i][j]=(int)((y1-Bottom)/(Top-Bottom)*Npix);
          if(ine[i][j] >= Npix)ine[i][j]=Npix-1;
          if(jne[i][j] >= Npix)jne[i][j]=Npix-1;
          if(ine[i][j] == i && jne[i][j] == j)icy[i][j]=-2;
        }
//        if(debug)System.out.println("i,j,icy,x1,y1,ine,jne= "
//                     +i+" "+j+" "+icy[i][j]+" "+x1+" "
//                     +y1+" "+ine[i][j]+" "+jne[i][j]);
      }
    }
    if(debug)System.out.println("Second phase");
    f1.setText("Second phase");
    try { runner.sleep(100);}
    catch (InterruptedException e) { }
    ncy = 1;
    ntotcy1 = 0;
    ntotcy2 = 0; 
    for ( i=0;i<Npix;i++){
      for ( j=0;j<Npix;j++){
        if(icy[i][j] == 0) {
          i0 = i;
          j0 = j;
          ncy = ncy + 1;
          lcy = 0;
          lcy = lcy +1;
          icy[i0][j0] = ncy;
//          if(debug)System.out.println("i0,j0,ncy="+i0+" "+j0+" "+icy[i0][j0]);
          i1 = ine[i0][j0];
          j1 = jne[i0][j0];
          while(icy[i1][j1] == 0) {
            i0 = i1;
            j0 = j1;
            lcy = lcy + 1;
            icy[i0][j0] = ncy;
//            if(debug)System.out.println("i0,j0,ncy="+i0+" "+j0+" "+icy[i0][j0]);
            i1 = ine[i0][j0];
            j1 = jne[i0][j0];
          }
          if(icy[i1][j1] != ncy) { 
            if(icy[i1][j1] <= -1000000) {
              ntotcy2 = ntotcy2 + 1;
              i0 = i;
              j0 = j;
              while(icy[i0][j0] == ncy) {
                icy[i0][j0] = -1000000-lcy;
//                if(debug)System.out.println("i0,j0,ncy="+i0+" "+j0+" "+icy[i0][j0]);
                i1 = ine[i0][j0];
                j1 = jne[i0][j0];
                i0 = i1;
                j0 = j1;
                lcy = lcy -1;
              }
            ncy = ncy -1;
            } else if (icy[i1][j1]>0 ||(icy[i1][j1] < 0 && icy[i1][j1] > -1000000)) {
              ntotcy1 = ntotcy1 + 1;
              i0 = i;
              j0 = j;
              while(icy[i0][j0] == ncy) {
                icy[i0][j0] = -ncy;
//                if(debug)System.out.println("i0,j0,ncy="+i0+" "+j0+" "+icy[i0][j0]);
                i1 = ine[i0][j0];
                j1 = jne[i0][j0];
                i0 = i1;
                j0 = j1;
              }
            }
          }
        }
      }
    }
    if(debug)System.out.println("third phase");
    f1.setText("Last phase");
    try { Thread.sleep(100);}
    catch (InterruptedException e) { }
    for ( i=0;i<Npix;i++){
      for ( j=0;j<Npix;j++){
        ncol = 1;
        if(icy[i][j] > 1) {
          ncol = icy[i][j]%(maxcol-10) + 10;
        }
        if(icy[i][j] < -1 && icy[i][j] > -1000000) {
          ncol = -icy[i][j];
          if(ncol >= maxcol) {
            ncol = (int)(ncol/(double)ntotcy1*maxcol);
          }
          ncol = ncol%(maxcol-10) + 10;
        }
        if (icy[i][j] <= -1000000){
          ncol = (-(icy[i][j]-1000000))%(maxcol-10)+ 1;
        }
        data[i+(Npix-1-j) *Npix] = (byte)ncol;
        if(debug)System.out.println("i,j,icy,ncol= "+i+" "+j+" "+icy[i][j]+" "+ncol);
      }
    }
    img.flush();
    img = null;
    img = createImage( new MemoryImageSource(Npix,Npix,icm,data,0,Npix));
    f1.setText("Done");
    if (debug)System.out.println("Done!");
  }

  public void update (Graphics g) {
    paint(g);
  }

  public void paint(Graphics g){
    if(img != null)g.drawImage(img,0,10,this);
  }
}

/*******************************************************
            Dr1attr
*******************************************************/

class Dr1attr extends Frame {
  boolean debug;
  int Npix=500;
  Formula form;
  TextField f1;

  public Dr1attr(String s) {
    super(s);
    MenuBar mb = new MenuBar();
    setMenuBar(mb);
    Menu m1 = new Menu("File");
    mb.add(m1);
    m1.add(new MenuItem("Quit"));
  }

  public void  setvar(boolean debug1,Formula form1,TextField f){
    debug = debug1;
    form = form1;
    f1 = f;
  }

  public boolean action(Event e, Object o) {
    if (e.target instanceof MenuItem) {
      String label = (String)o;
      if (label.equals("Quit")) dispose();
      return true;
    }
    else return false;
  }

  public  void drawimage(boolean same,double xin,double yin) {
    double Left= -4.,Right= 4.,Bottom= -4.,Top= 4.;
    Fpoint fp0 =new Fpoint(0.,0.);Fpoint fp1 =new Fpoint(0.,0.);
    double x0,y0,x,y;
    int xpix,ypix;
    int Npix1,Npix2;
    Graphics g;

    g = this.getGraphics();
    if(!same)g.setColor(Color.black);
    if(!same)g.fillRect(0,0,this.size().width,this.size().height);
    f1.setText("Drawing attractor");
    x0 = xin; y0 =yin;
    Npix1 = this.size().width;
    Npix2 = this.size().height;
    g.setColor(Color.blue);
    for (int l=0;l < 10000; l++) {
      fp0.x = x0;
      fp0.y = y0;
      fp1=form.compute(fp0);
      x=fp1.x;y=fp1.y;
      if (l > 1000) {
        xpix = (int)((x-Left)/(Right-Left)*Npix1);
        ypix = Npix2-(int)((y-Bottom)/(Top-Bottom)*Npix2);
        g.drawLine(xpix,ypix,xpix,ypix);
      }
//      if(debug)System.out.println("x,y,x0,y0 = "+x+" "+y+" "+x0+" "+y0);
      x0 =x;y0=y;
      if(x0 < Left || x0 > Right || y0 < Bottom || y0 > Top) break;
    }
  }

  public void update (Graphics g) {
    paint(g);
  }
}
