//File: SoundWin.java --- @CopyLeft by tsaiwn@csie.nctu.edu.tw
///Test Open a URL window, playing Song in Applet and Application
/// Also show you how Applet works through tracing each function
/// More Files need in addition to the SoundWin.java :
///    howcome.au, laugh.au, welcome.wav  and gigi.jpg , gigib.jpg
/// All files for this example can be found here:
//    http://www.csie.nctu.edu.tw/~tsaiwn/course/java/examples/soundwin/
///
//To compile this program:
//  javac -encoding Big5 -target 1.1 SoundWin.java
//
//You can try this URL:
//    http://www.csie.nctu.edu.tw/~tsaiwn/course/java/
//                       examples/soundwin/testsw.html
//
//This program demostrate:
//  (1) How to open another URL. Either from Applet or from Application.
//  (2) How to play Sound Files. Either from Applet or from Application)
//  (3) Plus, We also include an Image Button in this demo.
//      And, use a thread to act as a timer to perform the hint task.
//      It will show a message that rolling to left on the panel.
//      While another message is shown on a flash manner.
//       (會有一個跑馬燈 以及一列閃爍的提示訊息)
//  (4) 若當作 Application 來 Run, 會看到一大堆跑過各主要程式的訊息,
//      包括 main, init, start, repaint, update, paint 等
//  (5) 若當 Applet (由 Browser 中看), 則該些訊息在 Java Console(主控台),
//      可在 Browser 的 工具 ==> Java 主控台 把 Java 的 Consol 叫出來觀看.
//     (請check 你的 Browser 確認你是用 Sun 的 JVM 還是用 Microsoft VM ?)
//  (6) 為免太多訊息, 在第 58 次叫 paint()之前若是由 Hinter 引起的訊息則
//      不顯示; 第 59 次開始自動顯示, 但你可以按 STOP 按鈕使其不顯示或
//      切回要顯示 (toggle). 不過非 Hinter (負責跑馬燈和閃爍訊息) 所引起
//      的訊息時則一定會顯示.
//
// This Java program can be run both as Applet and as Application.
// To run as an Application: java SoundWin
//////////
/*****  When used as an Applet, embed it in an HTML file as following:
 <br>
 <applet code="SoundWin.class" WIDTH=380 HEIGHT=288>
 </applet>
 <! Note that More Files needed to be put in the same directory:
    howcome.au, laugh.au, welcome.wav  and gigi.jpg , gigib.jpg
   ---------------------------------------------------------->
 </body>
 </html>
************************/

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.text.*;
import javax.swing.ImageIcon;       // for ImageButton
import javax.swing.JButton;

