import ChaosDemos.*;
import java.awt.*;
import java.util.*;
import java.net.URL;
import graph.*;

/**                    
* Iterates and plots the chaos models described by coupled ODEs. <br> 
* Uses the "Java Graph Class Library" by Leigh Brookshaw
* @version 3 August, 1997
* @author Michael Cross
*/

public class Odes extends dynamicGraph {

/** functions */
      private static final int LORENZ=0;
      private static final int ROSSLER=1;
      private static final int DUFFING=2;
      private static final int PENDULUM=3;
      private static final int VANDERPOHL=4;      
      private static final int CHUA=5;
      
/** plot types */
      private static final int TIMESERIES=0; 
      private static final int FOURIER=1;
      private static final int POINCARE=2;
      private static final int RETURNMAP=3;
      private static final int MAXMAP=4;
      private static final int RECONSTRUCT=5;
      
      private static final double Pi2=2*Math.PI;      
      
      /* classes used */
      private startOdes outerparent;
      superGraph2D graph;
      private movie theMovie;
      ode solver;
      private OdesDiagnostics diagnostics;
      private powerSpectrum mySpectrum;
      OdesFunction odesFunction;      

/* animation thread */
      Thread aThread=null;      

      /* GUI classes */
      textControls variables,parameters;
      buttonControls buttons;
      choiceControls choices;      
      Panel topRightPanel;      
      Choice plotChoice;
      Choice functionChoice;
      Label status;                              

/* items for plotting points */
      private URL markerURL;
      
/** location of marker.txt */
      URL documentBase;
/** input marker size */
      double marker=1.;
/** marker size */      
      double markerScale;
/** type of marker (see marker.txt) */      
      int markerType;           
      

/** true after first mouse click  */      
      boolean clicked=false; 

/** true if time to be displayed */      
      boolean showTime=true; 
/** true if ghost to be showed */      
      boolean showGhost=false;       


