/*
汎用シミュレータ
System Simulator  coded by 
	製作者:
	石井 竜次 (ISHII Tatsuji) &
	喜多 敏博 (KITA Toshihiro; t-kita@eecs.kumamoto-u.ac.jp)
'97 Apr.

Copyright by Hiyama-Miyauchi lab. Kumamoto Univ. 1997
*/

import java.awt.*;     // Applet Window T... のロード
import java.applet.*;  // アプレット(WWW ブラウザで動く) クラスのロード
//import Acme.*;

/*
// TimeSeriesFrameクラス....新たなフレームを開いて、Peの時間変化を描くクラス
class TimeSeriesFrame extends Frame{         //フレームクラスの宣言
 
  //timeSeriesFrame()....タイトルをつけるコンストラクタ
  // ----------------------------------------------------------------------
  public TimeSeriesFrame(String t){
        setTitle(t);
      }

  // init()...フレームが開かれたときに呼び出されるメソッド
  // ----------------------------------------------------------------------
  public Graphics init(){
//        setBackground(Color.pink);
        setBackground(Color.black);
        show();                        //フレームに画像を貼り付ける
        return getGraphics();
      }

}
*/

// ######################################################################## 
class RungeKutta {
  int dim;      // 方程式の次元
  double[] xx, x1, x2, x3, k1, k2, k3, k4;

  RungeKutta(int dim){
    this.dim = dim;
    x1= new double[dim+1];
    x2= new double[dim+1];
    x3= new double[dim+1];
    k1= new double[dim+1];
    k2= new double[dim+1];
    k3= new double[dim+1];
    k4= new double[dim+1];
  }

  double[] dx(double x[], double time){ // ダミー...継承したクラスで定義する.
    return x;
  }

  public double[] toNextPoint(double x[], double time, double h){
    int j;
    double[] xx = new double[dim+1];

    // ルンゲ・クッタ法により微分方程式を求解
    k1= dx(x, time);                                               //k1
    for(j = 1; j <= dim; j++){
      x1[j] = x[j]+k1[j]*h/2.0;
    }
    k2= dx(x1, time);                                              //k2
    for(j = 1; j <= dim; j++){
      x2[j] = x[j]+k2[j]*h/2.0;
    }
    k3= dx(x2, time);                                              //k3
    for(j = 1; j <= dim; j++){
      x3[j] = x[j]+k3[j]*h;
    }
    k4= dx(x3, time);                                              //k4
    for(j =1; j <= dim; j++){
      xx[j] = x[j] + (k1[j]+2*k2[j]+2*k3[j]+k4[j])*h/6.0;
    }
    return xx;
  }	      
}


// ######################################################################## 
class PlotPlane extends Canvas{
  Graphics gcv;
  int width, height;
  double xmin, xmax, ymin, ymax;
  int gxmin, gxmax, gymin, gymax;
  int xmargin, ymargin;
  double lastx, lasty;
  boolean nolastxy = true;
  Color axisColor= Color.black;

  // ディフォルト値
  double[] xtic= {-100.0, 5.0, 100.0};
  double[] ytic= {-100.0, 5.0, 100.0};
  String xlabel= "x";
  String ylabel= "y";

  int withLine = 1;
  int withPoint= 2;
  int withFilledPoint= 3;
  int withDot=   4;

  // コンストラクタ
  PlotPlane( double xmin, double xmax, double ymin, double ymax,
	     int xmargin, int ymargin){
    this.setBackground(Color.gray); // キャンバスの背景は灰色.

    // コンストラクタの引数に従って フィールド変数をセットする
    this.width= width;
    this.height= height;
    this.xmin = xmin;
    this.xmax = xmax;
    this.ymin = ymin;
    this.ymax = ymax;
    this.xmargin = xmargin;
    this.ymargin = ymargin;
  }

