/**
 File:      DigitalClockApplet.java
 Author:    Angus McIntyre <angus@pobox.com>
 Date:      22.05.96
 Updated:   17.03.98 23:55
 
 Simple Java applet to display a digital clock and update it continuously.
 
    HISTORY
    -------
    
    05.03.00	SLAM	Fixed minor Y2K bug in year display.
	17.03.98	SLAM	Added lots of new features including date,
    					margin width control, and control over
    					3D appearance of clockface.
    27.05.96    SLAM    Bug fixes
	22.05.96	SLAM    First version implemented
    
    TO-DO
    -----
        
        * Use clipping regions to restrict the size of the area being
          updated. This should reduce flashing on some browsers.
              
    LEGAL
    -----
    
    This software is free. It can be used and modified in any way you 
    choose, but it may not be sold, either separately or as part of a 
    collection without explicit prior permission from the author. The 
    author assumes no liability for any loss, damage or mental or 
    physical trauma you may incur through use of or inability to use 
    this software. This disclaimer must appear on any modified or 
    unmodified version of the software in which the name of the author
    also appears.
    
**/

/* ----------------------------------------------------------------------
 *                              IMPORTS
 * ---------------------------------------------------------------------- */

import java.applet.*;
import java.awt.*;
import java.util.*;
import ClockApplet;

/* ----------------------------------------------------------------------
 *                              CLASSES
 * ---------------------------------------------------------------------- */

// Class:   DigitalClockApplet
//
// Built on top of ClockApplet, this is used to implement simple in-line
// digital clock displays.

public class DigitalClockApplet extends ClockApplet {

    // Defaults
    
    static  final   String      default_font_face = "Helvetica";
    static  final   int         default_font_size = 14;
    static  final   Color       default_display_color = Color.red;
    static  final   Color       default_back_color = Color.black;
    static  final   Color       default_frame_color = Color.lightGray;
	static	final	String		default_date_style = "none";
	static	final	int			default_frame_width = 2;

    // Instance variables
    
                    String      font_face;
                    int         font_size;
                    
                    Color       display_color;
                    Color       back_color;
                    Color       frame_color;
                    Font        font = null;

                    int         x,y;
                    int         string_width = 0;
                    int         string_height = 0;
                    int         baseline_offset = 0;
                    int			frame_width = default_frame_width;
                    
                    String		date_style = "";
                    boolean		show_date_p = false;
                    boolean		show_am_pm_p = false;
                    boolean		relief_p = true;
                    boolean		raised_p = true;
    
    // Method:  getAppletInfo()
    //
    // Return information about the applet. 

    public String getAppletInfo() {
        return "DigitalClockApplet 1.1 by Angus McIntyre <angus@pobox.com>";
    }

    // Method: getParameterInfo()
    //
    // Return information about the applet's parameter options. Read this
    // if you want to see what parameters this applet supports.
    
    public String[][] getParameterInfo() {
        String[][] info = {
			{"time-zone",			"int",		"TZ offset in hours from Greenwich"},
            {"font",                "String",   "name of font used for display"},
            {"fontsize",            "int",      "size of font used for display"},
            {"color",               "Color",    "color used for display"},
            {"frame-color",         "Color",    "color used for frame of clock"},
            {"back-color",          "Color",    "color used for display background"},
            {"frame-width",			"int",		"width of frame around clock"},
            {"date-style",			"String",	"'us' or 'euro' - default none"},
            {"draw-in-relief",      "boolean",	"give clock a 3D look - default to true"},
            {"draw-raised",			"boolean",  "draw clock raised rather than indented"},
            {"twenty-four-hour",    "boolean",  "use 24-hour clock - default to true"},
            {"show-am-pm",          "boolean",  "show am or pm marker - default to false"},
            {"show-seconds",        "boolean",  "show seconds - default to true"}
        };
        return info;
	}

    // Method:  init()
    //
    // Initialize the digital clock. This basically consists of reading
    // a whole bunch of parameters and setting up the clock's font
    // according to any specifications given.
    
    public void init() {
        super.init();
        twenty_four_hour_p = parseBooleanParameter("twenty-four-hour",true);
        show_am_pm_p = parseBooleanParameter("show-am-pm",false);
        relief_p = parseBooleanParameter("draw-in-relief",true);
		raised_p = parseBooleanParameter("draw-raised",true);
        font_face = parseStringParameter("font",default_font_face);
        font_size = parseIntegerParameter("fontsize",default_font_size);
        frame_width = parseIntegerParameter("frame_width",default_frame_width);
        display_color = parseColorParameter("color",default_display_color);
        back_color = parseColorParameter("back-color",default_back_color);
        frame_color = parseColorParameter("frame-color",default_frame_color);
        font = new Font(font_face,Font.BOLD,font_size);
        date_style = parseStringParameter("date-style",default_date_style);
        show_date_p = ( date_style == "none" ? false : true );
    }