      private boolean dummy;                

/** number of variables (icluding time) */
      int nVariables=4;

/** number of curves */      
      int ncurve=-1;      
/** plot type */      
      int plot=0;
/** function type */      
      int function=0;
      double ghostTime;
      int delay;
      double xmin=0,xmax=1,ymin=0,ymax=1;
      double xmouse=0,ymouse=0;      

/* parameters */
/** function parameter */
      double a[]={28.,2.667,10.,0.};        
                  

/** color of ghost */      
      Color transientColor;

/* default values depending on function and/or plot */
      private String[] axisLabel={"Time","  X ","  Y ","  Z "};      


/**
* @param target starting class
* @see startLor
*/ 
        Odes(startOdes target, URL in_documentBase) {
        documentBase=in_documentBase; 
        graph = new superGraph2D(this);
        graph.borderRight=35;                       
        try {
           markerURL = new URL(documentBase,"marker.txt");
           graph.setMarkers(new Markers(markerURL));
        } catch(Exception e) {
           System.out.println("Failed to create Marker URL!");
        }
        
        theMovie = new movie(this);
        solver = new ode((dynamicGraph) this, nVariables);
        this.outerparent = target; 

        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints constraints = new GridBagConstraints();
        
        setLayout(gridbag);
        constraints.fill=GridBagConstraints.BOTH;
        constraints.gridheight = 1;
        constraints.gridwidth=1;
        constraints.weighty = 1.0; 
        constraints.weightx=0.75;       
        constraints.insets = new Insets(0,0,0,10);
        
        Panel leftPanel = new Panel();
        leftPanel.setLayout(new BorderLayout());
        leftPanel.add("Center",graph);  
                
        Panel bottomLeftPanel = new Panel();
        bottomLeftPanel.setLayout( new GridLayout(2,1));
        bottomLeftPanel.add(theMovie);
         
        String[] buttonLabels={"   Reset    ","   Clear   ",
                    "    Start   ","    Stop   "};
        buttons = new buttonControls((dynamicGraph) this, 
                        buttonLabels,buttonLabels.length,true);
        buttons.b_init[0] = true;
        buttons.b_stopped[3] = false;
        buttons.b_started[1] = true;
        buttons.b_started[3] = true;
        buttons.setup();
        bottomLeftPanel.add(buttons);
                       
        leftPanel.add("South",bottomLeftPanel);
         
        constraints.insets = new Insets(0,0,10,0);
        gridbag.setConstraints(leftPanel, constraints);              
        add(leftPanel);    

        Panel rightPanel = new Panel();
        rightPanel.setLayout(new BorderLayout());
        constraints.weightx=0.25;
        constraints.insets = new Insets(0,0,15,10);
        gridbag.setConstraints(rightPanel, constraints);
        add(rightPanel);                
 
        topRightPanel = new Panel();
        topRightPanel.setLayout(gridbag);

        constraints.gridheight = 3;
        constraints.gridwidth=1;
        constraints.weightx=1.;
        constraints.weighty = 0.75;
        constraints.insets = new Insets(0,0,0,10);
        constraints.fill=GridBagConstraints.NONE;             

        String[] textboxes = {String.valueOf(a[0]),String.valueOf(a[1]),
                    String.valueOf(a[2]),String.valueOf(a[3]),"0.01",
                    "1","2"};
        String[] labels = {"  a","   b","   c","   d",
                             "  dt","x-ax","y-ax"};
        parameters = new 
              textControls((dynamicGraph)this,textboxes,labels,textboxes.length,5);        
        gridbag.setConstraints(parameters, constraints);
        topRightPanel.add(parameters);

        String[] textboxes1 = {"2","5","20","10","0.","0.","0."};                  
        String[] labels1 = {"     X0","     Y0","     Z0","  trans ","    dX0",
                             "    dY0","    dZ0"};
        variables = new 
              textControls((dynamicGraph) this,textboxes1,labels1,textboxes1.length,5);        
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        constraints.insets = new Insets(0,0,0,10);
        gridbag.setConstraints(variables, constraints);
        topRightPanel.add(variables);
        
        functionChoice = new Choice();
        functionChoice.addItem("Lorenz");
        functionChoice.addItem("Rossler");
        functionChoice.addItem("Duffing");
        functionChoice.addItem("Pendulum");
        functionChoice.addItem("VanDerPohl");
        functionChoice.addItem("Chua");
        constraints.gridwidth=1;
        constraints.weighty = 0.2;       
        constraints.gridheight=1;          
        constraints.gridwidth=GridBagConstraints.REMAINDER;        
        constraints.insets = new Insets(0,0,0,0);
        gridbag.setConstraints(functionChoice, constraints);  
        topRightPanel.add(functionChoice);        

        plotChoice = new Choice();
        plotChoice.addItem("Time Series");
        plotChoice.addItem("Spectrum");
        plotChoice.addItem("Poincare");
        plotChoice.addItem("Return Map");
        plotChoice.addItem("Max Map");
        plotChoice.addItem("Reconstruct");
         
        constraints.gridwidth=1;
        constraints.weighty = 0.2;       
        constraints.gridheight=1;          
        constraints.gridwidth=GridBagConstraints.REMAINDER;        
        constraints.insets = new Insets(0,0,0,0);
        gridbag.setConstraints(plotChoice, constraints);  
        topRightPanel.add(plotChoice);
        
        String[] choiceLabels={"Show Ghost:  ","Allow Sleep: ","Show Time:   "};
        choices = new choiceControls((dynamicGraph) this, 
                        choiceLabels);
        constraints.weighty = 0.25;
        constraints.gridheight = 1;
        gridbag.setConstraints(choices, constraints);
        topRightPanel.add(choices);     
        choices.setState(0,false);          
        theMovie.toSleep=true;
        choices.setState(1,true);      
//        showTime=true;             
        choices.setState(2,true);                     

        rightPanel.add("Center",topRightPanel);
        status=new Label("                    ");
        rightPanel.add("South",status);
        transientColor=Color.white;
        if(target.inputParameters) {
            function=target.function;
            functionChoice.select(function);
            plot=target.plot ;
            plotChoice.select(plot);
            setFunctionDefaults();
            setPlotDefaults();
            if(target.showGhost) {
               choices.setState(0,true);
               showGhost=true;
               transientColor=Color.lightGray;
            }    
            if(!target.showTime) {
               choices.setState(2,false);
               showTime=false;
            }    

            for(int i=0;i<target.nVariables;i++)
                  if(target.variableBoxes[i].length() != 0)
                        variables.setText(i,target.variableBoxes[i]); 
            for(int i=0;i<target.nParameters;i++)
                  if(target.parameterBoxes[i].length() != 0)
                        parameters.setText(i,target.parameterBoxes[i]);                                     
        } 
        else {
              setFunctionDefaults();
              setPlotDefaults();          
        }
        graph.clearAll=true;
        graph.setBackground(Color.white);

        buttons.enableGo();
        updateParameters();
        dummy=restart();
//        parameters.hide(3);    
      }

//**********************************************************************
/**
* Responds to textControls
* @see textControls
*/      
//**********************************************************************
      public void respondToText() {
            updateParameters();
            if(restart()) buttons.enableGo();
      }


//**********************************************************************
/**
* Responds to choiceControls
* @see choiceControls
*/      
//**********************************************************************      
      public void respondToChoices() {
            if(choices.getState(0)) 
                  transientColor = Color.lightGray;
            else
                  transientColor=graph.getBackground();
            if(choices.getState(1))
                  theMovie.toSleep=true;
            else
                  theMovie.toSleep=false;
            if(choices.getState(2))
                  showTime=true;
            else
                  showTime=false; 
                  status.setText("");                 
      }
                  
            
      
//**********************************************************************      
/**
* Respond to buttonControls
* @see      buttonControls
* @param    buttonIndex index of button pushed
*/          
//**********************************************************************            
      public void respondToButtons(int buttonIndex) {

            if(buttonIndex==0) {
                 updateParameters();              
                 if(restart()) buttons.enableGo();
            }
            else if(buttonIndex==1) {
//                graph.clearAll=false; //6/27/96
                if(aThread != null) {
                  movieStop();
                  if (restart());
                       movieStart();
                }
                else dummy=restart();
            }
            else if(buttonIndex==2) {
                buttons.disableGo();
                disableAll();
                status.setText("");
                clicked=false;
                graph.allowDrag=false; 
                movieStart();
            }
            else if(buttonIndex==3) {
                clicked=false;
                buttons.enableGo();
                movieStop();
                enableAll();
                if(diagnostics.allowDrag) graph.allowDrag=true;
                status.setText("Time= "+(float)diagnostics.t+
                     " Error= "+(float)diagnostics.err);                
            }
      }
      
//      public Insets insets() {
//            return new Insets(0,0,20,0);
//      }

//************************************************************************
/**
* Stop movie thread 
*/  
//************************************************************************