  public synchronized void plot(double x, double y, int plottype, Color c,
				int size){
    switch(plottype){
    case 1:  // withLine
      if(nolastxy){
	lastx = x;  lasty = y;
      }
      gcv.setColor(c);
      gcv.drawLine(toGx(lastx), toGy(lasty), toGx(x), toGy(y));
      lastx = x;  lasty = y;
      nolastxy = false;
      break;
    case 2:  // withPoint
      gcv.setColor(c);
      gcv.drawOval(toGx(x)-size/2, toGy(y)-size/2, size, size);
      break;
    case 3:  // withFilledPoint
      gcv.setColor(c);
      gcv.fillOval(toGx(x)-size/2, toGy(y)-size/2, size, size);
      break;
    case 4:  // withDot
      break;
    default:
    }
  }

  void initialize(){
    gcv= this.getGraphics(); //Graphicsを取得 ....張り付けられてから取得すべし
    Dimension dim = this.size();              //キャンバスの大きさを所得

    gxmax= dim.width - xmargin;
    gxmin= xmargin;
    gymax= dim.height - ymargin;
    gymin= ymargin;
    drawAxis();
  }

  void setXrange(double xmin, double xmax){
    this.xmin= xmin;
    this.xmax= xmax;
  }

  void setYrange(double ymin, double ymax){
    this.ymin= ymin;
    this.ymax= ymax;
  }

  void resetLastXy(){
    nolastxy = true;
  }

  void clear(){
    initialize(); // 現在のキャンバスの大きさに gxmax などを合わせる
    Dimension dim = this.size();              //キャンバスの大きさを所得
    gcv.clearRect(0,0,dim.width,dim.height);
    drawAxis();
  }

  synchronized void drawAxis(){
    double xa, ya;
    
    gcv.setColor(axisColor);
    // x軸
    gcv.drawLine(gxmin,gymax,gxmax,gymax);
    for(xa=xtic[0]; xa<xtic[2]+1.0e-8; xa+= xtic[1]){
      if (toGx(xa)<= gxmax && toGx(xa)>= gxmin){
	if (Math.abs(xa)<1.0e-16){ xa= 0.0; }
	gcv.drawLine(toGx(xa), gymax-ymargin/5, toGx(xa), gymax+ymargin/5);
// Acme パッケージの使用がうまく行かない
//	gcv.drawString(Fmt.fmt(xa,0,4),toGx(xa),gymax+ymargin/2);
	gcv.drawString(xa+"",toGx(xa),gymax+ymargin/2);
      }
    }
    // y軸
    gcv.drawLine(gxmin,gymin,gxmin,gymax);
    for(ya=ytic[0]; ya<ytic[2]+1.0e-8; ya+= ytic[1]){
      if (toGy(ya)<= gymax && toGy(ya)>= gymin){
	if (Math.abs(ya)<1.0e-16){ ya= 0.0; }
	gcv.drawLine(gxmin-xmargin/5, toGy(ya), gxmin+xmargin/5, toGy(ya));
// Acme パッケージの使用がうまく行かない
//	gcv.drawString(Fmt.fmt(ya,0,4),gxmin-xmargin,toGy(ya));
	gcv.drawString(ya+"",gxmin-xmargin,toGy(ya));
      }
    }
    // 軸のラベル
    gcv.setColor(Color.black);
    gcv.drawString(xlabel,(gxmax+gxmin)/2,gymax+ymargin-2);
    gcv.drawString(ylabel ,gxmin-xmargin/2,gymin-ymargin/2);
  }

  int toGx(double x){
    return (int)((x-xmin)/(xmax-xmin)*(gxmax-gxmin) + gxmin);
  }

  int toGy(double y){
    return (int)(-(y-ymin)/(ymax-ymin)*(gymax-gymin) + gymax);
  }

  double toRealx(int gx){
    return ((double)(gx-gxmin)/(double)(gxmax-gxmin)*(xmax-xmin) + xmin);
  }

  double toRealy(int gy){
    return (-(double)(gy-gymin)/(double)(gymax-gymin)*(ymax-ymin) + ymax);
  }

/*
  public boolean mouseDown(Event e,int mx,int my){
    double x, y;
    double[] xa= new double[3];

    xa[1]= toRealx(mx);
    xa[2]= toRealy(my);
   // resetLastXy(); // これを行なうべきタイミングはかなり微妙
    app.setStateVariable(xa);
    return true;
  }
*/
}
