import java.applet.*;
import java.awt.*;
import java.awt.event.*;    
/*
<applet code="Logistic_large" width=1074 height=588>
</applet>
*/
public class Logistic_large extends Applet implements ActionListener, ItemListener, Runnable {
    Image bif;
    Thread t;
    MyCanvas c;
    MyCanvas2 c2;
    Panel p,p1,p2,p3;
    Choice ch;
    TextField txdelr,txx0,txn,txCr,txIr;
    Button btnFaster,btnSlower,btnGo,btnPause,btnStop,btnBack;
    int delt=500;
    double r0,x0,delr,r;
    int histoCanvasWidth = 872;  // number of pixels in width = 872-50=822
    int histoCanvasHeight = 348; //272
    int imageCanvasWidth = 872;  //682
    int imageCanvasHeight = 228; //178
    int n,m;
//  m is bin size in pixels. Choices for m are K (default), K/2 and K/4 where K=length of histogram in pixels.
    final int ind=25;
//  ind is the indent of the x and y axis on c (the canvas containing the histogram)
    final int h=800;
    boolean isPause=false,isForward=false,isBackward=false,isStop=false;
    int j;

    public void init() {
         bif=getImage(getDocumentBase(),"BIF20.jpg");
         setLayout(new BorderLayout());
         p1=new Panel();
         p1.setLayout(new BorderLayout());
         p2=new Panel();
         p3=new Panel();
         add(p1,"West");
         p1.add(p2,"Center");
         p1.add(p3,"South");
         c2=new MyCanvas2();
//	   c2 is MyCanvas2 and is the top left canvas that contains the image of the bifurcation diagram
         c2.setSize(imageCanvasWidth,imageCanvasHeight);   //this set the size of c2
         p2.add(c2);
         c=new MyCanvas();
//       c is MyCanvas and is the bottom left canvas that contains the histogram
         c.setSize(histoCanvasWidth,histoCanvasHeight);   //this sets the size of c
         m = (c.getSize()).width - 2*ind;  //this is K, the width of the histogram (from 0 to 1) in pixels
         // n=m;
         p3.add(c);
         p=new Panel();
//       p is the panel containing the input elements
         p.setLayout(new GridLayout(18,1));
         Label lbIr=new Label("a0:",Label.CENTER);
         p.add(lbIr);
         txIr=new TextField("3.4");
         p.add(txIr);
         Label lbx0=new Label("x0: ",Label.CENTER);
         p.add(lbx0);
         txx0=new TextField("0.5");
         p.add(txx0);
         Label lbdelr=new Label("Delta a: ",Label.CENTER);
         p.add(lbdelr);
         txdelr=new TextField("0.001");
         p.add(txdelr);
         Label lbr=new Label("a: ",Label.CENTER);
         p.add(lbr);
         txCr=new TextField("3.4");
         p.add(txCr);
         Label lbn=new Label("N: ",Label.CENTER);
         p.add(lbn);
         txn=new TextField("20000");
         p.add(txn);
         ch=new Choice();
         ch.addItem("m");
         ch.addItem(""+m);
         ch.addItem(""+m/2);
         ch.addItem(""+m/4);
         ch.addItemListener(this);
         p.add(ch);
         Label lbSpace=new Label("");
         p.add(lbSpace);
         btnGo=new Button("forward");
         btnGo.addActionListener(this);
         p.add(btnGo);
         btnBack=new Button("backward");
         btnBack.addActionListener(this);
         p.add(btnBack);
         btnFaster=new Button("faster");
         btnFaster.addActionListener(this);
         p.add(btnFaster);
         btnSlower=new Button("slower");
         btnSlower.addActionListener(this);
         p.add(btnSlower);
         btnPause=new Button("pause");
         btnPause.addActionListener(this);
         p.add(btnPause);
         btnStop=new Button("stop");
         btnStop.addActionListener(this);
         p.add(btnStop);
         add(p,"Center");
     
       	        r=Double.valueOf(txIr.getText()).doubleValue();
                x0=Double.valueOf(txx0.getText()).doubleValue();
                n=Integer.parseInt(txn.getText());
    }

    public Insets getInsets() {
          return new Insets(0,20,0,20);
    }

    public void run() {
       try
          {
            while(true){
                if(isPause || isStop){
                   break;
                }
                Thread.sleep(delt);
                j++;
                if(isForward)r=r0+j*delr;
                else if(isBackward)r=r0-j*delr;
                txCr.setText(""+r);
                c.repaint();
                c2.repaint();
            }
          }
        catch (Exception ie) {}
    }