      public void movieStop() {
                if(aThread!=null) {
                    theMovie.stopIterate();
//                  aThread.stop();
                    aThread=null;
                }
      }
//************************************************************************
/**
* Start movie thread 
*/ 
//************************************************************************

      public void movieStart() {
//                if(aThread==null) {                  8/3/97
                    aThread = new Thread(theMovie);
                    aThread.start();
//                }              
      }

//************************************************************************
/**
* Event handler:
* Stops iteration on minimising and handles close window event<br>
* (May fail under Windows95)
*/
//************************************************************************      
        public boolean handleEvent(Event evt) {
            switch (evt.id) {
                case Event.WINDOW_DESTROY:
                    movieStop();
                    outerparent.hideWindow();
                    return super.handleEvent(evt);
                case Event.WINDOW_ICONIFY:
                    movieStop();
                    buttons.enableGo();
                    enableAll();
                    return super.handleEvent(evt);                
                case Event.ACTION_EVENT:
                    if(evt.target == functionChoice || evt.target == plotChoice)  {
                        function = functionChoice.getSelectedIndex();            
                        if(evt.target == functionChoice) {                         
                              setFunctionDefaults();
                        }
                        plot = plotChoice.getSelectedIndex();
                        setPlotDefaults();
                        updateParameters();
                        dummy=restart();
                    }
                return super.handleEvent(evt);                      
                default:                     
                    return super.handleEvent(evt);
            }
       }
       
//************************************************************************
/**
* Disables text input and choice controls
*/
//************************************************************************
      
