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

//********************************************************************
/**                    
* Phase space reconstruction diagnostics for Odes <br>
* @version 24 October 1997
* @author Michael Cross
*/
//********************************************************************

public class OdesReconstruct extends OdesDiagnostics {


/** time for ghost */      
      double ghostTime=10.;      
/** number of iterations for ghost */      
      int ghostLength;      
/** updated number of points in plot */      
      int nplot;
/** index of first data curve */      
      int ncurve1;
/** copy of x */       
      double[] xp={0.,0.,0.,0.};
/** number of dt in delay */
      int nTau;
      int delayIndex;
      int delayLength;
      int reconstructVariable;
      double[] delayArray;
      String[] titleArray={"Time","X(t)","X(t+T)","X(t+2T)"};
      

//******************************************************************
/**
* @param inParent parent class
* @see Map1D
*/
//******************************************************************
      public OdesReconstruct(Odes inParent) {
            super(inParent);                           
      }
      
//********************************************************************
/**
* Updates parameters from the text controls in parent class 
*/ 
//********************************************************************            
      public void updateParameters() { 
            super.updateParameters();
            ghostLength=(int)(parent.ghostTime/dtp); 
            nTau=parent.variables.parseTextField(4,nTau,true);
            reconstructVariable=parent.variables.parseTextField(5,reconstructVariable,1,3);  
            if(plot_x==0 || plot_y==0 || plot_x==plot_y) {
                 if(plot_x==0) {
                        plot_x=plot_y+1;
                        if(plot_x>3) plot_x=1;
                 }
                 if(plot_y==0) {
                        plot_y=plot_x+1;
                        if(plot_y>3) plot_y=1;
                 }
                 if(plot_y==plot_x) {
                        plot_y=plot_x+1;
                        if(plot_y>3) plot_y=1;
                 }                                  
                 parent.parameters.setText(5,String.valueOf(plot_x));
                 parent.parameters.setText(6,String.valueOf(plot_y));                                        
            }           
            parent.graph.setXAxisTitle(titleArray[plot_x]);
            parent.graph.setYAxisTitle(titleArray[plot_y]); 
                                                                 
      }      
                
//*********************************************************************
/**
* Restarts
*/
//*********************************************************************      
      public boolean restart() {
            
            int delayIndexSave;           
            double[] delayCopy; 
            double data[] = new double[2*ghostLength];
            double data1[] = new double[4];
            double data2[] = new double[4];
            int i,j;
            double xSave[] = new double[nVariables];
            double tSave;
            delayLength=2*nTau+1;
            delayArray=new double[delayLength];
            t=0.;

            if(runTrans) {
                if(!eliminateTransient()) return false;
                runTrans=false;
                parent.status.setText("");
            }
                                                           
            for(i=0;i<delayLength;i++) {
                try {
                       t=parent.solver.timeStep(x,t,dtp);
                } catch (ArithmeticException e) {
                       alertDialog alert = new alertDialog
                             (parent,"Value has diverged. Try again! ");
                return false;
                }                                 
                delayArray[i]=x[reconstructVariable];
            }             
            delayIndex=0;
            if(ghostLength>0) {                       
                   for(i=0;i<nVariables;i++) {
                       xSave[i]=x[i];
                   }
                   tSave=t;
                   delayCopy=new double[delayLength]; 
                   System.arraycopy(delayArray,0,delayCopy,0,delayLength);
                   delayIndexSave=delayIndex;                   
            
                   nplot=0;
                   delayIndex=0;
                   for(i=0,j=0;i<ghostLength;i++) {
                       try {
                              t=parent.solver.timeStep(x,t,dtp);
                       } catch (ArithmeticException e) {
                              alertDialog alert = new alertDialog
                                    (parent,"Value has diverged. Try again! ");
                       return false;
                       }                                                        
                       nplot=process(x,data,nplot);
                   }        
 
                   ncurve = parent.graph.addCurve(data,nplot,parent.transientColor);
                   System.arraycopy(delayCopy,0,delayArray,0,delayLength);
                   delayIndex=delayIndexSave;
                   for(i=0;i<nVariables;i++) {
                        x[i]=xSave[i];
                   }
                   t=tSave;                   
            }

            err=0.;
            runTrans=false;
            nplot=0;            
            while(nplot < 2) {
                try {
                      t=parent.solver.timeStep(x,t,dtp);
                } catch (ArithmeticException e) {
                       alertDialog alert = new alertDialog
                              (parent,"Value has diverged. Try again! ");
                       return false;
                }                                
                nplot=process(x,data1,nplot);      
            }
            parent.status.setText("");
                      
            ncurve = parent.graph.addCurve(data1,nplot,Color.blue);
            ncurve1=ncurve;                               

            parent.graph.paintAll=true; 
            parent.graph.repaint();
            return true;
            
      
      }

//*********************************************************************
/**
* Iterates ODEs and updates graph
* @return true if iteration successful
*/
//*********************************************************************      
      public boolean iterate() { 
            double[] moredata = new double[2];
            double[] moredata1 = new double[2];  
            nplot=0;
            try{
                  for(int i=0;i<delay;i++)  
                        t=parent.solver.timeStep(x,t,dt);
            } catch (ArithmeticException e) {
                  alertDialog alert = new alertDialog(
                        parent,"Value has diverged.");
                  return false;
            }                                                
            nplot=process(x,moredata,nplot);

            if(nplot > 0) {
                  parent.graph.paintAll=false;     // Don't paint while updating data  
                  parent.graph.appendToCurve(moredata,1,ncurve1);
                  parent.graph.paintAll=true;
                  parent.graph.clearAll=false;
                  parent.graph.repaint();
//                  graph.paint(graph.getGraphics());
            }    
            errp=parent.solver.err[plot_x]+parent.solver.err[plot_y];
            if(errp>err) err=errp;                       
            if(parent.showTime)
                  parent.status.setText("     Time ="+(float)t);
            return true;                        
      }
      
//**********************************************************************
/**
* Sets default values of parameters depending on plot type
*/
//**********************************************************************          
      public void setDefaults() {
                   parent.variables.show(4);
                   parent.variables.show(5);                        
                   parent.variables.hide(6);  
                   parent.variables.setText(4,"10");
                   parent.variables.setLabelText(4,"Delay");
                   parent.variables.setText(5,"1");
                   parent.variables.setLabelText(5,"Variable");                                                                 
      
                   parent.topRightPanel.validate();        
      }                                       

//**********************************************************************
/**
* Action to perform on mouse click. Default is display coordinates 
* of point
*/
//**********************************************************************      
      public void respondToClick(double xcoord, double ycoord) {
             double data[] = new double[4];                 

             if(parent.aThread != null) {
                  x[plot_x]=xcoord;
                  x[plot_y]=ycoord;
                  data[0]=xcoord;
                  data[1]=ycoord;
                  data[2]=xcoord;
                  data[3]=ycoord;
                  ncurve = parent.graph.addCurve(data,1,Color.blue);
                  ncurve1=ncurve;                               
                  parent.clicked=false;                        
             }     
      }       

//**********************************************************************
/**
* Shifts x to 0<x<1
* @param x input value
* @return value shifted to between 0 and shift
*/
//**********************************************************************      
      private double mod(double x, double shift) {
         while (x>shift) {
            x=x-shift;
         }   
         while (x<0.) {
            x=x+shift;
         }
         return x;
      }

//**********************************************************************
/**
* Shifts x to 0<x<1
* @param x input value
* @return value shifted to between 0 and shift-1
*/
//**********************************************************************      
      private int mod(int x, int shift) {
         while (x>=shift) {
            x=x-shift;
         }   
         while (x<0) {
            x=x+shift;
         }
         return x;
      }

//**********************************************************************
/**
* Sets delay for movie iteration
*/
//**********************************************************************      
      public void setDelay(int inDelay) {
            delay=inDelay;
            dt=dtp/((double) delay);
            ntrans=(int) (trans/dtp); 
            ghostLength=(int) (parent.ghostTime/dtp);           
      } 

//**********************************************************************

/**
* process data
* @param    x variable
* @param    data for plotting
* @param    nplot number of points indata
* @return   nplot new number of points in data
*/          
//**********************************************************************                        

      int process(double x[], double[] data,  int nplot) {
              int j=2*nplot;              
              data[j++]=delayArray[mod(delayIndex+(plot_x-1)*nTau,delayLength)];
              data[j]=delayArray[mod(delayIndex+(plot_y-1)*nTau, delayLength)];
              delayIndex=mod(delayIndex+1,delayLength);
              delayArray[mod(delayIndex+2*nTau, delayLength)]=x[reconstructVariable];
              nplot++;                            
              return nplot;
      }
      
}      
