//SoundWin.java -- by tsaiwn@csie.nctu.edu.tw
// Test Open a URL window, playing Song in Applet
//  javac -encoding Big5 -target 1.1 SoundWin.java
//
//This Java program can be used both as Applet and as Application.
//To run as an Application: java SoundWin
//////////
/*****  When used as an Applet, embed it in a HTML as following:
 <br>
 <applet code="SoundWin.class" width=380 height=288>
 </applet>
 <! More Files need:
    howcome.au, laugh.au, welcome.au  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;
import javax.swing.JButton;

public class SoundWin extends Applet implements ActionListener{
      static final int width=358, height=288;
      static int msgLength;   // msg is on the last part
      String songName = "howcome.au",  laughName = "laugh.au";
      String kimoLocation = "http://tw.yahoo.com";
      String songLocation = "http://www.csie.nctu.edu.tw/~tsaiwn/audir/";
      String flashLocation =
       "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" +
            "movie%ad%ec%a9l%c0%c9/4-%af%ab%c0J%abL%abQ/4.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/" };

      String giGiFilename = "gigi.jpg";
      String giGiFilename2 = "gigib.jpg";
      Toolkit toolkit;
      Frame f;
      Applet ap=null;
      Image giGiImage, giGiImage2;
      ImageIcon giGiIcon;
      JButton bGiGi = new JButton("Ha大笑");
      AudioClip song; 
      Button bWeb = new Button("連到奇摩");
      Button bSong = new Button("點唱 情字這條路");
      Button bLaugh = new Button("Ha大笑");
      Button bQuit = new Button("STOP");
      Button bFlash = new Button("FLASH");
      static int visitCount = 0;
      Font myFont = new Font("標楷體", Font.BOLD, 18);
      protected Hinter hinter;  // a thread to flash the hint message
      String status = "---";

      static private boolean isApplication = false;
   public static void main( String s[]) {   // for Application only
      Frame f = new Frame("Window 2004");
      isApplication = true;
      SoundWin a = new SoundWin( ); a.ap = a; a.f = f;
      a.init( ); a.start( );  // simulate Applet behavior
      f.add(a, BorderLayout.CENTER); f.setSize(width+20, height+12);
      f.setVisible(true); f.validate( );
      a.makeLaugh( );
   }

   public SoundWin( ) {  // Constructor
      if(ap==null) ap = this;   // it is Applet and thus ap is null
   }

   private void decorateFrame( ) {
      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 pWin = new Panel(); pWin.add(bSong);
      pWin.add(bWeb); pWin.add(bFlash); 
      ap.add(pWin,"South");
     //
      Panel pLaugh = new Panel(new GridLayout(2,1,5,28));
      pLaugh.add(bGiGi); pLaugh.add(bQuit);
      ap.add(pLaugh, "West"); 
   } // decorateFrame

   public void init( ) {
      toolkit = Toolkit.getDefaultToolkit();
      bGiGi = new JButton("HaHa大笑");
      try {
         if(isApplication){
            giGiImage = newImage(giGiFilename);
         } else
            giGiImage = getImage(new URL( getCodeBase()+ giGiFilename));
         giGiIcon = new ImageIcon(giGiImage);
         bGiGi = new JButton(giGiIcon);
         if(isApplication){
            giGiImage2 = newImage(giGiFilename2);
         } else
            giGiImage2 = getImage(new URL( getCodeBase()+ giGiFilename2));
      } catch (Exception e) { ; }
      bGiGi.setCursor( new Cursor(Cursor.HAND_CURSOR) );
      bQuit.setCursor( new Cursor(Cursor.HAND_CURSOR) );
      //ap.setLayout(new BorderLayout( ) );
      setLayout(new BorderLayout( ) );
      decorateFrame( );
     ///
      bQuit.setBackground(Color.red);
      bQuit.setFont( new Font("Ludica Console", Font.BOLD, 20) );
      bSong.setBackground(Color.pink);
      bWeb.setBackground(Color.green);
     ////
      bWeb.addActionListener(this);  // register with ActionListener
      bFlash.addActionListener(this);
      bSong.addActionListener(this);
      bGiGi.addActionListener(this);
      bGiGi.addMouseListener(new Amigo( ));
      bQuit.addMouseListener(new Amigo( ) );
      bQuit.addActionListener(this); 
      ap.setSize(width, height);
      ap.setVisible(true);
      status = "...Press the Button to test ..";  repaint( );
     /// for Application
      if( f != null) {
         f.setSize(width+20, height+12);
         f.setVisible(true); f.validate( );
      }
      msgLength = msg.length( );
      hinter = new Hinter( );  // is a Thread acts as a timer
      hinter.start( );  // start the Timer thread to toggle hint message
   } // init()

   public void start( ) { super.start( ); }

   public void paint(Graphics g) { // we should NOT call paint directly
      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);
   }

   private void rollMessage(Graphics g) {
       int showLen = 18;
       int len = msgLength;
       int p = (int) (hinter.showFlag % msgLength);
       int pEnd = p + showLen -1;
       String s;
       if(pEnd < msgLength ){
         s = msg.substring(p, pEnd);
       }else{
         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( );
      if(who == bWeb) {
          bWeb.setBackground(Color.red);
          openKimo( );
          //f.validate( );  // so that Layout Manager ...
      }
      else if(who == bSong) playSong( ); //play song: 情字這條路
      else if(who == bGiGi) makeLaugh( ); //play laugh.au
      else if(who == bFlash) { openFlashURL( ); }
      else if(who == bQuit) {
          if(song != null) song.stop( );  // stop playing the song
          status = "...Press the Button to test ..";  repaint( );
          System.exit(0);
      } //
   } // actionPerformed()

   void openKimo( ) {
       try {
          if(isApplication){
             try {
                Runtime.getRuntime().exec(
                  "cmd /c \"start " + kimoLocation +"\" " );
             } catch (Exception e95){  // try Win 95/98
                Runtime.getRuntime().exec(
                  "start " + kimoLocation );
             }
          } else {
             URL url = new URL(kimoLocation);
             getAppletContext().showDocument(url, "_blank"); 
          }
                         // _blank means in New Window
       } catch (Exception e) {; }
   }

   void openFlashURL( ) {
       int n = (int)(Math.random( ) * 100);
       n = n% swfAry.length;
       if( visitCount++ == 0 ) n = 0;   // first visit, show swfAry[0]
       if( visitCount == 2 ) n = 2;  // GGL
       if( visitCount == 3 ) n = 3;  // play_hand_mouse
       if( visitCount >= 4 )if( n == 0 ) n = visitCount % swfAry.length;
       try {
          flashLocation = swfAry[n];
       } catch (Exception e) { n=2; }  // 2 is GGL
       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"); 
          }
       } catch (Exception e) {; }
   }

   void openSong( ) {
       try {
          URL url = new URL( (songLocation + songName).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( ) {
       try {
         //System.err.print("CodeBase= " + getCodeBase() ); 
         try {
           status = "...Loading " + songName;  repaint( );
           showStatus("...Loading " + songName);
           song = null;
         } catch (Exception e) {;}
         if(isApplication) {  // after JDK 1.2
            song = Applet.newAudioClip(new URL(newCodeBase()+songName)); 
         }else{
            song = getAudioClip(getDocumentBase(), songName); 
         } // if
       } catch ( Exception e ) {
           //System.out.println("Fail "+e);
           try{  // try tsaiwn URL
              showStatus(".. " + songLocation + songName);
              song = getAudioClip( new URL(songLocation + songName) );
              status = ".. " + songLocation + songName + "     ";
              if(song==null) { openSong(); return;  }  // try my best
           } catch (Exception e2){
           //System.out.println("Fail "+e);
              try{
                 song = getAudioClip( new URL("./welcome.au") );
                 status = "..   ./welcome.au == === ===" +  "     ";
              } catch (Exception e3){ 
                 try { song = Applet.newAudioClip(
                     new URL(newCodeBase() +"welcome.au") );
                 } catch ( Exception e4) { }  // try it anyway
              }
           }
       } ; //
        // Play the sound if we got the AudioClip
       try {
          try{System.err.println("Playing.." + songName);}catch(Exception e){}
          if(song!=null) {
             song.play(); 
             status = "...Playing " + songName;
          }
          repaint( );
          showStatus(" " + status );
       } catch ( Exception e ) { return; }
   } // playSong()

   void makeLaugh( ) {
       try {
          if(isApplication) {
             URL base = newCodeBase();
             song = Applet.newAudioClip(new URL(base+"laugh.au")); 
          } else
             song = getAudioClip(getDocumentBase(), "laugh.au"); 
          song.play( );
          status = "...Laugh .." + laughName;  repaint( );
       } catch (Exception e) {; }
   }

   static public URL newCodeBase( ) {    // for Application
       URL codeBase = null;
       try{
          codeBase = new URL("file:" + System.getProperty("user.dir") + "/");
       } catch ( Exception e ) {
          // maybe it is an Applet, use getCodeBase() or getDocumentBase()
       }
       return codeBase;
   }

 /// get Image from a local file --- for Application (not Applet)
   static public Image newImage(String filename) {
       Image img = null;
       try{ Toolkit tkt = Toolkit.getDefaultToolkit( );
            img = tkt.getImage(filename);  //for application only
            // img = getImage(getCodeBase( ), filename); //for Applet
       } catch ( Exception e ) {;}
       return img;
   } // newImage(filename)
   static public Image getMyImage(String filename) {
       return newImage(filename);
   } // getMyImage(filename)

   protected boolean hintMode = false;   // control toggle display hint

 // an inner class to act as a Timer to show hint message
 class Hinter extends Thread {
    protected volatile boolean shouldDie = false;  // instead of stop( );
    protected long showFlag = 0;
    final private static int showInterval = 588;
    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
 } // 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? */
        if(who == bGiGi) {
          status = "... 按我就會大笑喔:-)";
          giGiIcon.setImage(giGiImage2);  bGiGi.updateUI();
        }
        if(who == bQuit) {
          status = "... 按 STOP 停止大笑或唱歌 ! ";
        }
        repaint( );
    }
    public void mouseExited(MouseEvent e){ 
        Object who = e.getSource( );   /* 查哪零件觸發 Mouse event? */
        if(who == bGiGi || who == bQuit) {
          status = " ... Press Buttons to Test"; repaint( );
        }
        if(who == bGiGi) {
          giGiIcon.setImage(giGiImage); bGiGi.updateUI();
        }
        repaint( );
    }
 } // class Amigo == means friend in spanish
 ///// end of inner class Amigo

     static final String msg = " Dear ..  My Dear  . . " +
        "我答應妳再也不會  打擾妳的生活 .. " +
        "捨不得妳  所以才會騙了妳也騙自己 .. " +
        "捨不得妳  雖然明知我的愛妳不珍惜 .. " +
        " - - - . . .  每當我最需要你  最想念你" +
        " 你總是缺席 ...   " +
        "能不能讓我   陪著妳走  既然妳說   留不住妳  " +
        "回去的路   有些黑暗  擔心讓妳   一個人走" +
        " . . .  . .     .  .      ..      " +
        "如果你要離開我  . .  我想我不會太難過 " +
        " 也許會有一點點難過 ...  至少不會在你的面前難過 " +
        " 也許會在你的面前難過 ..  至少不會在你的面前流淚 " +
        " 也許會在你的面前流淚 . . 至少不會在你的面前哭出聲 " +
        " . . .        .  .      .   ..    ";
}