public class SoundWin extends Applet implements ActionListener {
      static final private int WIDTH=358, HEIGHT=288;
      final private static int SHOW_HINT_INTERVAL = 588;  // milli seconds
      static final String WELCOME_NAME = "welcome.wav";
      static final String SONG_NAME = "howcome.au";
      static final String SONG2_NAME = "howcome.wav";
      static final String SONG_BUTTON_CAPTION = "點唱 情字這條路";
      static final String LAUGH_AUDIO_NAME = "laugh.au";
      static final String LAUGH_BUTTON_CAPTION = "HaHa大笑";
      static final String GIGI_PIC_FILENAME = "gigi.jpg";
      static final String GIGI_PIC_FILENAME2 = "gigib.jpg";
      static final String WEB_BUTTON_CAPTION = "連到奇摩";
      static final String TASK_BUTTON_CAPTION = "Manager";
      static final String WEB_LOCATION = "http://tw.yahoo.com";
      String SONG_LOCATION = "http://www.csie.nctu.edu.tw/~tsaiwn/audir/";
      String flashLocation =     // may be changed to other at RUN Time
         "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
            "movie%ad%ec%a9l%c0%c9/4-%af%ab%c0J%abL%abQ/4.swf";
   //Some funny flash links in my directory: NCTU_CSIE_WEB/~tsaiwn/flash/
   //We will use a Random number to choose one from these URLs (.swf)
      String swfAry[ ] = {  // array for .swf flash file
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
              "movie%ad%ec%a9l%c0%c9/4-%af%ab%c0J%abL%abQ/4.swf",
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
              "movie%ad%ec%a9l%c0%c9/2-%ad%b8%b5%be%a4%a7%b9%da/2.swf",
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/02-GGL-fun/GGL_02.swf",
          "http://www.csie.nctu.edu.tw/~tsaiwn/mouse/catch_cursor.htm",
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
              "movie%ad%ec%a9l%c0%c9/3-%b1%a1%b8%d6/3.swf",
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
              "effect%ad%ec%a9l%c0%c9/36-%b7%cf%a4%f5%a4@/36.swf",
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
              "effect%ad%ec%a9l%c0%c9/25-3Dengine/25.swf",
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
              "effect%ad%ec%a9l%c0%c9/61-%b7%c6%b9%ab%afS%ae%c4%a4Q/61.swf",
          "http://www.csie.nctu.edu.tw/~tsaiwn/flash/",
          "http://www.csie.nctu.edu.tw/~tsaiwn/mouse/catch_cursor.htm",
          "http://www.csie.nctu.edu.tw/~tsaiwn/course/introcs/ghost/" };

      static int visitCount = 0;  // control which swf in swfAry[] to show
      static final Font myFont = new Font("標楷體", Font.BOLD, 18);

      Toolkit toolkit;
      Frame f;
      Applet ap = null;
      TextField tSouth = null;    // so the Applet can see this
      AudioClip song; 
      Image giGiImage, giGiImage2;
      ImageIcon giGiIcon;
      Button bWeb = new Button( WEB_BUTTON_CAPTION );
      Button bSong = new Button( SONG_BUTTON_CAPTION);
      Button bLaugh = new Button( LAUGH_BUTTON_CAPTION ); // replaced by bGiGi
      JButton bGiGi = new JButton( LAUGH_BUTTON_CAPTION );
  //// bGiGi will use ImageButton through ImageIcon giGiIcon
      Button bStop = new Button("STOP");
      Button bFlash = new Button("FLASH");
      Button bTaskMgr = new Button( TASK_BUTTON_CAPTION);
    ///
  ///// we need a thread act as timer to show hint msg periodically
      protected Hinter hinter;  // a thread to flash the hint message
      String status = "---";

   static void printMsg(String s) {
       try{
         System.err.println(s);  
         System.err.flush( );  // need flush?
       } catch (Exception e) {;}  // ignore all errors
   } // printMsg 方便使用而已 

      static private boolean isApplication = false;  // Application or Applet

   public static void main( String s[ ]) {   // for Application only
      printMsg("Run the main( ) program..." );
      Frame f = new Frame("Window 2004");
      isApplication = true;   // to indicate that this is an Application
               // an Applet will NOT run this main( ) function
      SoundWin a = new SoundWin( );    // new the Applet (simulate Browser)
      a.ap = a;   // a.ap points to the Applet it self
      a.f = f;  // a.f points to the Frame f created in Application main()
      TextField t2 = new TextField("This is an Application." +
                                   " Press Enter Here will Quit.");
      a.tSouth = t2;    // so the Applet can see this t2 as tSouth
             // Applet won't run main( ); tSouth will equales null
      f.add(a, BorderLayout.CENTER);  // put the Applet in the Frame f
      TextArea t = new TextArea("這\n是\n獨\n立\n應\n用\n程\n式",2,3);
      t.setEditable(false); t.setBackground(Color.green);
      t.setLocale(java.util.Locale.CHINESE);
      t.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
      t.setFont( new Font("標楷體", Font.BOLD, 24) );
      f.add(t, BorderLayout.EAST);   // a text board on the Right Side
      t2.setFont( new Font("Ludica Console", Font.BOLD, 24) );
      t2.setEditable(false); t.setBackground(Color.blue);
      t2.setForeground(Color.red);  // 紅色字体
      f.add(t2, BorderLayout.SOUTH); // t 和 t2 只是秀出這是 Application
      a.init( );   // simulate Applet behavior
      a.start( );  // simulate Applet behavior
      a.sayHello(WELCOME_NAME);    // Application say Hello on Console
     /// resizing the window for fun
      int szW[ ] = {  988,  58,  88, 888, 98, 108, 128, 149, 58, 158 };
      int szH[ ] = {   58, 888, 666, 888, 18, 28,  38,   58, 16,  68 };
      for(int i=0; i< szW.length; ++i) {  // resize the window for fun
         try {
            try { Thread.sleep(368); } catch (InterruptedException e) {;}
            f.setSize(WIDTH+ szW[i], HEIGHT+ szH[i]);
            f.setVisible(true); f.validate( );
         } catch(Exception e2) {;}
      } // for
      printMsg("=== .. main( ) finish. ===" );
      printMsg("   ====================" );
      printMsg("      ==============" );
      printMsg("         ========\n" );
   } // main( ) ends here

