import ChaosDemos.*;
import java.awt.*;
import java.util.*;

//********************************************************************
/**                    
* Diagnostics for Map1D <br>
* Plots the "bifurcation diagram" i.e. the values of x in the attractor
* for different values of the map parameter a.<br>
* Portions of the plot can be enlarged by outlining with a mouse drag.
* Points on the running plot can be read out with a mouse click.
* @version 10 October 1997
* @author Michael Cross
*/
//********************************************************************     

public class Map1DBifurcation extends Map1DDiagnostics {
 
/** maximum number of attempts to iterate from initial condition to fond point */       
      private static int MAX_TRY=1024;                             
/** number of data points for power spectrum (must be power of 2!) and histogram */
      private int dataLength ;
/** 2*dataLength */
      private int dataLength2;
/** array for plotting histogram */
      private double[] plotData;
/** Minimum value of a in scan */      
      private double amin;
/** Maximum value of a in scan */      
      private double amax;         
/** increment of a */
      private double dela;   
/** true if axes range contains first point **/
      private boolean validRange;                       
          

//******************************************************************
/**
* @param inParent parent class
* @see Map1D
*/
//******************************************************************
      public Map1DBifurcation(Map1D inParent) {
            super(inParent);
            hideab=true;                                                                                                    
      }
      
//********************************************************************
/**
* Updates parameters from the text controls in parent class 
*/ 
//********************************************************************
      public void updateParameters() {
            int i;           

          if(parent.mapFunction.enforceBRange) {
                double bMaxLimit=parent.mapFunction.bMaximum;
                double bMinLimit=parent.mapFunction.bMinimum;
                b=parent.variables.parseTextField(1, 0.5*(bMinLimit+bMaxLimit),
                            bMinLimit, bMaxLimit);
          }                  
          else  b=parent.variables.parseTextField(1, b);
          aMaxLimit=parent.mapFunction.getAMaximum(b);             
          aMinLimit=parent.mapFunction.getAMinimum(b);
          if(parent.mapFunction.enforceARange) {     
            amin=parent.variables.parseTextField(5, aMinLimit, aMinLimit, aMaxLimit);
            amax=parent.variables.parseTextField(6, aMaxLimit, aMinLimit, aMaxLimit);
          }  
          else {
            amin=parent.variables.parseTextField(5, amin);
            amax=parent.variables.parseTextField(6, amax);
          }  

          if(!setAxesRange) {                               
                xmin=amin;
                xmax=amax;
          }      

          dataLength=parent.variables.parseTextField(4,256,true);
          dataLength2=2*dataLength;
          
          a=xmin;
          nParameters=parent.nParameters;
          parameters = new double[nParameters];
          parameters[0]=a;
          if(nParameters>1) parameters[1]=parent.parameters[1];
          parent.mapFunction.setParameters(parameters);                                   

          x=Math.random();
          ntrans=parent.variables.parseTextField(3,ntrans);
          if(ntrans>0) runTrans=true;                                                

          nf=parent.variables.parseTextField(2,nf,true);
          parent.mapFunction.setCompose(nf);                             
      }      
                
//*********************************************************************
/**
* Restarts
*/
//*********************************************************************
      
      public void restart() {

            double data1[] = new double[6];
            double data2[] = new double[6];
            int i,j;

            double f;
            int ip=0;
            
            a=xmin;
            parameters[0]=xmin;
            parent.mapFunction.setParameters(parameters);              
            
            // Reset graph
            ncurve=parent.resetGraph();
                        
           plotData = new double[dataLength2];
           data1[0]=xmin;
           data1[1]=ymin;
           data1[2]=xmax;
           data1[3]=ymax; 

           ncurve = parent.graph.addCurve(data1,2,Color.black,0,7,1.); 
           data2[0]=xmin;
           i=0;
           validRange=false;
           while(i< MAX_TRY && !validRange) {
                 x=Math.random();
                 // Eliminate transient
                 if(runTrans) {
                     for(j=0;j<ntrans;j++) 
                         x=parent.mapFunction.iterate(x);                         
                 }
                 i++;
                 j=0;                 
                 validRange=checkRange(a,x);
                 while(j< MAX_TRY && !validRange) {                   
                      x=parent.mapFunction.iterate(x);
                      validRange=checkRange(a,x);
                      j++;
                 }
           }
//           runTrans=false;               //don't need this ? 11/2/97              
           if(!validRange) {
                 alertDialog alert = new alertDialog
                 (parent," No points in x-range: please reset to continue");
                 return; 
           }
           data2[1]=x;
           ncurve = parent.graph.addCurve(data2,1,Color.blue,0,7,1.);
           ncurve1=ncurve;
           dela=(xmax-xmin)/256.;
           iterations=0;
           parent.graph.paintAll=true;
           parent.graph.clearAll=true;
           parent.graph.repaint();        
            if(parent.showTime) parent.status.setText("No. of Iterations "+ iterations);            
      }

//*********************************************************************
/**
* Iterates Map equations and updates graph
*/
//*********************************************************************      
      public boolean iterate() {
            int i,j;
            double[] moredata = new double[6];
            double[] moredata1 = new double[6];

            for(i=0,j=0;i<dataLength;i++) {
                  x=parent.mapFunction.iterate(x);
                  if(checkRange(a,x)) {
                        plotData[j++]=a;
                        plotData[j++]=x;
                  }      
            } 
            parent.graph.clearAll=false;                         
            parent.graph.paintAll=false;     
            if(j>0) parent.graph.appendToCurve(plotData,j/2,ncurve1);
            parent.graph.paintAll=true;                        
            parent.graph.repaint();                        
            a=a+dela;
            if(a>xmax) a=xmin+Math.random()*dela;
            parameters[0]=a;
            parent.mapFunction.setParameters(parameters);
            x=Math.random();
            for(i=0;i<ntrans;i++) x=parent.mapFunction.iterate(x);            
            return true;
      }
      
//**********************************************************************
/**
* Sets default values of parameters
*/
//**********************************************************************          
      public void setPlotDefaults() {
               String[] label={"Transient","Points","  a_min  ","  a_max  "};
               String[] text={"64","8",String.valueOf(parent.mapFunction.aMinimum),
                            String.valueOf(parent.mapFunction.aMaximum)};
               parent.setPlotTextBoxes(label,text);                               
               parent.choices.setState(0,false);
               parent.showTime=false;
               parent.status.setText("");
               parent.choices.disable(0);  
      }                 
            
           
//**********************************************************************
/**
* Checks if point within plot range
* @param x x-coordinate of point
* @param y y-coordinate of point
* @return true if within range
*/
//**********************************************************************              
      private boolean checkRange(double x,double y) {
            if(x>=xmin && x<=xmax && y>=ymin && y<=ymax) return true;
            else return false;
      }
      
//**********************************************************************
/**
* Resets x-range to 0 < x < 1
*/
//**********************************************************************            
      public void resetRange() {
            xmin=amin;
            xmax=amax;
            ymin=0.;
            ymax=1.;
            setAxesRange=false;
      } 
      
//**********************************************************************                     
}      
