import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Color;
import java.awt.Event;
import java.util.StringTokenizer;

/**
 複数の画像の表示を切り替える FlipFlop のクラス
 */
public class FlipFlop extends Applet implements Runnable {

     /**
       画像の数の最大値
      */
       static final int limitNumber=16;

     /**
       画像を囲む枠の幅
      */
       static final int border=4;

     /**
       画像の切り替えを行うスレッド
      */
       public Thread flipThread=null;

     /**
       イメージ・データ
      */
       public Image images[];

     /**
       イメージのファイル名
      */
       public String fileNames[];

     /**
       イメージの個数、サイズの最大値
      */ 
       protected int  maxNumber=0, maxWidth=0, maxHeight=0;

     /**
       イメージ切り替えの間隔（ミリ秒単位で指定）
      */ 
       public int intervalTime;

     /**
       回転の表示の状態( 0->1->2->3->0->1.... )
      */ 
       protected int showMode = 0;

     /**
       表示されるイメージの番号
      */ 
       protected int counter=0;

     /**
      画像の回転方向( true -- 横回転、false -- 縦回転 )
      */ 
       protected boolean rotateFlag = true;

     /**
       初期設定の関数。
      */
       public void init() {

             try {
                  intervalTime = getIntValue( "interval" );
             }   
             catch( NoValueException e ) {
                  intervalTime = 1000;
             }   
             if( intervalTime > 10000 ) intervalTime = 10000;
             if( intervalTime < 50   )  intervalTime = 50;

             String rotate = getParameter("rotate");
             if( rotate != null && rotate.equals("vertical") )
                 rotateFlag = false;
             else
                 rotateFlag = true;

             String fileString = getParameter("files");
             if( fileString == null ) 
                 fileString = "images/book.gif|images/keyboard.gif";
             fileNames = new String[limitNumber];
             maxNumber = getResolvedStrings( '|', fileString, fileNames );

             images = new Image[limitNumber];
             for( int i=0; i<maxNumber; i++ ) {

                 images[i] = getImage( getDocumentBase(), fileNames[i] );

             }

             maxWidth = size().width - border*2;
             maxHeight = size().height - border*2;
       }

    /**
      与えられた文字列を与えられた文字を区切りにサブストリングに分解
     */
       public int getResolvedStrings( char c, String s, String ss[] ) {

             int i=0;  // サブ・ストリングの数 - 1

             for( int j=0; j<s.length() && i<limitNumber; i++ ) {

                  int next = s.indexOf( c, j );

                  if( next == -1 ) {
                      ss[i] = new String( s.substring( j, s.length()));
                      break;
                  }
                  else {
                      ss[i] = new String( s.substring( j, next ));
                  }
                  j=next+1;
             }

             return (i+1);  // サブ・ストリングの数を返す
        }

    /**
      HTMLのデータを受け取り、Strig型からint型に変換する
     */
       public int getIntValue( String keyword ) throws NoValueException {
 
             String valueString = getParameter( keyword );
 
             if( valueString == null )
                throw  new NoValueException();  // 値が不明という例外
 
             Integer I = new Integer( valueString );
             return I.intValue();
       }

     /** 
      アプレットの表示を行う関数。
      */
       public void paint( Graphics g ) {

             g.setColor( Color.black );
             g.fill3DRect( 0, 0, 
                   maxWidth+border*2, maxHeight+border*2, false );

          // 縦方向の回転

             if( rotateFlag == false ) {

                   g.setColor( Color.yellow );
                   g.fill3DRect( border-2, (maxHeight+border-4)/2,
                                 maxWidth+4, 4, false );

                   if( showMode == 1 ) {
                         g.setColor( Color.lightGray );
                         g.fill3DRect( border, (border+maxHeight/2-6)/2,
                                       maxWidth, maxHeight/2+7, true );
                   }
                   else if( showMode == 2 ) {
                         g.setColor( Color.lightGray );
                         g.fill3DRect( border, (border+maxHeight-6)/2,
                                       maxWidth, 7, true );
                   }
                   else if( showMode == 3 ) {
                         g.setColor( Color.gray );
                         g.fill3DRect( border, (border+maxHeight/2-6)/2,
                                       maxWidth, maxHeight/2+7, true );
                   }
                   else {
                       if( 0 <= counter && counter < maxNumber ) {
                            g.clearRect( border, border, maxWidth, maxHeight );
                            g.drawImage( images[counter], border, border , this );
                       }
                   }
              }

           // 横方向の回転

              else {
                   g.setColor( Color.yellow );
                   g.fill3DRect( (maxWidth+border-4)/2, border-2,
                                  4, maxHeight+4, false );

                   if( showMode == 1 ) {
                         g.setColor( Color.lightGray );
                         g.fill3DRect( (border+maxWidth/2-6)/2, border,
                                        maxWidth/2+7, maxHeight, true );
                   }
                   else if( showMode == 2 ) {
                         g.setColor( Color.lightGray );
                         g.fill3DRect( (border+maxWidth-6)/2, border,
                                        7, maxHeight, true );
                   }
                   else if( showMode == 3 ) {
                         g.setColor( Color.gray );
                         g.fill3DRect( (border+maxWidth/2-6)/2, border,
                                        maxWidth/2+7, maxHeight, true );
                   }
                   else {
                       if( 0 <= counter && counter < maxNumber ) {
                            g.clearRect( border, border, maxWidth, maxHeight );
                            g.drawImage( images[counter], border, border , this );
                       }
                   }
              }

       }

     /**
      アプレットが画面に現れた時に呼び出される。
      */
       public void start() {
             if( flipThread == null ) {
                   flipThread = new Thread(this);
                   flipThread.start();
             }
       }

     /**
      アプレットが画面から消えた時に呼び出される。
      */
       public void stop() {
             if( flipThread != null ) {
                   flipThread.stop();
                   flipThread = null;
             }
       }

     /**
      アプレットが続行する作業
      */
       public void run() {

             while( flipThread.isAlive() ) {

                  repaint();

                // 回転の途中の表示

                  if( showMode != 0 ) {
                      try {
                          Thread.sleep( 400 );
                      }
                      catch (InterruptedException e){}
                      showMode++;
                      showMode%=4;
                  }

                // イメージの表示

                  else {
                      try {
                          Thread.sleep( intervalTime );
                      }
                      catch (InterruptedException e){}
                      counter++; counter%=maxNumber;
                      showMode = 1;
                  }
             }
       }

     /**
      マウスのボタンが押された時呼び出される処理。
      */
       public boolean mouseDown( Event evt, int x, int y ) {
 
             if( flipThread == null ) {
                   flipThread = new Thread(this);  // スレッド生成
                   flipThread.start();             // スレッド起動
             }       
             else {
                   flipThread.stop();              // スレッド停止
                   flipThread = null;              // スレッド消去
             }       
 
        return true;
       }
}