   public SoundWin( ) {  // Constructor, remember SoundWin extends Applet
      if(ap==null) ap = this;   // Let ap points to myself first
   }

   private void decorateFrame( ) {  // some funny Layout
      Label b2a = new Label("假"); Label b2b = new Label("做");
      Label b2c = new Label("真"); Label b2d = new Label("時");
      b2a.setFont(new Font("標楷體", Font.BOLD, 18));
      b2b.setFont(myFont); b2c.setFont(myFont); b2d.setFont(myFont);
      Label bx = new Label("　"), by = new Label("　"), bz = new Label("　");
      bx.setFont(myFont); by.setFont(myFont); bz.setFont(myFont);
      Panel pRight = new Panel(new GridLayout(5,2, 1,1));
      pRight.setLocale(java.util.Locale.CHINESE);
      pRight.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
      Label ya = new Label("真"); Label yb = new Label("亦");
      Label yc = new Label("假");
      ya.setFont(myFont); yb.setFont(myFont); yc.setFont(myFont);

      pRight.add(b2a); pRight.add(bx); pRight.add(b2b); pRight.add(by);
      pRight.add(b2c); pRight.add(ya);
      pRight.add(b2d); pRight.add(yb);
      pRight.add(bz); pRight.add(yc);
      ap.add(pRight, BorderLayout.EAST);
     //
      Panel pSouth = new Panel();   // default LayoutManager is FlowLayout
      pSouth.add(bSong); pSouth.add(bWeb);
      pSouth.add(bFlash);  pSouth.add(bTaskMgr);
      ap.add(pSouth,"South");
     //
      Panel pLeft = new Panel(new GridLayout(2,1,5,28)); // 2 row, 1 column
      pLeft.add(bGiGi); pLeft.add(bStop);
      ap.add(pLeft, "West");    // 裝了兩個 Button 的 Panel 放左邊
   } // decorateFrame

