/********************************************************************************/
/*     code by Janette Duvall  Copyright 1998        Version 2
/*
/*     This applet draws a happy face on the screen.  It will not resize the
/*     face when the window is resized.  Note how all the dimensions are constant.
/*                             int     diameter = 200;
/*     It is possible to draw the face so it always fills the window.
/*
/*       This version also animates the happy face.
/*   I am also animating a string.
/*
/*     Object Oriented designs are supposed to eliminate the need for globals but
/*          there they are.  All globals begin with a capital letter so they are easy
/*    to keep track of in the code.
/********************************************************************************/

import java.awt.*;

public class HappyFaceV2 extends java.applet.Applet implements Runnable
{
        Thread        FaceThread;
        Image         OffScreenImg;
        Graphics      OffScreenG;
        int           TheBlink;
        boolean       LeftEye;
        int           MouthStart;
        int           Dir;
        int           Animate_What;
        Color         MyColor;

        Font          TheFont;
        FontMetrics   TheMetrics;
        int           X_Pos, Y_Pos;
        int           WinWidth, WinHt;
        String        Str = "The Happy Face is Winking";
        int           StrLen;
        int           Loops;
        boolean       InWindow;

        public void init()
        {
                // set up the parts for animation

                // the face
                TheBlink = 0;
                LeftEye = true;
                Loops = 0;
                MouthStart = 30;
                Dir = -1;
                Animate_What = 1;
                MyColor = Color.yellow;
                InWindow = false;

                // the text
                try
                {
                        TheFont = new Font( "Times", Font.BOLD, 36 );
                }
                catch   (Exception e)
                {
                        // not throwing anytthing back
                        System.out.println("Font didn't set");
                }
                TheMetrics = getFontMetrics( TheFont );
                StrLen = TheMetrics.stringWidth( Str );

                // the other things
                WinWidth = size().width;
                WinHt = size().height;
                Y_Pos = WinHt - TheMetrics.getHeight() - 10;
                X_Pos = WinWidth;

                // the buffering - a chunk of memory the size of the screen
                // (or the size of the piece we work with)
                OffScreenImg = createImage( WinWidth, WinHt );

                // connect a graphics device to it
                OffScreenG = OffScreenImg.getGraphics();
        }

        public void start()
        {

                if (FaceThread == null)
                {
                        FaceThread = new Thread(this);
                        FaceThread.start();
                }
        }

        public void run()
        {
                int margin = 10;

                while (true)
                {
                        // set up the eye for blinking  (it needs to blink a little slower)
                        if ( Loops >= 5 )
                        {
                                if ( TheBlink++ > margin )
                                {
                                        TheBlink = - TheBlink;
                                        LeftEye = !LeftEye;
                                        MyColor = nextColor(MyColor);
                                }

                                Loops = 0;
                        }

                        // change the mouth ends
                        if ( MouthStart > 30 || MouthStart - 180 < -210 )
                                Dir = -Dir;
                        MouthStart += Dir;
                        //System.out.println(+ MouthStart);

                        // now do the text
                        if ( --X_Pos <= -StrLen )
                        {
                                X_Pos = WinWidth;
                        }

                        repaint();
                        try
                        {
                                Thread.sleep( 5 );
                                Loops++;
                        }
                        catch ( InterruptedException e )
                        {
                                System.out.println( " interrupt execption error " + e );
                        }
                }
        }

        public void stop()
        {
                if ( FaceThread != null )
                {
                        FaceThread.stop();
                        FaceThread = null;
                }
         }

         public boolean mouseEnter(Event evt, int x, int y)
         {
                InWindow = true;
                repaint();

                return true;
         }

         public boolean mouseExit(Event evt, int x, int y)
         {
                InWindow = false;
                repaint();

                return true;
         }

         public void update (Graphics g)
         {
                paint( g );
         }

         public void paint (Graphics g)
         {
                // define some integers to do some math
                int             diameter = 200;
                int             margin = 10;
                int             eyeHt, eyeWidth;
                int             thisX, thisY;
                int             i;

                // calculate some centering info
                thisX = ( WinWidth - diameter ) / 2;
                thisY = ( WinHt - 100 - diameter ) / 2;

                // first set the color and draw the circle
                OffScreenG.setColor(MyColor);
                OffScreenG.fillOval( thisX, thisY, diameter, diameter );

                // draw an outline
                OffScreenG.setColor( Color.black );
                OffScreenG.drawOval( thisX, thisY, diameter, diameter );

                // now the eyes
                // Calculate where they go
                eyeHt = diameter / 4;
                eyeWidth =  diameter / 3;

                //draw the eyes
                OffScreenG.fillOval( eyeWidth+thisX, eyeHt+thisY, margin, margin*2 );
                OffScreenG.fillOval( eyeWidth*2+thisX, eyeHt+thisY, margin, margin*2 );

                // set things up for the mouth by redrawing the circle in the mouth area
                OffScreenG.setColor( MyColor );
                int     mouthX = eyeWidth - (2 * margin) + thisX - 1;
                int       mouthY = eyeHt * 2 + 2 + thisY;
                OffScreenG.fillOval( mouthX, mouthY, eyeWidth + 4*margin,
                                eyeWidth*2/3+2*margin );
                OffScreenG.setColor( Color.black );

                // now the mouth -- draw it as fat as the eye
                // can't find the documentation on pen width
                for ( i = 1; i <= margin/2; i++)
                {
                        mouthY = eyeHt * 2 + i + thisY;
                        if ( InWindow )
                                OffScreenG.drawArc( mouthX, mouthY,
                                        eyeWidth + 4*margin, eyeWidth*2/3 + 2*margin,
                                        MouthStart, -180 );
                        if ( !InWindow )
                                OffScreenG.drawArc( mouthX, mouthY,
                                        eyeWidth + 4*margin, eyeWidth*2/3 + 2*margin,
                                        MouthStart, 180 );
                }

                // draw the blink
                OffScreenG.setColor( MyColor );
                if ( LeftEye == true )
                        OffScreenG.fillOval( eyeWidth-1+thisX, eyeHt-1+thisY,
                                        margin+2, TheBlink*2+2 );
                else
                        OffScreenG.fillOval( eyeWidth*2+thisX-1, eyeHt-1+thisY,
                                        margin+2, TheBlink*2+2 );

                // Now do the text at the bottom of the screen
                OffScreenG.setColor( Color.white );
                OffScreenG.fillRect( 0, WinHt-75, WinWidth, WinHt);
                OffScreenG.setColor(MyColor);
                OffScreenG.drawString( Str, X_Pos, Y_Pos );

                // we have been drawing off screen  Now splat the screen
                g.drawImage( OffScreenImg, 0, 0, this);

         }

         Color nextColor(Color thisColor)
         {
                if ( thisColor == Color.yellow )
                        return (Color.red);
                if ( thisColor == Color.red )
                        return (Color.green);
                if ( thisColor == Color.green )
                        return (Color.blue);
                if ( thisColor == Color.blue )
                        return (Color.magenta);
                if ( thisColor == Color.magenta)
                        return (Color.yellow);

                return (Color.yellow);
         
         }
}



