/**********************************************************************************
 *                                                                                *
 *                     アナログ/デジタル時計Javaアプレット                      *
 *                             ( AD_Clock.java )                                  *
 *                                                                                *
 *                                                        Author : Seiichi Inoue  *
 **********************************************************************************/

/****************** << インポートパッケージクラス定義 >> ********************/
import java.applet.Applet;           /* Appletパッケージ                       */
import java.awt.*;                   /* Abstract Windowing Toolkitパッケージの全て*/
import java.util.Date;               /* Dateパッケージ                            */

/************************ << 自分のクラス定義 >> ****************************/
//   クラス名称   : AD_Clock
//   アクセス制御  : public(どのクラスからもアクセス可能)
//   継承クラス   : Applet
//   引継クラス   : Runnable(Threadを使用可能にする)
public  class  AD_Clock  extends Applet implements Runnable {

/************************ << クラス属性の定義 >> ****************************/
    Dimension    dm;                            /* 表示領域            */
    Thread       kicker=null;                   /* スレッド制御(初期値:停止)  */
    Image        offs;                          /* オフスクリーンエリア      */
    Graphics     grf;                           /* 描画領域             */
    Image        img;                           /* 背景イメージ情報        */
    MediaTracker mt;                            /* メディアトラッカー       */
    String       param;                         /* 入力パラメータ取込エリア    */
    int          imgsw;                         /* 背景イメージ有無情報      */
    int          h_fontsize;                    /* 時表示フォント情報       */
    int          m_fontsize;                    /* 分表示フォント情報       */
    int          s_fontsize;                    /* 秒表示フォント情報       */
    String       sh,h10,h01;                    /* 時表示文字情報         */
    String       sm,m10,m01;                    /* 分表示文字情報         */
    String       ss,s10,s01;                    /* 秒表示文字情報         */
    int          h10x,h10y,h01x,h01y;           /* 時表示位置情報         */
    int          m10x,m10y,m01x,m01y;           /* 分表示位置情報         */
    int          s10x,s10y,s01x,s01y;           /* 秒表示位置情報         */
    int          am_pm;                         /* 午前/午後情報         */
    int          cent_x,cent_y;                 /* アナログ時計中心座標      */
    boolean      digital,analog;                /* 表示/非表示情報        */
    int          r;                             /* アナログ時計のサイズ情報    */

/******************** << クラスのメッソード指定(実行手順) >> **************/

/*********** 初期化(init)メッソード **********/
    public void init() {
        dm = size();                            /* 表示画面サイズ情報を設定     */
        offs = createImage(dm.width,dm.height); /* オフスクリーン用エリア作成   */
        grf  = offs.getGraphics();              /* Graphicsオブジェクト取出     */

        param = getParameter("image");          /* 背景イメージ入力取込      */
        if ( param != null ) {                  /* 入力パラメータ有り?      */
            mt = new MediaTracker(this);        /* メディアトラッカーインスタンス */
            img = getImage(getCodeBase(),param);/* 背景イメージ取込            */
            mt.addImage(img,0);                 /* イメージロード監視登録     */
            imgsw = 1;                          /* 背景イメージ有り情報設定    */
        }
        else                                    /* NO :入力指定無し        */
            imgsw = 0;                          /* 背景イメージ無し情報設定    */

        param = getParameter("h_fontsize");     /* 時間表示フォントサイズ入力取込 */
        h_fontsize = (param != null)?           /* 入力判定(無指定時:20ポイント) */
            Integer.parseInt(param): 20;
        param = getParameter("m_fontsize");     /* 分表示フォントサイズ入力取込  */
        m_fontsize = (param != null)?           /* 入力判定(無指定時:20ポイント) */
            Integer.parseInt(param): 20;
        param = getParameter("s_fontsize");     /* 秒表示フォントサイズ入力取込  */
        s_fontsize = (param != null)?           /* 入力判定(無指定時:20ポイント) */
            Integer.parseInt(param): 20;

        param = getParameter("h10x");           /* 時10位表示位置(横)入力取込 */
        h10x = (param != null)?                 /* 入力判定(無指定時:0)      */
            Integer.parseInt(param): 0;
        param = getParameter("h10y");           /* 時10位表示位置(縦)入力取込 */
        h10y = (param != null)?                 /* 入力判定(無指定時:20)     */
            Integer.parseInt(param): 20;
        param = getParameter("h01x");           /* 時1位表示位置(横)入力取込  */
        h01x = (param != null)?                 /* 入力判定(無指定時:10)     */
            Integer.parseInt(param): 10;
        param = getParameter("h01y");           /* 時1位表示位置(縦)入力取込  */
        h01y = (param != null)?                 /* 入力判定(無指定時:20)     */
            Integer.parseInt(param): 20;

        param = getParameter("m10x");           /* 分10位表示位置(横)入力取込 */
        m10x = (param != null)?                 /* 入力判定(無指定時:30)     */
            Integer.parseInt(param): 30;
        param = getParameter("m10y");           /* 分10位表示位置(縦)入力取込 */
        m10y = (param != null)?                 /* 入力判定(無指定時:20)     */
            Integer.parseInt(param): 20;
        param = getParameter("m01x");           /* 分1位表示位置(横)入力取込  */
        m01x = (param != null)?                 /* 入力判定(無指定時:40)     */
            Integer.parseInt(param): 40;
        param = getParameter("m01y");           /* 分1位表示位置(縦)入力取込  */
        m01y = (param != null)?                 /* 入力判定(無指定時:20)     */
            Integer.parseInt(param): 20;

        param = getParameter("s10x");           /* 秒10位表示位置(横)入力取込 */
        s10x = (param != null)?                 /* 入力判定(無指定時:60)     */
            Integer.parseInt(param): 60;
        param = getParameter("s10y");           /* 秒10位表示位置(縦)入力取込 */
        s10y = (param != null)?                 /* 入力判定(無指定時:20)     */
            Integer.parseInt(param): 20;
        param = getParameter("s01x");           /* 秒1位表示位置(横)入力取込  */
        s01x = (param != null)?                 /* 入力判定(無指定時:70)     */
            Integer.parseInt(param): 70;
        param = getParameter("s01y");           /* 秒1位表示位置(縦)入力取込  */
        s01y = (param != null)?                 /* 入力判定(無指定時:20)     */
            Integer.parseInt(param): 20;

        param = getParameter("clock_x");        /* アナログ時計中心X座標取込   */
        cent_x = (param != null)?               /* 入力判定(無指定時:描画領域中央)*/
            Integer.parseInt(param): dm.width/2;
        param = getParameter("clock_y");        /* アナログ時計中心Y座標取込   */
        cent_y = (param != null)?               /* 入力判定(無指定時:描画領域中央)*/
            Integer.parseInt(param): dm.height/2;

        param = getParameter("digital");        /* デジタル時計表示指定取込    */
        param = (param != null)?                /* 入力判定(無指定時:true)    */
            param: "true";
        if ( "true".equals (param) )            /* デジタル時計を表示する?    */
            digital = true;                     /* YES:表示する(正)設定     */
        else
            digital = false;                    /* NO :表示しない(偽)設定    */

        param = getParameter("analog");         /* アナログ時計表示指定取込    */
        param = (param != null)?                /* 入力判定(無指定時:true)    */
            param: "true";
        if ( "true".equals (param) )            /* アナログ時計を表示する?    */
            analog = true;                      /* YES:表示する(正)設定     */
        else
            analog = false;                     /* NO :表示しない(偽)設定    */

        param = getParameter("size");           /* アナログ時計サイズ取込     */
        r = (param != null)?                    /* 入力判定(無指定時:半径60ピクセル) */
            Integer.parseInt(param): 60;


    }                                           /* 初期化メソッド終了       */

/********** スタート(start)メソッド **********/
    public void start() {
        if ( kicker == null ) {                 /* kickerがnull?(停止中?)   */
            kicker = new Thread(this);          /* YES:kickerを動作中に設定   */
            kicker.start();                     /* startを設定          */
        }
        repaint();
    }                                           /* スタートメソッド終了      */

/*********** 繰り返し(run)メソッド ***********/
    public void run() {
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY-3);
        if ( imgsw != 0 ) {                     /* イメージ指定あり?       */
            try {                               /* 割り込み確認          */
                mt.waitForID(0);                /* イメージロード待ち合わせ    */
            } catch( InterruptedException e ) { /* 割り込み処理          */
                System.out.println("Wait Error");
                return;
            }
        }