   public void init( ) {
      toolkit = Toolkit.getDefaultToolkit();    // for later use
      printMsg("Run the init( ) in Applet." );
      bGiGi = new JButton( LAUGH_BUTTON_CAPTION );
      try {       // Application 中讀取 Image 方法與 Applet 中不同
         if(isApplication) {  // use my function newImage to load Image file
            giGiImage = newImageBoth(GIGI_PIC_FILENAME); 
         } else
            giGiImage = newImageBoth(GIGI_PIC_FILENAME); 
            //giGiImage = getImage(new URL( getCodeBase()+ GIGI_PIC_FILENAME));
         giGiIcon = new ImageIcon(giGiImage); 
         bGiGi = new JButton(giGiIcon);    // wrap GiGI's picture
         if(isApplication) {
            giGiImage2 = newImageBoth(GIGI_PIC_FILENAME2);
         } else
            giGiImage2 = newImageBoth(GIGI_PIC_FILENAME2);
            //giGiImage2 = getImage(new URL( getCodeBase()+ GIGI_PIC_FILENAME2));
          // giGiImage2 will be used to flip pic when mouse enters bGiGi
          // see the MouseEvent handler (class Amigo) below
      } catch (Exception e) { ; }
      bGiGi.setCursor( new Cursor(Cursor.HAND_CURSOR) );
      bStop.setCursor( new Cursor(Cursor.HAND_CURSOR) );
      //ap.setLayout(new BorderLayout( ) );
      setLayout(new BorderLayout( ) );  // change the Applet's LayoutManager
      decorateFrame( );  // decorate the window with some Chinese character
     ///
      bStop.setBackground(Color.red);
      bStop.setFont( new Font("Ludica Console", Font.BOLD, 20) );
      bSong.setBackground(Color.pink);
      bWeb.setBackground(Color.green);
     //// Register necessary Event Listener to handle events
      bWeb.addActionListener(this);  // register with ActionListener
      bFlash.addActionListener(this);
      bTaskMgr.addActionListener(this);
      bSong.addActionListener(this);
      bGiGi.addActionListener(this);
      bGiGi.addMouseListener(new Amigo( ));
      bStop.addMouseListener(new Amigo( ) );
      bStop.addActionListener(this); 
      if(tSouth != null) tSouth.addActionListener(this);
      ap.setSize(WIDTH, HEIGHT);
      ap.setVisible(true);
      hinter = new Hinter(SHOW_HINT_INTERVAL); //a Thread acts as a timer
      hinter.start( );  // start the Timer thread to toggle hint message
      status = "...Press the Button to test ..";
      //repaint( );   // not necessary , 我們的 Hinter 內會叫 repaint
   } // init()

   public void start( ) {
      printMsg("Run the start( ) in Applet." );
      super.start( );   // 別忘了上層的 start( ) 
   }

   public void stop( ) {  // 離開 Applet 網頁時執行 
      printMsg(" - - -stop( ) called === " );
      super.stop( );
   }

   public void validate( ) {  // don NOT forget super class's validate
      printMsg(" !  validate( ) called === " );
      super.validate( );
   }

   protected int nUpdate = 0;   // number of visit to the update( );
   public void update(Graphics g) {
      ++nUpdate;
      ////////////////
      try{ 
         if( ! hintMode) {
            printMsg(" update( ) called ::: "+ nUpdate +
               ",  Repaint :" + nRepaint +
               ",  Update: "+nUpdate + ",  Paint :" + nPaint);
         } else {  // special processing for hintMode
            if( nPaint > 58) {   // hide paint message if count <= 58
              if(showHintPaint)
                 printMsg(" update( ) called ::: "+ nUpdate +
                    ",  Repaint :" + nRepaint +
                    ",  Update: "+nUpdate + ",  Paint :" + nPaint +
                    " --- by Hinter. ");
            } // if nPaint>58
         } // if 
      }catch(Exception ex){;}  // forget this Error
      ///                 /// 上層的 update 會先把 Applet 清除 (clear)
      super.update(g);    // 別忘了上層的 update()  , 它會叫用 paint( )
       /// 可故意把這 super.update(g) 暫時 註解掉測試看看
   }

   protected int nRepaint = 0;   // number of visit to the repaint( );
   public void repaint( ) {
      ++nRepaint;
      /// /// /// /// ///  keep quiet before nPaint == 59
      if( ! hintMode) {
          printMsg(" repaint( ) called - -- --- ----- "+ nRepaint +
             ",  Update: "+nUpdate + ",  Paint :" + nPaint);
      } else {  // special processing for hintMode
         if( nPaint > 58) {   // hide paint message if count <= 58
           if(showHintPaint)
              printMsg(" repaint( ) called - -- --- ----- "+ nRepaint +
                ",  Update: "+nUpdate + ",  Paint :" + nPaint +
                " by Hinter. ");
         } // if nPaint>58
      } // if 
     ///可故意拿掉下列再測試看看 
      super.repaint();   // 別忘了上層的 repaint()  , 它會叫 update( )
   }

