/**********************************************************************************
 *                                                                                *
 *                             Sound clock Applet                                 *
 *                             ( SoundClock.java )                                *
 *                                                         Author : Seiichi Inoue *
 **********************************************************************************/

/********************** << Imported package class definition >> *******************/
import java.applet.Applet;      /* Applet packages                                */
import java.awt.*;              /* All of the Abstract Windowing Toolkit packages */
import java.util.Date;          /* Date packages                                  */
import java.applet.AudioClip;   /* AudioClip package                              */

/************************** <<Oneself of class definition>> ***********************/
//    Class name      : SoundClock
//    Access control  : public( Access possibility even from which class )
//    Extends class   : Applet
//    Implements class: Runnable( Use of Thread is enabled )
public  class  SoundClock  extends Applet implements Runnable {

/************************* << Class attribute of definition >> ********************/
    Dimension    dm;                          /* Display range                    */
    Thread       kicker=null;                 /* Thread(Initial value:suspension) */
    Image        offs;                        /* Off screen                       */
    Graphics     grf;                         /* Drawing range                    */
    Image        img;                         /* Background image                 */
    MediaTracker mt;                          /* MediaTracker                     */
    String       param;                       /* Parameter reading                */
    int          imgsw;                       /* Background image presence info   */
    int          h_fontsize;                  /* Hour display font information    */
    int          m_fontsize;                  /* Minute display font information  */
    int          s_fontsize;                  /* Second display font information  */
    String       sh,h10,h01;                  /* Hour display letter information  */
    String       sm,m10,m01;                  /* Minute display letter information*/
    String       ss,s10,s01;                  /* Second display letter information*/
    int          h10x,h10y,h01x,h01y;         /* Hour display position information*/
    int          m10x,m10y,m01x,m01y;         /* Minute display position info     */
    int          s10x,s10y,s01x,s01y;         /* Second display position info     */
    int          am_pm;                       /* Morning/Afternoon information    */
    int          cent_x,cent_y;               /* Analog clock center coordinate   */
    boolean      digital,analog;              /* Display/undisplay information    */
    int          r;                           /* Size of analog clock             */
    AudioClip    sound = null;                /* Time signal sound information    */
    boolean      sound_sw;                    /* Time signal presence information */
    boolean      played = false;              /* Time signal completion inform    */
    Color        backcolor;                   /* Background color information     */

/***************** << Class of method (implementation procedure) >> ***************/
//
/******** Initialization (init) method *********/
    public void init() {
        dm = size();                            /* Set display screen size        */
        offs = createImage(dm.width,dm.height); /* Off scr area preparation       */
        grf  = offs.getGraphics();              /* Graphics object extraction     */

        param = getParameter("image");          /* Background image input reading */
        if ( param != null ) {                  /* Input parameter existence?     */
            mt = new MediaTracker(this);        /* MediaTracker instance          */
            img = getImage(getCodeBase(),param);/* Background image reading       */
            mt.addImage(img,0);                 /* Image load surveillance reg    */
            imgsw = 1;                          /* Background image existence info*/
        }
        else {                                  /* No : no designated input       */
            imgsw = 0;                          /* No background image info       */
            param = getParameter("backred");    /* Background red reading         */
            int backred = (param != null)?      /* Input determination            */
                Integer.parseInt(param): 0;
            param = getParameter("backgreen");  /* Background green reading       */
            int backgreen = (param != null)?    /* Input determination            */
                Integer.parseInt(param): 0;
            param = getParameter("backblue");   /* Background blue reading        */
            int backblue = (param != null)?     /* Input determination            */
                Integer.parseInt(param): 0;
            backcolor = new Color               /* Background color assembly      */
                (backred,backgreen,backblue);
        }

        param = getParameter("h_fontsize");     /* Hour display font size reading */
        h_fontsize = (param != null)?           /* Input determination            */
            Integer.parseInt(param): 20;
        param = getParameter("m_fontsize");     /* Minute disp font size reading  */
        m_fontsize = (param != null)?           /* Input determination            */
            Integer.parseInt(param): 20;
        param = getParameter("s_fontsize");     /* Second disp font size reading  */
        s_fontsize = (param != null)?           /* Input determination            */
            Integer.parseInt(param): 20;

        param = getParameter("h10x");           /* Hour 10 places disp position(H)*/
        h10x = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 0;
        param = getParameter("h10y");           /* Hour 10 places disp position(V)*/
        h10y = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 20;
        param = getParameter("h01x");           /* Hour 1 place disp position(H)  */
        h01x = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 10;
        param = getParameter("h01y");           /* Hour 1 place disp position(V)  */
        h01y = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 20;

        param = getParameter("m10x");           /* Minute 10 places disp posi(H)  */
        m10x = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 30;
        param = getParameter("m10y");           /* Minute 10 places disp posi(V)  */
        m10y = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 20;
        param = getParameter("m01x");           /* Minute 1 place disp position(H)*/
        m01x = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 40;
        param = getParameter("m01y");           /* Minute 1 place disp position(V)*/
        m01y = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 20;

        param = getParameter("s10x");           /* Second 10 places disp posi(H)  */
        s10x = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 60;
        param = getParameter("s10y");           /* Second 10 places disp posi(V)  */
        s10y = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 20;
        param = getParameter("s01x");           /* Second 1 place disp position(H)*/
        s01x = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 70;
        param = getParameter("s01y");           /* Second 1 place disp position(V)*/
        s01y = (param != null)?                 /* Input determination            */
            Integer.parseInt(param): 20;

        param = getParameter("clock_x");        /* Analog clock center read(H)    */
        cent_x = (param != null)?               /* Input determination            */
            Integer.parseInt(param): dm.width/2;
        param = getParameter("clock_y");        /* Analog clock center read(V)    */
        cent_y = (param != null)?               /* Input determination            */
            Integer.parseInt(param): dm.height/2;

        param = getParameter("digital");        /* Digital clock display reading  */
        param = (param != null)?                /* Input determination            */
            param: "true";
        if ( "true".equals (param) )            /* Digital clock is displayed?    */
            digital = true;                     /* YES: display setting           */
        else
            digital = false;                    /* NO: undisplay setting          */

        param = getParameter("analog");         /* Analog clock display reading   */
        param = (param != null)?                /* Input determination            */
            param: "true";
        if ( "true".equals (param) )            /* Analog clock is displayed?     */
            analog = true;                      /* YES: display setting           */
        else
            analog = false;                     /* NO: undisplay setting          */

        param = getParameter("size");           /* Analog clock size reading      */
        r = (param != null)?                    /* Input determination            */
            Integer.parseInt(param): 60;

        param = getParameter("sound");          /* Time signal sound param reading*/
        if ( param == null  ) {                 /* No sound designate ?           */
            sound_sw = false;                   /* No time signal setting         */
        }
        else {                                  /* It is                          */
            sound_sw = true;                    /* Time signal setting            */
            sound = getAudioClip(getCodeBase(),param); /* Time signal sound read  */
        }

    }                                           /* End of initial method          */

/************ Start (start) method *************/
    public void start() {
        if ( kicker == null ) {                 /* Kicker is null? ( Suspension? )*/
            kicker = new Thread(this);          /* YES: kicker setting            */
            kicker.start();                     /* Setting of start               */
        }
        repaint();
    }                                           /* End of start method            */

/*********** Repeatedly (run) method ***********/
    public void run() {
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY-3);
        if ( imgsw != 0 ) {                     /* It is designated an image?     */
            try {                               /* Interruption confirmation      */
                mt.waitForID(0);                /* Image load waiting             */
            } catch( InterruptedException e ) { /* Interruption processing        */
                System.out.println("Wait Error");
                return;
            }
        }