        while( kicker != null) {                /* kickerがnullになるまで繰り返し */
            repaint();                          /* 描画              */
            try {                               /* 割り込み確認          */
                kicker.sleep(100);              /* 待ち時間を100ミリ秒設定    */
            } catch (InterruptedException e) {} /* 割り込み処理          */
        }
        kicker = null;
    }                                           /* 実行メソッド終了        */


/************ 更新(update)メソッド ***********/
    public void update(Graphics g) {            /* 画面のちらつきを無くす     */
        paint(g);                               /* 描画              */
    }                                           /* 更新メソッド終了        */


/************ 描画(paint)メソッド ************/
    public void paint(Graphics g) {
        if ( imgsw != 0 ) {                     /* 背景イメージ情報有り?     */
            if ( mt.isErrorID(0)) {             /* ロードエラー?         */
                g.drawString("Image Load Error....",50,20); /* エラー表示     */
                return;
            }
            if( ! mt.checkID(0)) {              /* ロード中?           */
                g.drawString("Loading....",dm.width/2-30,20); /* ロード中表示   */
                return;
            }
            grf.drawImage(img,0,0,this);        /* イメージ情報設定        */
        }
        else {                                  /* NO :                           */
            grf.setColor(Color.black);          /*   背景色(黒)を設定     */
            grf.fillRect(0,0,dm.width,dm.height); /*  背景色塗りつぶし       */
        }

        Date d = new Date();                    /* 時計情報を取込         */
        double h = d.getHours();                /* 時情報を取込          */
        double m = d.getMinutes();              /* 分情報を取込          */
        double s = d.getSeconds();              /* 秒情報を取込          */

// <<デジタル時計描画処理>>
        if ( digital ) {                        /* デジタル時計を表示する?    */

                                                /* YES             */
        if ( h < 12 )                           /* 午前?             */
            am_pm = 0;                          /* YES:午前情報設定        */
        else {                                  /* NO :午後            */
            h -= 12;                            /*     時情報から12時間減算   */
            am_pm = 1;                          /*     午後情報設定        */
        }

        if ( h < 10 )                           /* 1桁( 0 - 9 )?        */
            sh = " " + h + " ";                 /* 2桁(  0 -  9 ) + 空白     */
        else
            sh = h + " ";                       /* 数字 + 空白(抽出処理のため)  */
        h10 = sh.substring(0,1);                /* 時10位数字抽出        */
        h01 = sh.substring(1,2);                /* 時1位数字抽出         */
        if ( am_pm == 0 )                       /* 午前?             */
            grf.setColor(Color.red);            /* 午前文字色(赤)設定      */
        else
            grf.setColor(Color.green);          /* 午後文字色(緑)設定      */
        grf.setFont(new Font("Dialog",Font.BOLD,h_fontsize)); /* フォント情報設定 */
        grf.drawString( h10, h10x, h10y );      /* 時10位表示情報設定      */
        grf.drawString( h01, h01x, h01y );      /* 時1位表示情報設定       */

        if ( m < 10 )                           /* 1桁( 0 - 9 )?        */
            sm = "0" + m + " ";                 /* 2桁( 00 - 09 ) + 空白     */
        else
            sm = m + " ";                       /* 数字 + 空白(抽出処理のため)  */
        m10 = sm.substring(0,1);                /* 分10位数字抽出        */
        m01 = sm.substring(1,2);                /* 分1位数字抽出         */
        if ( am_pm == 0 )                       /* 午前?             */
            grf.setColor(Color.red);            /* 午前文字色(赤)設定      */
        else
            grf.setColor(Color.green);          /* 午後文字色(緑)設定      */
        grf.setFont(new Font("Dialog",Font.BOLD,m_fontsize)); /* フォント情報設定 */
        grf.drawString( m10, m10x, m10y );      /* 分10位表示情報設定      */
        grf.drawString( m01, m01x, m01y );      /* 分1位表示情報設定       */

        if ( s < 10 )                           /* 1桁( 0 - 9 )?        */
            ss = "0" + s + " ";                 /* 2桁( 00 - 09 ) + 空白     */
        else
            ss = s + " ";                       /* 数字 + 空白(抽出処理のため)  */
        s10 = ss.substring(0,1);                /* 秒10位数字抽出        */
        s01 = ss.substring(1,2);                /* 秒1位数字抽出         */
        grf.setColor(Color.red);                /* 文字色設定           */
        grf.setFont(new Font("Dialog",Font.BOLD,s_fontsize)); /* フォント情報設定 */
        grf.drawString( s10, s10x, s10y );      /* 秒10位表示情報設定      */
        grf.drawString( s01, s01x, s01y );      /* 秒1位表示情報設定       */

        }


// <<アナログ時計描画処理>>
        if ( analog ) {                         /* アナログ時計を表示する?    */

                                                /* YES             */
        double rd = 3.14159/180;                /* ラジアン値(64bit)       */

        grf.setColor(Color.yellow);             /* 文字盤色設定          */
        for ( int k=0; k<12; k++ ) {            /* 文字盤(12ドット)描画    */
            int dx = (int)(cent_x+(r+5)*Math.sin(k*30*rd)); /* X座標計算     */
            int dy = (int)(cent_y-(r+5)*Math.cos(k*30*rd)); /* Y座標計算     */
            grf.fillRect(dx-3,dy-3,6,6);        /*6ピクセルの四角を描画     */
        }

// 時針、分針の幅座標を求める式で最後の項(0.5とか0.4)は中心からの角度です。
// 時計のサイズを変更しても変化しませんので、見栄により変えた方が良いかも知れません。
                                                /* 時針(短針)の処理       */
        int hx2 = (int)(cent_x+r/3*Math.sin((h*5+m/12)*6*rd-0.5));/*時針左幅X座標*/
        int hy2 = (int)(cent_y-r/3*Math.cos((h*5+m/12)*6*rd-0.5));/*時針左幅Y座標*/
        int hx3 = (int)(cent_x+r*2/3*Math.sin((h*5+m/12)*6*rd));  /*時針先端X座標*/
        int hy3 = (int)(cent_y-r*2/3*Math.cos((h*5+m/12)*6*rd));  /*時針先端Y座標*/
        int hx4 = (int)(cent_x+r/3*Math.sin((h*5+m/12)*6*rd+0.5));/*時針右幅X座標*/
        int hy4 = (int)(cent_y-r/3*Math.cos((h*5+m/12)*6*rd+0.5));/*時針右幅Y座標*/
        int hxPoint[] = {cent_x,hx2,hx3,hx4};   /* 多角形(ポリゴン)X座標設定  */
        int hyPoint[] = {cent_y,hy2,hy3,hy4};   /* 多角形(ポリゴン)Y座標設定  */
        grf.setColor(Color.green);              /* 時針色設定           */
        grf.fillPolygon(hxPoint,hyPoint,4);     /* 時針多角形(ポリゴン)描画   */


                                                /* 分針(長針)の処理       */
        int mx2 = (int)(cent_x+r/3*Math.sin((m+s/60)*6*rd-0.4));  /*分針左幅X座標*/
        int my2 = (int)(cent_y-r/3*Math.cos((m+s/60)*6*rd-0.4));  /*分針左幅Y座標*/
        int mx3 = (int)(cent_x+r*Math.sin((m+s/60)*6*rd));        /*分針先端X座標*/
        int my3 = (int)(cent_y-r*Math.cos((m+s/60)*6*rd));        /*分針先端Y座標*/
        int mx4 = (int)(cent_x+r/3*Math.sin((m+s/60)*6*rd+0.4));  /*分針右幅X座標*/
        int my4 = (int)(cent_y-r/3*Math.cos((m+s/60)*6*rd+0.4));  /*分針右幅Y座標*/
        int mxPoint[] = {cent_x,mx2,mx3,mx4};   /* 多角形(ポリゴン)X座標設定  */
        int myPoint[] = {cent_y,my2,my3,my4};   /* 多角形(ポリゴン)Y座標設定  */
        grf.setColor(Color.blue);               /* 分針色設定           */
        grf.fillPolygon(mxPoint,myPoint,4);     /* 分針多角形(ポリゴン)描画   */


                                                /* 秒針の処理           */
        int sx2 = (int)(cent_x+r*Math.sin(s*6*rd));             /* 秒針先端X座標 */
        int sy2 = (int)(cent_y-r*Math.cos(s*6*rd));             /* 秒針先端Y座標 */
        grf.setColor(Color.red);                /* 秒針色設定           */
        grf.drawLine(cent_x,cent_y,sx2,sy2);    /* 秒針描画            */

        grf.setColor(Color.red);                /* センターノブ色設定       */
        grf.fillOval(cent_x-5,cent_y-5,10,10);  /* 10ピクセルの円を描画     */

        }


        g.drawImage(offs,0,0,this);             /* 描画設定            */

    }                                           /* 描画メソッド終了        */


/********** ストップ(stop)メソッド *********/
    public void stop() {
        if( kicker != null ) {                  /* kickerがnullでない?(動作中?) */
            kicker.stop();                      /* kickerを停止に設定       */
            kicker = null;                      /* kickerに停止状態を設定     */
        }
    }                                           /* ストップメソッド終了      */

}                                               /* クラス設定終了         */

/**********************************************************************************
 *          アナログ/デジタル時計アプレット終了                        *
 **********************************************************************************/