   protected int nPaint = 0;   // number of visit to the paint( );
                // we should NOT call paint directly

   public void paint(Graphics g) {
      ++nPaint;
      if( ! hintMode) { printMsg("  paint( ) is called: "+ nPaint +
                ",  Repaint :" + nRepaint +
                ",  Update: "+nUpdate + ",  Paint :" + nPaint);
      } else {  // special processing for hintMode
         if( nPaint > 58) {   // hide paint message if count <= 58
           if(showHintPaint)
              printMsg("  paint( ) is called : "+ nPaint +
               " by Hinter. Press STOP to toggle Hinter paint message.");
         } // if nPaint>58
      } // if 
      g.setColor(Color.red);
      g.setFont( new Font("標楷體", Font.BOLD, 14) );
      g.drawString( status + "      ", 88, 128);
      if(hintMode) { // is in hintMode
         switch( (int)hinter.showFlag%8/2 ) {
            case 0:
               g.drawString( "/  ..按 FLASH 每次不同喔 !", 108, 228);
               bFlash.setBackground(Color.orange);
               break;
            case 1:
               g.drawString( "-                     !! ", 108, 228);
               bFlash.setBackground(Color.pink); break;
            case 2:
               g.drawString( "\\  ..按 FLASH 每次不同喔 !", 108, 228);
               bFlash.setBackground(Color.magenta); break;
            case 3:
               g.drawString( "|                    !! ", 108, 228);
               bFlash.setBackground(Color.white); break;
         } // switch
         if( hinter.showFlag <= 18 )   // 開始時都秀出 
               g.drawString( "   ..按 FLASH 每次不同喔 !", 108, 228);
      }
      rollMessage(g);   // 太長了切出去另一個 function 
   }

   private void rollMessage(Graphics g) {
       int showLen = 18;      // show characters windwow size
       int len = msgLength;
       int p = (int) (hinter.showFlag % msgLength);
       int pEnd = p + showLen -1;
       String s;
       if(pEnd < msgLength ){
         s = msg.substring(p, pEnd);   // 這種不斷改變 s 字串的方法不好 
       }else{                   // 可改用 StringBuffer 比較不浪費資源 
         int pLen  = msgLength - p;
         s = msg.substring(p, msgLength-1) + msg.substring(0, showLen-pLen);
       }
       g.drawString( s, 108, 58);
   }

   public void actionPerformed (ActionEvent evt) {
      Object who = evt.getSource( );    // who fires the ActionEvent ?
      printMsg("ActionEvent: " + who);
      if(who == bWeb) {                 // bWeb Button was clicked
          bWeb.setBackground(Color.red); // Let user know he press me
          try { openWebWindow( ); } catch(Exception e) {;}
      }
      else if(who == bSong) playSong( ); //play song: 情字這條路
      else if(who == bGiGi) makeLaugh( ); //play laugh.au
      else if(who == bFlash) { openFlashURL( ); }
      else if(who == bTaskMgr) { runTaskManager( ); }
      else if(who == tSouth)  System.exit(0);   // special in Application
      else if(who == bStop) {  // try to Stop the Audio, including Laughing
          if(song != null) song.stop( );  // stop playing the song
          status = "...Press the Button to test .."; 
          //repaint( );
          /// toggle the showHintPaint mode every time you press the STOP
          if(showHintPaint) showHintPaint=false;  else showHintPaint=true;
          //System.exit(0);  // enable this line if you want to Quit fot this
      } // else if
   } // actionPerformed()

