//******************************************************************************
// BinclockApp.java:    Applet
//
//******************************************************************************
import java.applet.*;
import java.awt.*;
import java.util.Calendar;
import BinclockAppFrame;

//==============================================================================
// Main Class for applet BinclockApp
//
//==============================================================================
public class BinclockApp extends Applet implements Runnable
{
        private Calendar now, newnow;
        private Image backBuffer;
        private Graphics bg;
        private Font font;
        private String decimalTime;
        int x;
        int y;

        // THREAD SUPPORT:
        // m_BinclockApp        is the Thread object for the applet
        //--------------------------------------------------------------------------
        private Thread   clockThread = null;

        // STANDALONE APPLICATION SUPPORT:
        // m_fStandAlone will be set to true if applet is run standalone
        //--------------------------------------------------------------------------
        private boolean  m_fStandAlone = false;

        // STANDALONE APPLICATION SUPPORT
        // The main() method acts as the applet's entry point when it is run
        // as a standalone application. It is ignored if the applet is run from
        // within an HTML page.
        //--------------------------------------------------------------------------

        public static void main(String args[])
        {
                // Create Toplevel Window to contain applet BinclockApp
                //----------------------------------------------------------------------
                BinclockAppFrame frame = new BinclockAppFrame("Binary Clock");

                frame.setBounds(100, 100, 330, 330);

                // The following code starts the applet running within the frame window.
                // It also calls GetParameters() to retrieve parameter values from the
                // command line, and sets m_fStandAlone to true to prevent init() from
                // trying to get them from the HTML page.
                //----------------------------------------------------------------------
                BinclockApp applet_BinclockApp = new BinclockApp();

                // Must show Frame before we size it so getInset() will return valid values
                //----------------------------------------------------------------------
                frame.show();

                frame.add("Center", applet_BinclockApp);
                applet_BinclockApp.m_fStandAlone = true;

                applet_BinclockApp.init();
                applet_BinclockApp.start();
                frame.show();
        }

        // BinclockApp Class Constructor
        //--------------------------------------------------------------------------
        public BinclockApp()
        {
        // TODO: Add constructor code here
        // global variables
        }

        // APPLET INFO SUPPORT:
        // The getAppletInfo() method returns a string describing the applet's
        // author, copyright date, or miscellaneous information.
        //--------------------------------------------------------------------------
        public String getAppletInfo()
        {
                return "Name: Binclock\r\n" +
                       "Author: David Binard (mailto:binard@california.com)\r\n" +
                       "Date: 08/20/98\r\n" +
                       "Description: Binary Clock Animation\r\n" +
                       "Created with Microsoft Visual J++ Version 1.1\r\n" +
                       "Reactualized for Sun's JDK 1.1.7";
        }


        // The init() method is called by the AWT when an applet is first loaded or
        // reloaded.  Override this method to perform whatever initialization your
        // applet needs, such as initializing data structures, loading images or
        // fonts, creating frame windows, setting the layout manager, or adding UI
        // components.
        //--------------------------------------------------------------------------
        public void init()
        {
        // If you use a ResourceWizard-generated "control creator" class to
        // arrange controls in your applet, you may want to call its
        // CreateControls() method from within this method. Remove the following
        // call to setSize() before adding the call to CreateControls();
        // CreateControls() does its own resizing.
        //----------------------------------------------------------------------
        setSize(getSize().width, getSize().height);
	font = new Font("Helvetica", Font.PLAIN, 11);
        try {
                backBuffer = createImage(getSize().width, getSize().height); 
                bg = backBuffer.getGraphics(); 
        }
        catch (Exception e) {
                bg = null;
        };

                // TODO: Place additional initialization code here
        }

        // Place additional applet clean up code here.  destroy() is called when
        // when you applet is terminating and being unloaded.
        //-------------------------------------------------------------------------
        public void destroy()
        {
                // TODO: Place applet cleanup code here
        }


        // The start() method is called when the page containing the applet
        // first appears on the screen. The AppletWizard's initial implementation
        // of this method starts execution of the applet's thread.
        //--------------------------------------------------------------------------
        public void start()
        {
                now = Calendar.getInstance();
                newnow = Calendar.getInstance();
                if (clockThread == null) {
                        clockThread = new Thread(this, "Binclock");
                        clockThread.start();
                }
                // TODO: Place additional applet start code here
        }
        
        // The stop() method is called when the page containing the applet is
        // no longer on the screen. The AppletWizard's initial implementation of
        // this method stops execution of the applet's thread.
        //--------------------------------------------------------------------------
        public void stop()
        {
                if (clockThread != null)
                {
                        clockThread.stop();
                        clockThread = null;
                }

                // TODO: Place additional applet stop code here
        }