      public void disableAll() {
          int i;
          for(i=0;i<variables.ncontrols();i++)
                 variables.disableText(i);
          for(i=0;i<parameters.ncontrols();i++) 
                 parameters.disableText(i);
          plotChoice.disable();
          functionChoice.disable();                         
      }

//*********************************************************************
/**
* Enables text input and choice contorls
*/ 
//*********************************************************************

      public void enableAll() {
          for(int i=0;i<variables.ncontrols();i++)
                variables.enableText(i);
          for(int i=0;i<parameters.ncontrols();i++)
                parameters.enableText(i);
          plotChoice.enable();
          functionChoice.enable();      
      }

//*********************************************************************
/**
* Returns RHS of differential equations for Lorenz model
* @param x[] vector of current value of dependent variables
* @param n number of dependent variables in array x[]
* @param t current value of independent variable
* @return n compoent vector giving derivatives of dependent variables
*/
//*********************************************************************       
      public double[] derivs(double[] x, double t, int n){
            return odesFunction.derivs(x,t);
     }

//********************************************************************
/**
* Updates parameters from the text controls 
*/ 
//********************************************************************      
      public void updateParameters() {
 
            clicked=false;

//            plot=plotChoice.getSelectedIndex();
//            function=functionChoice.getSelectedIndex();
            for(int i=0;i<4;i++)
                  a[i]=parameters.parseTextField(i,a[i]);
            diagnostics.updateParameters();
            odesFunction.setParameters(a);
      }      
                
//*********************************************************************
/**
* Resets plot by deleting all curves and restarting
*/
//*********************************************************************
      
      public boolean restart() {  
            graph.clearAll=true;
            status.setText("");
            ncurve = graph.deleteAllCurves();                                
            return diagnostics.restart();            
      }

//*********************************************************************
/**
* Iterates ODE and updates graph  
*/
//*********************************************************************
      
      public boolean iterate() {
            return diagnostics.iterate();
      }

//**********************************************************************
/**
*  Stop movie thread
*/ 
//**********************************************************************
      
      public void stop() {
            movieStop();
            enableAll();
      }                            

/**********************************************************************/
      public void updateSpeed(int in_delay) {
            delay=in_delay;
            if(diagnostics != null) diagnostics.setDelay(delay);
      }
            
//**********************************************************************
/**
* Sets default values of parameters depending on function number
*/
//**********************************************************************          
      private void setFunctionDefaults() {
           switch (function) {
                  case LORENZ:
                        odesFunction = new LorenzFunction(nVariables);
                        break;
                  case ROSSLER:
                        odesFunction = new RosslerFunction(nVariables);
                        break;                        
                  case DUFFING:
                        odesFunction = new DuffingFunction(nVariables);
                        break;                        
                  case PENDULUM:
                        odesFunction = new PendulumFunction(nVariables);
                        break;       
                  case VANDERPOHL:
                        odesFunction = new VanDerPohlFunction(nVariables);
                        break;         
                  case CHUA:
                        odesFunction = new ChuaFunction(nVariables);
                        break;                                                                        
                  default:
                        odesFunction = new LorenzFunction(nVariables);
                        break;
           }                                   
           for(int i=0;i<odesFunction.getNParameters();i++)   {
                 parameters.show(i);
                 parameters.setText(i,String.valueOf(odesFunction.aDefault[i]));
           }      
           for(int i=odesFunction.getNParameters();i<4;i++)
                 parameters.hide(i);                 
           parameters.setText(4,String.valueOf(odesFunction.dt));
           for(int i=0;i<nVariables-1;i++) 
                  variables.setText(i,String.valueOf(odesFunction.x0[i+1]));
           variables.setText(3,String.valueOf(odesFunction.trans));             
           variables.setText(6,String.valueOf(odesFunction.poincareSection));
           ghostTime=odesFunction.ghostTime;
           graph.setTitle(odesFunction.title);
           
      }
      