   void runTaskManager( ) {    // Application only
       printMsg("Try to run the Task Manager (taskmgr ) " );
       try {
          if(isApplication) {  // utilize the Runtime exec function
             try {              // 注意格式, 因字串中含有 " 雙引號 "
                Runtime.getRuntime().exec(
                  "cmd /c \"taskmgr"  + "\" " );
             } catch (Exception e95){  }  // Win95/98 ?
          } //
       } catch (Exception e) {; }
   } // run taskmgr

   void openWebWindow( ) {    // note that different when in Application
       printMsg("Try to open " + WEB_LOCATION);
       try {
          if(isApplication){  // utilize the Runtime exec function
             try {              // 注意格式, 因字串中含有 " 雙引號 "
                Runtime.getRuntime().exec(
                  "cmd /c \"start " + WEB_LOCATION +"\" " );
             } catch (Exception e95){  // try Win 95/98
                Runtime.getRuntime().exec(
                  "start " + WEB_LOCATION );   //Win95/98中 start 是內建
             }
          } else { // is Applet, we are in Browser, use showDocument( )
             URL url = new URL(WEB_LOCATION); 
             getAppletContext().showDocument(url, "_blank"); 
          }   // see AppletContext
                         // _blank means in New Window
       } catch (Exception e) {; }
   }

   void openFlashURL( ) {    // URL address String in String swfAry[ ]
       int n = (int)(Math.random( ) * 100);     // 0..99
       n = n % swfAry.length;
       if( visitCount++ == 0 ) n = 0;   // first visit, show swfAry[0]
       if( visitCount == 2 ) n = 2;  // GGL, second visit, show swfAry[2]
       if( visitCount == 3 ) n = 3;  // [3] = play_hand_mouse on 3rd visit
       if( n == 0 &&  visitCount >  3 && visitCount <  8 )
           n = visitCount % swfAry.length; // 第8次前不再秀swfAry[0]神鵰俠侶
       try {
          flashLocation = swfAry[n];
       } catch (Exception e) { n=2; }  // 2 is GGL
       printMsg("Try to open " + flashLocation);
       try {
          if(isApplication){
             try {  // XP, NT
                Runtime.getRuntime().exec(
                   "cmd /c \"start " + flashLocation + "\" ");
             } catch (Exception e98) {   // try Win95/Win98
                Runtime.getRuntime().exec(
                   "start " + flashLocation );
             }
          } else {
             URL url = new URL( flashLocation ); // a file in ~tsaiwn/...
             getAppletContext().showDocument(url, "_blank"); 
          } // if
       } catch (Exception e) {; }
   }

   void openSong( ) {   // use a Browser to open a Song URL
       printMsg("Try to open " +SONG_NAME + " in " + SONG_LOCATION);
       try {
          URL url = new URL( (SONG_LOCATION + SONG_NAME).trim() );
          if(isApplication){
             try {  // XP, NT
                Runtime.getRuntime().exec(
                   "cmd /c \"start " + url.toString( ) + "\" ");
             } catch (Exception e98) {   // try Win95/Win98
                Runtime.getRuntime().exec(
                   "start " + url.toString( ) );
             }
          } else { // Applet
              getAppletContext().showDocument(url, "_blank"); 
          } // if
       } catch (Exception e) {; }
   }