    // Method:  drawClock(Graphics)
    //
    // Draw the clock. This draws the clock's frame as a raised, 3D
    // rectangle, and then updates the clock display. It calls the
    // superclass method first to ensure that the time is correctly
    // set.
    
    public void drawClock (Graphics g) {
        super.drawClock(g);
        g.setColor(frame_color);
        if (relief_p)
	        g.fill3DRect(bounds().x,bounds().y,
	                     bounds().width,bounds().height,raised_p);
	  	else 
	        g.fillRect(bounds().x,bounds().y,
	                   bounds().width,bounds().height);
        updateClock(g);
    }
    
    // Method:  updateClock(Graphics)
    //
    // Update the clock display. Call the superclass method to get the
    // time correctly set, then call 'getTimeString' to convert that
    // to a string we can display.
    
    public void updateClock (Graphics g) {
        super.updateClock(g);
        String  string = getTimeString();
        
        // To draw the clock properly, we need to know some things
        // about the height and width of the string in the current
        // font. However, since the string length won't vary subsequently
        // (numbers should be fixed-width in *all* fonts, and there's no
        // mechanism to change the font or switch on/off the display of
        // seconds once the clock has started) we can get these values
        // just once and then cache them. This block does that, using
        // a FontMetrics object. In addition to the obvious business of
        // getting height and width, and setting up the point at which
        // the display is drawn (centered on the clock face) it also
        // calculates a 'baseline_offset' needed to position the text
        // properly. Drawing text isn't quite like other drawing, because
        // it's drawn *up* and to the left of the specified pen position.
        // The 'baseline_offset' takes this into account.
        
        if (string_width == 0) {
            FontMetrics metrics = g.getFontMetrics(font);
            string_width = metrics.stringWidth(string);
            string_height = metrics.getHeight();
            baseline_offset = metrics.getAscent() - string_height;
            x = ((bounds().width - string_width) / 2);
            y = ((bounds().height - string_height) / 2);
        }
        
        // Wipe out the existing text with a rectangle of the background
        // color, and then draw the new text over it.
        
        g.setColor(back_color);
        g.fillRect(x-frame_width,y-frame_width,
                   string_width+(2*frame_width),
                   string_height+(2*frame_width));
        g.setColor(display_color);
        g.setFont(font);
        g.drawString(string,x,y+string_height+baseline_offset);
    }
    
    // Method:  getTimeString()
    //
    // Return a string showing the current time as seen by this clock.
    // Appropriate conversions for the 12-hour clock are carried out,
    // and leading zeroes are inserted where needed.
    
    protected String getTimeString() {
        int hours = date.getHours();
        int minutes = date.getMinutes();
        int seconds = date.getSeconds();
        String am_pm = ( hours >= 12 ? "pm" : "am" );
        
        // Adjust for twenty-four hour clock if required
        
        if ((twenty_four_hour_p == false) && (hours > 12))
            hours -= 12;
            
        // Return the appropriate string. This is rather inefficient
        // in that it calls 'getDateString' as often as once a second
        // when strictly it only needs to be called once every twenty-four
        // hours. Still, the computation is trivial enough that it
        // shouldn't really make any odds.
        
        return ( show_date_p ? getDateString() + " " : "" ) +
        	   (hours < 10 ? "0" : "") + hours + ":" +
               (minutes < 10 ? "0" : "") + minutes +
               ( show_seconds_p ? 
                 ":" + (seconds < 10 ? "0" : "") + seconds : 
                 "") +
               ( show_am_pm_p ? am_pm : "" );
    }
    
    // Method:	getDateString()
    //
    // Get a date string. This does crude formatting according to
    // whether the user has specified 'us' or 'euro' style dates.
    // I should really use the DateFormat() class in JDK 1.1, but
    // I want this to run on older browsers.
    
    protected String getDateString() {
        int year = date.getYear();
        int month = date.getMonth();
        int day = date.getDate();
        String yearString = (year < 10 ? "0" : "") + year;
        
        if (date_style.equalsIgnoreCase("euro"))
			return (day < 10 ? "0" : "") + day + "." +
				   (month < 10 ? "0" : "") + month + "." +
				   yearString.substring(yearString.length() - 2);
		else 
			return (month < 10 ? "0" : "") + month + "/" +
				   (day < 10 ? "0" : "") + day + "/" +
				   yearString.substring(yearString.length() - 2);
	}
}