    public void actionPerformed(ActionEvent ae) {
      String aeStr=ae.getActionCommand();
         if(aeStr=="faster" && (isForward || isBackward)) {
                 delt=delt-200;
                 if (delt<=100)delt=100;
         }
         else if(aeStr=="slower" && (isForward || isBackward)) {
                 delt=delt+200;
         }
         else if(aeStr=="pause" && (isForward || isBackward) && !isPause) {
                 isPause=true;
         }
         else if(aeStr=="stop" && (isForward || isBackward)) {             
             isStop=true;
             delt=500;
         }
         else if((aeStr=="forward" && !(isForward || isBackward)) || (aeStr=="forward" && isPause) || (aeStr=="forward" && isStop)) {
            try{
       	        if(!isPause)r0=Double.valueOf(txIr.getText()).doubleValue();
       	        else if(isPause)r0=Double.valueOf(txCr.getText()).doubleValue();
                delr=Double.valueOf(txdelr.getText()).doubleValue();
                x0=Double.valueOf(txx0.getText()).doubleValue();
                n=Integer.parseInt(txn.getText());
            }
            catch(Exception e) {}
                 j=0;
                 isForward=true;
                 isBackward=false;
                 isStop=false;
                 isPause=false;
                 t=new Thread(this);
                 t.start();
         }
         else if((aeStr=="backward" && !(isForward || isBackward)) || (aeStr=="backward" && isPause) || (aeStr=="backward" && isStop)) {
            try{
       	        if(!isPause)r0=Double.valueOf(txIr.getText()).doubleValue();
       	        else if(isPause)r0=Double.valueOf(txCr.getText()).doubleValue();
                delr=Double.valueOf(txdelr.getText()).doubleValue();
                x0=Double.valueOf(txx0.getText()).doubleValue();
                n=Integer.parseInt(txn.getText());
            }
            catch(Exception e) {}
                 j=0;
                 isForward=false;
                 isBackward=true;
                 isStop=false;
                 isPause=false;
                 t=new Thread(this);
                 t.start();
         }
      }
    public void itemStateChanged(ItemEvent ie) {
        Choice cc=(Choice)ie.getItemSelectable();
        m=Integer.parseInt(cc.getSelectedItem());
    }
class MyCanvas2 extends Canvas { 
    public void update(Graphics g) {
          paint(g);
    }
    public void paint(Graphics g) {
        int x=0;
        Dimension d=getSize();
//      d is the size of c2 in pixels
        Image buffer=createImage(d.width,d.height); //this create a buffer with size d
        Graphics bufferg=buffer.getGraphics();
        bufferg.setColor(Color.white);
        bufferg.fillRect(0,0,d.width,d.height);
        bufferg.setColor(Color.black);
        bufferg.drawImage(bif,100,0,this);  //this draws the bif image on the buffer, x0=100, y0=0
        if(r>2.8 && r<=4.){
           x=(int)(139+124*(r-3));       // *******
        }
        bufferg.drawLine(x,93,x,7);
        g.drawImage(buffer,0,0,this);  //this draws buffer on to c2
    }
}

class MyCanvas extends Canvas { 
    int xCount[]=new int[822];  // should be m        *****
    public void update(Graphics g) {
          paint(g);
    }

    public void paint(Graphics g) {
    for (int i=0; i<xCount.length; i++)
    {
       xCount[i]=0;
    }
        Font f=getFont();
        FontMetrics fm=getFontMetrics(f);
        Dimension d=getSize();
//      here d is the size of c
        Image buffer=createImage(d.width,d.height);
        Graphics bufferg=buffer.getGraphics();
        bufferg.setColor(Color.white); //set drawing background white
        bufferg.fillRect(0,0,d.width,d.height);
        bufferg.setColor(Color.black);  //set drawing black
//      the width of the histogram is (d.width - 2*ind)
//      the height of the histogram is (d.height - 2*ind)
        bufferg.drawLine(ind,d.height-ind,d.width-ind,d.height-ind);  
        bufferg.drawLine(ind,d.height-ind,ind,ind);
        bufferg.drawString("0",ind-fm.stringWidth("0")/2,d.height-10);
        int dx=(int)((d.width-2*ind)/10);
        bufferg.drawString("0.1",ind+dx-fm.stringWidth("0.1")/2,d.height-10);
        bufferg.drawString("0.2",ind+2*dx-fm.stringWidth("0.2")/2,d.height-10);
        bufferg.drawString("0.3",ind+3*dx-fm.stringWidth("0.3")/2,d.height-10);
        bufferg.drawString("0.4",ind+4*dx-fm.stringWidth("0.4")/2,d.height-10);
        bufferg.drawString("0.5",ind+5*dx-fm.stringWidth("0.5")/2,d.height-10);
        bufferg.drawString("0.6",ind+6*dx-fm.stringWidth("0.6")/2,d.height-10);
        bufferg.drawString("0.7",ind+7*dx-fm.stringWidth("0.7")/2,d.height-10);
        bufferg.drawString("0.8",ind+8*dx-fm.stringWidth("0.8")/2,d.height-10);
        bufferg.drawString("0.9",ind+9*dx-fm.stringWidth("0.9")/2,d.height-10);
        bufferg.drawString("1",d.width-ind-fm.stringWidth("1")/2,d.height-10);
        bufferg.drawString("x",d.width-ind+10,d.height-ind+5);
        bufferg.drawString("0",ind-fm.stringWidth("0")-5,d.height-20);
        bufferg.drawString(""+h,ind-fm.stringWidth(""+h)-5,ind+5);
        bufferg.drawString("N",ind-fm.stringWidth("N")+5,ind-8);
       double x1=x0;
        for (int i=1; i<=n; i++) {
           double x2=r*x1*(1-x1);
         if (x2>=0. && x2<=1.) {
           x1=x2;
//         convert x2 to pixels;
	   x2=m*x2;
           xCount[(int)x2]++;
           }
        }
        for (int i=0; i<m; i++)
        {
           int y1=ind+(h-xCount[i])*(d.height-2*ind)/h;  // height of histo
           int y2=d.height-ind-y1;
           int x2=(d.width-2*ind)/m;
           int x11=ind+i*x2;
           bufferg.fillRect(x11,y1,x2,y2);
        }
        g.drawImage(buffer,0,0,this);
    }
 }
}