   void playSong( ) {    // play the AudioClip from a file or a URL
       printMsg("Playing.." + SONG_NAME);
       try {
          if(isApplication) {  // after JDK 1.2
             song = Applet.newAudioClip(new URL(newCodeBase( )+SONG_NAME)); 
          }else{
             song = getAudioClip(getCodeBase( ), SONG_NAME); 
          } // if
        } catch ( Exception e ) {
           try{  // try-2, try tsaiwn URL
              try{ showStatus( ".. " + SONG_LOCATION + SONG_NAME);
              } catch ( Exception es ) {;}
              song = getAudioClip( new URL(SONG_LOCATION + SONG_NAME) );
              status = ".. " + SONG_LOCATION + SONG_NAME + "     ";
           } catch (Exception e2){
           //System.err.println("Fail : "+e);
              try{  // try-3
                 song = getAudioClip(
                     new URL("./" + SONG2_NAME ) );
                 status = " ..   ./" + SONG2_NAME + "== = =   ";
              } catch (Exception e3){ 
                 try {  // try-4
                     song = Applet.newAudioClip(
                            new URL(newCodeBase( ) + SONG2_NAME ) );
                 } catch ( Exception e4) {
                    if(song==null) { openSong(); return;  }  // try my best
                 }  //  try-4
              } // try-3
           } // try-2
       } ; //
        // Play the sound if we got the AudioClip
       try {
          if(song != null) {
             song.play(); 
             status = "...Playing " + SONG_NAME;
          } // if
          try { showStatus(" " + status ); 
          } catch ( Exception es ) { ; } // on window's status line  狀態列
          repaint( );  // draw message in the Applet Panel
       } catch ( Exception e ) { return; }
   } // playSong()

   void makeLaugh( ) {
       try {
          try{ showStatus(" :-)  Laughing ..." ); } catch ( Exception es ) {;}
          playFile(LAUGH_AUDIO_NAME );
       } catch ( Exception e ) {;}
   }
   void sayHello(String filename) {
       playFile(filename);
   }
/*********
   void playFile(String filename) {
       try {
          if(isApplication) {
             URL base = newCodeBase();
             song = Applet.newAudioClip(new URL(base+filename)); 
          } else
             song = getAudioClip(getCodeBase(), filename);  // Applet's
          song.play( );
          status = "...Playing .." + filename; 
          try{ showStatus(status); } catch ( Exception es ) {;}
          repaint( );   // show the status message on the Applet
       } catch (Exception e) {; } // ignore any error
   }
*************/
////////////
///
   public AudioClip newAudioBoth(String filename) {   /// NOT static
       AudioClip audio = null;
       try {   // 2004/06/08
          Toolkit tkt = Toolkit.getDefaultToolkit( );
          Class me = getClass( );   // get The class is running
          URL url = me.getResource(filename);
          audio = Applet.newAudioClip( url );
       } catch (Exception e) { ; }
       return audio;
   } // newAudioBoth(filename)
 /// newAudio(url, filename)

   public AudioClip playFile(String filename) {
       AudioClip song = null;
       try {
           //song = getAudioClip(getCodeBase(), filename);  // Applet's
           song = newAudioBoth(filename);  // both OK
           song.play( );
       } catch (Exception e) { return song; } // Let the caller know
       try { Thread.sleep(358); } catch (Exception e) {;}
       return song;
   }
/////////////////////////

   public URL newCodeBase( ) {    // for Application to get CWD
       URL codeBase = null;        // assume we can not get it
       try{
          codeBase = new URL("file:" + System.getProperty("user.dir") + "/");
       } catch ( Exception e ) {
          codeBase = getCodeBase( );   // where the Applet in
          // maybe it is an Applet, use getCodeBase() or getDocumentBase()
       }
       return codeBase;
   }

 /// get Image from a local file --- for Application (not Applet)
   public Image newImage(String filename) {
       Image img = null;
       try{ Toolkit tkt = Toolkit.getDefaultToolkit( );
            img = tkt.getImage(filename);  //for application only
       } catch ( Exception e ) {
           try { img = getImage(getCodeBase( ), filename); //for Applet
           } catch (Exception e2) {;} // ignore any error now
       }
       return img;
   } // newImage(filename)
   public Image getMyImage(String filename) {
       return newImage(filename);
   } // getMyImage(filename)
///
   public  Image  newImageBoth(String filename) {   /// NOT static
       Image image = null;
       try {   // 2011/04/02  good in Jar file
          Toolkit tkt = Toolkit.getDefaultToolkit( );
          Class me = getClass( );   // get The class is running
          URL url = me.getResource(filename);
          image = tkt.getImage(url); 
       } catch (Exception e) { ; }
       return image;
   } // newImageBoth(String 
//////

