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

//********************************************************************
/**                    
* TimeSeris Diagnostics for Odes <br>
* @version 24 October 1997
* @author Michael Cross
*/
//********************************************************************

public class OdesTimeSeries extends OdesDiagnostics {

/** true if two curves are to be plotted  */
      boolean curve2 = false;
/** 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;
/** index of second data curve */      
      int ncurve2;      
/** updated number of points in plot of second curve */         
      int nplot1; 
/** copy of x */       
      double[] xp={0.,0.,0.,0.};
/** x for second curve */      
      double[] x1={0.,0.,0.,0.};
/** perturbation */      
      double[] dx={0.,0.,0.,0.};  
/** time for second curve */      
      double t1=0;       
      String[] titleArray={"Time","  X ","  Y ","  Z "};
      

//******************************************************************
/**
* @param inParent parent class
* @see Map1D
*/
//******************************************************************
      public OdesTimeSeries(Odes inParent) {
            super(inParent);                           
      }
      
//********************************************************************
/**
* Updates parameters from the text controls in parent class 
*/ 
//********************************************************************            
      public void updateParameters() { 
            super.updateParameters();
            ghostLength=(int)(parent.ghostTime/dtp);                                                
            curve2=false;              
            for(int i=1;i<=3;i++) {
                dx[i]=parent.variables.parseTextField(i+3,dx[i]);
                if(dx[i]!=0.) curve2=true;
            }      
            parent.graph.setXAxisTitle(titleArray[plot_x]);
            parent.graph.setYAxisTitle(titleArray[plot_y]); 
                                                                 
      }      
                
//*********************************************************************
/**
* Restarts
*/
//*********************************************************************      
      public boolean restart() {
            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;
            if(x[0]==0.&&curve2) {
                for(i=1;i<=3;i++)
                    x1[i]=x[i]+dx[i];
                x1[0]=0.;
            }
            t=0.;
            t1=0;
//            parent.graph.clearAll=true;
//            parent.status.setText("");
//            ncurve = parent.graph.deleteAllCurves();
//            parent.graph.repaint();
            if(runTrans) {
                if(!eliminateTransient()) return false;
                if(curve2) {
                        for(i=1;i<=3;i++) 
                              x1[i]=x[i]+dx[i];
                              x1[0]=x[0];
                              t1=t;
                }
                runTrans=false;
                parent.status.setText("");
            }                                               
            err=0.;
                    
            System.arraycopy(x,0,xp,0,nVariables);

            if(ghostLength>0) {                       
                   for(i=0;i<nVariables;i++) {
                       xSave[i]=x[i];
                   }
                   tSave=t;
            
                   nplot=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);

                   for(i=0;i<nVariables;i++) {
                        x[i]=xSave[i];
//                        if(curve2) x1[i]=x[i]+dx[i];                        
                   }
                   t=tSave;
                   t1=t;                      
            }
//            if(curve2) x1[0]=x[0];
            runTrans=false;
            nplot=0;
            nplot1=0;
            System.arraycopy(x,0,xp,0,nVariables);
            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);
                if(curve2) {
                        try {
                              t1=parent.solver.timeStep(x1,t1,dtp);
                        } catch (ArithmeticException e) {
                              alertDialog alert = new alertDialog
                                    (parent,"Value has diverged. Try again! ");
                        return false;
                        }                                        
                        nplot1=process(x1,data2,nplot1);
                }        
            }
            parent.status.setText("");                          

            ncurve = parent.graph.addCurve(data1,nplot,Color.blue);
            ncurve1=ncurve;
            if(curve2) {         
                  ncurve = parent.graph.addCurve(data2,nplot,Color.red);
                  ncurve2=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;
            nplot1=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(curve2) {
                  try {
                        for(int i=0;i<delay;i++)                   
                              t1=parent.solver.timeStep(x1,t1,dt);
                  } catch (ArithmeticException e) {
                        alertDialog alert = new alertDialog(
                              parent,"Value has diverged.");
                        return false;
                  }                               
                  nplot1= process(x1,moredata1,nplot1);            
            }      
            if(nplot > 0) {
                  parent.graph.paintAll=false;     // Don't paint while updating data  
                  parent.graph.appendToCurve(moredata,1,ncurve1);
                  if(curve2)
                        parent.graph.appendToCurve(moredata1,1,ncurve2);
                  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.show(6);  
                   parent.variables.setText(4,"0.");
                   parent.variables.setLabelText(4,"  dX0");
                   parent.variables.setText(5,"0.");
                   parent.variables.setLabelText(5,"  dY0");       
                   parent.variables.setText(6,"0.");
                   parent.variables.setLabelText(6,"  dZ0");                                                          
      
                   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;
      }

//**********************************************************************
/**
* 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++]=x[plot_x];
              data[j]=x[plot_y];
              nplot++;                            
              return nplot;
      }
      
}      