        // THREAD SUPPORT
        // The run() method is called when the applet's thread is started. If
        // your applet performs any ongoing activities without waiting for user
        // input, the code for implementing that behavior typically goes here. For
        // example, for an applet that performs animation, the run() method controls
        // the display of images.
        //--------------------------------------------------------------------------
        public void run() {
                // loop terminates when clockThread is set to null in stop()
                while (Thread.currentThread() == clockThread) {
                        repaint();
                        // loop until the time changes by one second
                        // the sleeps are here to reduce CPU usage
                        while (now.get(Calendar.SECOND) == newnow.get(Calendar.SECOND)) {
                                try {
                                        clockThread.sleep(200);
                                } catch (Exception e) {
                                };
                                newnow = Calendar.getInstance();
                        }
                }
        }

        // TODO: Place additional applet code here

        private void repaintClock(Graphics g)
        {
                now = Calendar.getInstance();
                int hours = now.get(Calendar.HOUR_OF_DAY);
                int mins = now.get(Calendar.MINUTE);
                int secs = now.get(Calendar.SECOND);
                decimalTime = lpad(hours) + ":" + lpad(mins) + ":" + lpad(secs);
                String hourBits = calc_bits(hours);
                String minBits = calc_bits(mins);
                String secBits = calc_bits(secs);
                // Clear Background 
                g.setColor(Color.white);
                g.fillRect(0, 0, getSize().width, getSize().height); 
                // Draw Clock
		g.setFont(font);
                g.setColor(Color.black);
                x = 45;
                y = 225;
                g.drawString("Hours", x + 80, y);
                g.drawString("Minutes", x + 135, y);
                g.drawString("Seconds", x + 192, y);
                y += 15;
                g.drawString("Decimal time", x, y);
                y += 15;
                g.drawString("Octal time", x, y);
                y += 15;
                g.drawString("Hex time", x, y);
                y += 15;
                g.drawString("Binary time", x, y);
                g.setColor(Color.blue);
                y -= 45;
                g.drawString(lpad(hours), x + 88, y);
                g.drawString(lpad(mins), x + 148, y);
                g.drawString(lpad(secs), x + 208, y);
                y += 15;
                g.drawString(to_octal(hours), x + 88, y);
                g.drawString(to_octal(mins), x + 148, y);
                g.drawString(to_octal(secs), x + 208, y);
                y += 15;
                g.drawString(to_hex(hours), x + 88, y);
                g.drawString(to_hex(mins), x + 148, y);
                g.drawString(to_hex(secs), x + 208, y);
                y += 15;
                g.drawString(hourBits, x + 70, y);
                g.drawString(minBits, x + 130, y);
                g.drawString(secBits, x + 190, y);
                x = 5;
                y = 5;
                drawBits(hourBits, g, x, y);
                y += 70;
                drawBits(minBits, g, x, y);
                y += 70;
                drawBits(secBits, g, x, y);
                y += 70;
        }

        private void drawBits(String bits, Graphics g, int x, int y)
        {
                for (int i = 0; i < 8; i++) {
                        if (bits.charAt(i) == '0') {
                                g.setColor(Color.cyan);
                        } else {
                                g.setColor(Color.blue);
                        }
                        g.fillRect(x, y, 30, 60);
                        x += 40;
                }
        }

        public void update(Graphics g)
        {
                if (bg == null)   // no backgound buffer 
                        repaintClock(g); 
                else { 
                        repaintClock(bg); 
                        g.drawImage(backBuffer,0,0,this);
                        showStatus("Decimal time: " + decimalTime);
                }
        } 

        public String calc_bits(int value) {
                int bit, filter = 32;
                StringBuffer bitString = new StringBuffer("00");
                for (bit = 3; bit <= 8; bit++) {
                        if (value >= filter) {
                                bitString.append('1');
                                value -= filter;
                        }
                        else {
                                bitString.append('0');
                        }
                        filter = filter - (filter / 2);
                }
                return bitString.toString();
        }

        public String lpad(int value) {
                String mystring = "00";
                if (value <= 9) {
                mystring = "0" + Integer.toString(value);
                }
                else {
                        mystring = Integer.toString(value);
                }
                return mystring;
        }

        public String to_octal(int value) {
                String octal = (value / 8) + "" + (value % 8);
                return octal;
        }

        public String to_alpha_hex(int value) {
                if (value < 10)
                        return Integer.toString(value);
                else if (value == 10)
                        return "A";
                else if (value == 11)
                        return "B";
                else if (value == 12)
                        return "C";
                else if (value == 13)
                        return "D";
                else if (value == 14)
                        return "E";
                else if (value == 15)
                        return "F";
                else
                        return "0";
        }
        
        public String to_hex(int value) {
                String hex = to_alpha_hex(value / 16) + "" + to_alpha_hex(value % 16);
                return hex;
        }
}
