/***********************************************************
  Applet Displayrand1 : shows a random dynamical system
  from a data base of around 50000.
  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.*;
import java.applet.*;

public class Displayrand1 extends Applet implements Runnable {

  URL theURL;
  Thread runner;
  TextArea ta = new TextArea("Getting text...",30,20);
  Formula form,form1,form2;
  Vector formule;
  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 breed = false;
  boolean same = false;
  boolean back = false;
  Dr1basin basin;
  Dr1attr attr;
  Dr1global global;
  Panel imagePanel;
  Panel controlPanel;
  Panel buttonPanel;
  Panel textPanel;
  TextField f1,dipos,dnpos,f3,f4;
  int npos,ipos,ipos1,ipos2;

  public void init() {
    int i; 

    formule = new Vector();   
    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);

    form = new Formula(debug);
    String url1 = "ufattrdb" ;
    try { this.theURL = new URL(getDocumentBase(),url1); 
    }catch ( MalformedURLException e) {
      System.out.println("Bad URL: " + theURL);
    }
    formule.addElement(form);
    npos = formule.size();
    form.read(theURL,false);
    for (i =0; i<500;i++){
      System.out.println("Reading formula "+i);
      form = new Formula(debug);
      formule.addElement(form);
      form.next();
    }
    npos = formule.size();

    String url = "http://www.ba.infn.it/zitobin/nph-rformula";
    try { this.theURL = new URL(url); 
    }catch ( MalformedURLException e) {
      System.out.println("Bad URL: " + theURL);
    }
    setLayout(new BorderLayout());
    imagePanel = new Panel();
    imagePanel.setLayout(new GridLayout(2,1));
    add("Center", imagePanel);
    basin = new Dr1basin();
    imagePanel.add(basin);
    global = new Dr1global();
    imagePanel.add(global);
    attr = new Dr1attr("strange attractor");
    attr.resize(500,500);
    attr.move(50,50);
    attr.show();
    add("East",ta);
    controlPanel = new Panel();
    controlPanel.setLayout(new GridLayout(2,1));
    add("South", controlPanel);
    buttonPanel = new Panel();
    controlPanel.add  (buttonPanel);
    buttonPanel.add(new Button("Back")); 
    buttonPanel.add(new Button("Same"));
    buttonPanel.add(new Button("Forward")); 
    buttonPanel.add(new Button("Read next"));
    buttonPanel.add(new Button("Breed"));
    buttonPanel.add(new Button("Decode"));
    textPanel = new Panel();
    controlPanel.add(textPanel);
    f1 = new TextField("Starting",10);
    textPanel.add(f1);
    dnpos = new TextField(String.valueOf(npos),4);
    textPanel.add(dnpos);
    dipos = new TextField(String.valueOf(ipos),4);
    textPanel.add(dipos);
    f3 = new TextField("ipos1 "+ipos1,10);
    textPanel.add(f3);
    f4 = new TextField("ipos2 "+ipos2,10);
    textPanel.add(f4);
    start();  
    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 && !breed && !same && !back) {
      form = new Formula();
      formule.addElement(form);
      npos = formule.size();
      dnpos.setText(String.valueOf(npos) );
      form.read(theURL,true);
    }
    if(test || breed) form.write();
    form.print(ta);
    form.init();
    attr.drawimage(same,form.xin,form.yin);
    if(!same)same=true;
    global.drawimage();
    global.repaint();
    basin.drawimage();
  }
  public boolean action(Event e, Object arg) {
    String button_name;

    if(e.target instanceof Button){
      button_name =(String)arg;
      if(button_name.equals("Read next")){
        stop();
        breed = false;
        same = false;
        back = false;
        start();
      }
      if(button_name.equals("Back")){
        stop();
        back = false;
        if(ipos > 0){
          form = (Formula)(formule.elementAt(ipos-1));
          ipos = ipos -1;
          dipos.setText(String.valueOf(ipos));
          back = true;
          breed = false;
          same = false;
          start();
        }else f1.setText("No more formula");
      }
      if(button_name.equals("Forward")){
        stop();
        back = false;
        if(ipos < npos){
          form = (Formula)(formule.elementAt(ipos-1));
          ipos = ipos +1;
          dipos.setText(String.valueOf(ipos));
          back = true;
          breed = false;
          same = false;
          start();
        }else f1.setText("No more formula");
      }
      if(button_name.equals("Decode")){
        if(form.nsel[0]>0){
         form.decode();
         form.print(ta);
        }else f1.setText("No formula yet loaded");
      }
      if(button_name.equals("Same")){
        same = true;
        attr.drawimage(same,Math.random()*8.-4.,Math.random()*8.-4.);        
       }
      if(button_name.equals("Breed")){
        stop();
        if(formule.size()<2){
          do {
            form1 = new Formula();
            formule.addElement(form1);
            form2 = new Formula();
            formule.addElement(form2);
            form1.read(theURL,true);
            f1.setText("Read formula "+form1.nsel[0]+" "+form1.nsel[1]);
            form2.read(theURL,true);
            f1.setText("Read formula "+form2.nsel[0]+" "+form2.nsel[1]);
          } while((form1.nsel[0]+form2.nsel[0])>50 ||
                  (form1.nsel[1]+form2.nsel[1])>50);
        }
        form1 = new Formula();
        form2 = new Formula();
        do {
          ipos1 = (int) (Math.random()*formule.size());
          f3.setText("ipos1 "+ipos1); 
          ipos2 = (int) (Math.random()*formule.size());
          f4.setText("ipos2 "+ipos2); 
          form1 = (Formula)(formule.elementAt(ipos1));
          form2 = (Formula)(formule.elementAt(ipos2));
          f1.setText("Trying to breed formula "+ipos1+" and  "+ipos2);
        } while((form1.nsel[0]+form2.nsel[0])>50 ||
                  (form1.nsel[1]+form2.nsel[1])>50);
        form = new Formula();
        formule.addElement(form);
        for(int i=0;i<2;i++){
          for(int j=0;j<form1.nsel[i];j++){
            form.isel[i][j]=form1.isel[i][j];
            form.c[i][j]=form1.c[i][j];
          }
        }
        for(int i=0;i<2;i++){
          for(int j=0;j<form2.nsel[i];j++){
            form.isel[i][j+form1.nsel[i]]=form2.isel[i][j];
            form.c[i][j+form1.nsel[i]]=form2.c[i][j];
          }
        }
        form.nsel[0]=form1.nsel[0]+form2.nsel[0];
        form.nsel[1]=form1.nsel[1]+form2.nsel[1];
        form.write();
        breed = true;
        npos = formule.size();
        dnpos.setText(String.valueOf(npos));
        start();
      }
    }
    if(e.target instanceof TextField){
      if(e.target == dipos) {
        ipos = Integer.parseInt(dipos.getText());
        stop();
        if(ipos > 0 && ipos < npos){
          form = (Formula)(formule.elementAt(ipos-1));
          back = true;
          breed = false;
          same = false;
          start();
        }else f1.setText("Non existing formula");
      }
    }
    return true;
  }


}

/*******************************************************
            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.);
  static DataInputStream data;
  URLConnection conn;

  public Formula(boolean debug1){
    debug = debug1;
    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 Formula(){
    nsel[0] = 0;
  }

  public void print(TextArea ta){
    ta.setText(buf.toString()); 
  }
  
  public void write(){

    buf = new StringBuffer();
    buf.append(" 0 ");
    buf.append(nsel[0]+" "+nsel[1]+"\n");
    for(int i=0;i<2;i++){
      for(int j=0;j<50;j++){
        buf.append(isel[i][j]+" ");
        if(((j+1)%10)== 0)buf.append("\n");
      }
    }
    for(int i=0;i<2;i++){
      for(int j=0;j<50;j++){
        buf.append(c[i][j]+" ");
        if(((j+1)%10)== 0)buf.append("\n");
      }
    }  
    buf.append(" 0. 0. \n");
  }

  public void decode(){
    
    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 {; 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");
  }

  public void read(URL theURL,boolean db) {
    String line;
    int j;
    try {
      conn = theURL.openConnection();
      conn.connect();
      data = new DataInputStream(new BufferedInputStream(
                     conn.getInputStream()));
      if(db)line = data.readLine();
      if(db)line = data.readLine();
      next();
    }
    catch (IOException e) {
      System.out.println("IO Error:" + e.getMessage());
    }
  }

  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=100;
  int width=100;
  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 = 100;
  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);
  }
}