        while( kicker != null) {              /* Repeat until kicker becomes null */
            repaint();                          /* Drawing triggering             */
            try {                               /* Interruption confirmation      */
                kicker.sleep(100);              /* Wait 100 milli seconds set     */
            } catch (InterruptedException e) {} /* Interruption processing        */
        }
        kicker = null;                          /* Repeate process completion set */
    }                                           /* End of run method              */


/*********** Renewal (update) method ***********/
    public void update(Graphics g) {            /* Lost of screen flickering      */
        paint(g);                               /* Drawing                        */
    }                                           /* End of update method           */


/*********** Drawing (paint) method ************/
    public void paint(Graphics g) {
        if ( imgsw != 0 ) {                  /* Background image infor existence? */
            if ( mt.isErrorID(0)) {             /* Load error?                    */
                g.drawString("Image Load Error....",50,20); /* Error display      */
                return;
            }
            if( ! mt.checkID(0)) {              /* Loading ?                      */
                g.drawString("Loading....",dm.width/2-30,20); /* Loading display  */
                return;
            }
            grf.drawImage(img,0,0,this);        /* Image information setting      */
        }
        else {                                  /* NO :                           */
            grf.setColor(backcolor);            /* Set backcolor                  */
            grf.fillRect(0,0,dm.width,dm.height); /* Paint backcolor              */
        }

        Date d = new Date();                    /* Read clock information         */
        double h = d.getHours();                /* Hour information reading       */
        double m = d.getMinutes();              /* Minute information reading     */
        double s = d.getSeconds();              /* Second information reading     */

        if ( sound_sw ) {                       /* Time signal sound exists ?     */
            if ( s == 0 ) {                     /* 0 second ?                     */
                if ( played ) {}                /* Time signal trigger completion?*/
                else {                          /* Untriggering                   */
                    sound.play();               /* Time signal is sounded         */
                    played = true;              /* Set triggering completion      */
                }
            }
            else played = false;                /* Set untriggering information   */
        }


// <<Digital clock drawing processing>> 
        if ( digital ) {                        /* Digital clock is displayed?    */

                                                /* YES                            */
        if ( h < 12 )                           /* Morning?                       */
            am_pm = 0;                          /* YES:Morning information setting*/
        else {                                  /* NO :Afternoon                  */
            h -= 12;                            /* 12 hours reduction from hour   */
            am_pm = 1;                          /* Afternoon information setting  */
        }

        if ( h < 10 )                           /* One column ( 0 - 9 )?          */
            sh = " " + h + " ";                 /* Two column (  0 -  9 ) + Blank */
        else
            sh = h + " ";                       /* Figure + Blank(for extraction) */
        h10 = sh.substring(0,1);                /* Hour 10 places figure extracte */
        h01 = sh.substring(1,2);                /* Hour 1 place figure extracte   */
        if ( am_pm == 0 )                       /* Morning?                       */
            grf.setColor(Color.red);            /* Set morning letter color(red)  */
        else
            grf.setColor(Color.green);         /*Set afternoon letter color(green)*/
        grf.setFont(new Font("Dialog",Font.BOLD,h_fontsize)); /* Set font info    */
        grf.drawString( h10, h10x, h10y );      /* Set hour 10 places display     */
        grf.drawString( h01, h01x, h01y );      /* Set hour 1 place display       */

        if ( m < 10 )                           /* One column ( 0 - 9 )?          */
            sm = "0" + m + " ";                 /* Two column ( 00 - 09 ) + Blank */
        else
            sm = m + " ";                       /* Figure + Blank(for extraction) */
        m10 = sm.substring(0,1);                /* Minute 10 places fig extracte  */
        m01 = sm.substring(1,2);                /* Minute 1 place fig extracte    */
        if ( am_pm == 0 )                       /* Morning?                       */
            grf.setColor(Color.red);            /* Set morning letter color(red)  */
        else
            grf.setColor(Color.green);         /*Set afternoon letter color(green)*/
        grf.setFont(new Font("Dialog",Font.BOLD,m_fontsize)); /* Set font info    */
        grf.drawString( m10, m10x, m10y );      /* Set minute 10 places display   */
        grf.drawString( m01, m01x, m01y );      /* Set minute 1 place display     */

        if ( s < 10 )                           /* One column ( 0 - 9 )?          */
            ss = "0" + s + " ";                 /* Two column ( 00 - 09 ) + Blank */
        else
            ss = s + " ";                       /* Figure + Blank(for extraction) */
        s10 = ss.substring(0,1);                /* Second 10 places fig extracte  */
        s01 = ss.substring(1,2);                /* Second 1 place fig extracte    */
        grf.setColor(Color.red);                /* Letter color setting (red)     */
        grf.setFont(new Font("Dialog",Font.BOLD,s_fontsize)); /* Set font info    */
        grf.drawString( s10, s10x, s10y );      /* Set second 10 places display   */
        grf.drawString( s01, s01x, s01y );      /* Set second 1 place display     */

        }


// <<Analog clock drawing processing>> 
        if ( analog ) {                         /* Analog clock is displayed?     */

                                                /* YES                            */
        double rd = 3.14159/180;                /* Radian value (64bit)           */

        grf.setColor(Color.yellow);             /* Dial plate color setting       */
        for ( int k=0; k<60; k++ ) {            /* Dial plate drawing (Sixty dot) */
            int dmx = (int)(cent_x+(r+5)*Math.sin(k*6*rd)); /* Calculate abscissa */
            int dmy = (int)(cent_y+(r+5)*Math.cos(k*6*rd)); /* Calculate ordinate */
            grf.fillOval(dmx-1,dmy-1,2,2);      /* Drawing square of 2 pixel      */
        }
        grf.setColor(Color.red);                /* Dial plate color setting       */
        for ( int k=0; k<12; k++ ) {            /* Dial plate drawing (Twelve dot)*/
            int dx = (int)(cent_x+(r+5)*Math.sin(k*30*rd)); /* Calculate abscissa */
            int dy = (int)(cent_y-(r+5)*Math.cos(k*30*rd)); /* Calculate ordinate */
            grf.fillRect(dx-3,dy-3,6,6);        /* Drawing square of 6 pixel      */
        }

// With the expression that calculates the width coordinate of the hour hand and
// minute hand the last term(0.5 or 0.4) is a central angle.
// Even if the size of the clock is changed it does not change.
// Therefore, it might had better change it by the size of the clock. 
                                              /* Hour hand (short hand) processing*/
        int hx2 = (int)(cent_x+r/3*Math.sin((h*5+m/12)*6*rd-0.5));/*Left width(X) */
        int hy2 = (int)(cent_y-r/3*Math.cos((h*5+m/12)*6*rd-0.5));/*Left width(Y) */
        int hx3 = (int)(cent_x+r*2/3*Math.sin((h*5+m/12)*6*rd));  /*Top(X)        */
        int hy3 = (int)(cent_y-r*2/3*Math.cos((h*5+m/12)*6*rd));  /*Top(Y)        */
        int hx4 = (int)(cent_x+r/3*Math.sin((h*5+m/12)*6*rd+0.5));/*Right width(X)*/
        int hy4 = (int)(cent_y-r/3*Math.cos((h*5+m/12)*6*rd+0.5));/*Right width(Y)*/
        int hxPoint[] = {cent_x,hx2,hx3,hx4};   /* Polygon setting (X)            */
        int hyPoint[] = {cent_y,hy2,hy3,hy4};   /* Polygon setting (Y)            */
        grf.setColor(Color.green);              /* Hour hand color setting        */
        grf.fillPolygon(hxPoint,hyPoint,4);     /* Hour hand polygon drawing      */


                                             /* Minute hand (long hand) processing*/
        int mx2 = (int)(cent_x+r/3*Math.sin((m+s/60)*6*rd-0.4));  /*Left width(X) */
        int my2 = (int)(cent_y-r/3*Math.cos((m+s/60)*6*rd-0.4));  /*Left width(Y) */
        int mx3 = (int)(cent_x+r*Math.sin((m+s/60)*6*rd));        /*Top(X)        */
        int my3 = (int)(cent_y-r*Math.cos((m+s/60)*6*rd));        /*Top(Y)        */
        int mx4 = (int)(cent_x+r/3*Math.sin((m+s/60)*6*rd+0.4));  /*Right width(X)*/
        int my4 = (int)(cent_y-r/3*Math.cos((m+s/60)*6*rd+0.4));  /*Right width(Y)*/
        int mxPoint[] = {cent_x,mx2,mx3,mx4};   /* Polygon setting (X)            */
        int myPoint[] = {cent_y,my2,my3,my4};   /* Polygon setting (Y)            */
        grf.setColor(Color.blue);               /* Minute hand color setting      */
        grf.fillPolygon(mxPoint,myPoint,4);     /* Minute hand polygon drawing    */


                                                /* Second hand  processing        */
        int sx2 = (int)(cent_x+r*Math.sin(s*6*rd));/* Second hand top X coordinate*/
        int sy2 = (int)(cent_y-r*Math.cos(s*6*rd));/* Second hand top Y coordinate*/
        grf.setColor(Color.red);                /* Second hand color setting      */
        grf.drawLine(cent_x,cent_y,sx2,sy2);    /* Second hand drawing            */

        grf.setColor(Color.red);                /* Center dot color setting       */
        grf.fillOval(cent_x-5,cent_y-5,10,10);  /* Drawing circle of 10 pixel     */

        }


        g.drawImage(offs,0,0,this);             /* Drawing setting                */

    }                                           /* End of paint method            */


/************ Stop (stop) method ***************/
    public void stop() {
        if( kicker != null ) {                  /* Kicker is not null?( action? ) */
            kicker.stop();                      /* Set kicker to suspension       */
            kicker = null;                      /* Set kicker suspension condition*/
        }
    }                                           /* End of stop method             */

}                                               /* End of class setting           */

/**********************************************************************************
 *                            End of Sound clock Applet                           *
 **********************************************************************************/