      private void setPlotDefaults() {             
             
             switch (plot) {
                  case TIMESERIES:             
                        diagnostics = new OdesTimeSeries(this);
                        break;
                  case FOURIER:
                        diagnostics = new OdesSpectrum(this);
                        break;        
                  case POINCARE:
                        diagnostics = new OdesPoincare(this);
                        break;  
                  case RETURNMAP:
                        diagnostics = new OdesReturnMap(this);
                        break;      
                  case MAXMAP:
                        diagnostics = new OdesMaxMap(this);
                        break;
                  case RECONSTRUCT:
                        diagnostics = new OdesReconstruct(this);
                        break;                                                                                                                                
                  default:
                        diagnostics = new OdesTimeSeries(this);
             }  
             diagnostics.setDefaults(); 
             diagnostics.setDelay(delay);
             if(odesFunction.wrapZ)
                  diagnostics.setWrap(3,odesFunction.wrapZValue);
             if(odesFunction.wrapY)
                  diagnostics.setWrap(2,odesFunction.wrapYValue); 
             if(odesFunction.wrapX)
                  diagnostics.setWrap(1,odesFunction.wrapXValue);                                                                           
       }                              
     

//**********************************************************************
/**
* Responds to mouse events
* @param xcoord x-coordinate of mouse click
* @param xcoordValid true if x-coordinate of mouse click within graph
* @param ycoord y-coordinate of mouse click
* @param ycoordValid true if y-coordinate of mouse click within graph
*/
//**********************************************************************         
      public void respondToMouse(double xcoord, boolean xcoordValid,
                 double ycoord, boolean ycoordValid){
             double exchange;
             boolean setAxesRange=false;
//             System.out.println("Mouse clicked = "+clicked);
             if(xcoordValid && ycoordValid)  {
                  if(aThread != null) {
                      if(!clicked) { 
                         clicked=true;                   
                         diagnostics.respondToClick(xcoord,ycoord);
                      } 
                      else clicked=false;                     
                  }
                  else if(diagnostics.allowDrag) {                     
                        if(!clicked) {
                             xmouse=xcoord;
                             ymouse=ycoord;                
                             clicked=true;
                        }
                        else {
                             clicked=false;
                             if(xmouse != xcoord) {
                                 xmax=xcoord;
                                 xmin=xmouse;
                                 if(xmin > xmax) {
                                        exchange=xmin;
                                        xmin=xmax;
                                        xmax=exchange;
                                 } 
                                 setAxesRange=true;   
                             }
                             if(ymouse != ycoord) {      
                                 ymax=ycoord;
                                 ymin=ymouse;
                                 if(ymin > ymax) {
                                       exchange=ymin;
                                       ymin=ymax;
                                       ymax=exchange;
                                  }                                                                                                
                                  setAxesRange=true;
                             }
//                             System.out.println(xmin+" "+xmax+" "+ymin+" "+ymax);
                             if(setAxesRange) 
                             diagnostics.respondToDrag(xmin,xmax,ymin,ymax);
                        }
                  }                        
            }
            else {
                  if(aThread==null) {
                       clicked=false;
                             updateParameters();              
                             if(restart()) buttons.enableGo();                       
                   }
             }                 
      }        

//********************************************************************** 
 
}                         