   protected boolean hintMode = false;   // control toggle display hint
                     //////// paint( ) will check this variable

   protected boolean showHintPaint = true;   // toggle paint message

 // an inner class to act as a Timer to show hint message
// The uint of SHOW_HINT_INTERVAL is in milli seconds
 class Hinter extends Thread {
    protected volatile boolean shouldDie = false;  // instead of stop( );
    protected long showFlag = 0;
    protected int showInterval;    // 記住傳來的 interval for hint message

    public Hinter(int interval) { showInterval = interval;} //Constructor
    //when new Hinter, please pass the interval to me as the argument.

   // the main part of a thread is the run( ) method
    public void run( ) {  // Thread should implements the run( ) method
       while( ! shouldDie) { // Loop forever till the Master wants me to die
          try { showFlag++; } catch (Exception e){;}
          hintMode = true;
          repaint( );    // call it every showInterval milli-seconds
          hintMode = false; // so that won't affect other's call to paint
          try {sleep(showInterval); } catch(InterruptedException e){;}
       } // while
    } // run
   ///注意我們叫用 repaint( ); repaint() 會去叫我們的 paint(Graphics);
   /// 但是不是只有我們會叫到 paint( ); 因此要讓 paint( ) 知道是誰叫的 
   //  所以用一個 hintMode 這變數讓 paint( ) 檢查 
 } // MyTimer

 // another inner class Amigo to handle Mouse events
 //這個 Amigo 有能力處理部份 Mouse event
 class Amigo extends MouseAdapter {
    public void mouseEntered(MouseEvent e) {
        Object who = e.getSource( );   /* 查哪零件觸發 Mouse event? */
        printMsg("MouseEvent: Entered " + who);
      ///
        if(who == bGiGi) {
          status = "... 按我就會大笑喔:-)";
          giGiIcon.setImage(giGiImage2);  bGiGi.updateUI();
        }
        if(who == bStop) {
          status = "... 按 STOP 停止大笑或唱歌 ! ";
        }
        repaint( );      // it will call our paint( )
    }
    public void mouseExited(MouseEvent e) { 
        Object who = e.getSource( );   /* 查哪零件觸發 Mouse event? */
        printMsg("MouseEvent: Exited " + who);
      ///
        if(who == bGiGi) {
          giGiIcon.setImage(giGiImage); bGiGi.updateUI();
        }
        if(who == bGiGi || who == bStop) {
          status = " ... Press Buttons to Test";
        }
        repaint( );     // it will call our paint( )
    }
 } // class Amigo == means friend in spanish
 ///// end of inner class Amigo

     static int msgLength;   // msgLength is used for Length of msg
     static final String msg = " Dear ..  My Dear  . . " +
        "我答應妳再也不會  打擾妳的生活 .. " +
        "捨不得妳  所以才會騙了妳也騙自己 .. " +
        "捨不得妳  雖然明知我的愛妳不珍惜 .. " +
        " - - - . . .  每當我最需要你  最想念你" +
        " 你總是缺席 ...   " +
        "能不能讓我   陪著妳走  既然妳說   留不住妳  " +
        "回去的路   有些黑暗  擔心讓妳   一個人走" +
        " . . .    .  .    ..     " +
        "如果你要離開我  . .  我想我不會太難過 :-(" +
        " 也許會有一點點難過 ...  至少不會在你的面前難過 :-(" +
        " 也許會在你的面前難過 ..  至少不會在你的面前流淚 :-(" +
        " 也許會在你的面前流淚 . . 至少不會在你的面前哭出聲 :::-(" +
        " . . .        .  .      .   ..    ";
     static { msgLength = msg.length( ); }  // do this when class loaded
  /// Note that 注意 static Block 只在 class 被 Loaded 進 JVM 時 Run 一次
} // end of the whole class SoundWin
