package widget;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;

import java.awt.Panel;

/**
 * The parent class of all GUI components/widgets
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public abstract class Widget extends    Panel
			     implements FocusListener
{
    protected boolean            doubleBuffered = true;
    protected boolean            hasFocus = false;
    protected Graphics           bufferedGraphics;
    protected Image              bufferedImage;


    /**
     * Default Constructor
     */
    public Widget()
    {
	super();
    }




    /**
     * Process a focusGained event
     *
     * @param evt   The FocusEvent
     */
    public void focusGained(FocusEvent evt)
    {
	if (!evt.isTemporary()) setHasFocus(true);
    }




    /**
     * Process a focusLost event
     *
     * @param evt   The FocusEvent
     */
    public void focusLost(FocusEvent evt)
    {
	if (!evt.isTemporary()) setHasFocus(false);
    }





    /**
     * Get a color for this widget/Component
     *
     * @param part   The part of the component (e.g., BORDER)
     * @param state  The state (e.g., DISABLED)
     * @return       The Color
     */
    public Color getColor(int part, int state)
    {
	return getView().getColor(part, state);
    }


    /**
     * Get the model associated with this component/Widget
     *
     * @return    The model
     */
    public abstract WidgetModel getModel();



    /**
     * Get the view associated with this component/Widget
     *
     * @return    The view
     */
    public abstract WidgetView getView();







    /**
     * Get the minimum amount of size required by this
     * component/Widget
     *
     * @return    The minimum required size
     */
    public Dimension getMinimumSize()
    {
	return getView().getMinimumSize();
    }



    /**
     * Get the preferred size for this component/Widget
     *
     * @return  The minimum required size
     */
    public Dimension getPreferredSize()
    {
	return getMinimumSize();
    }



    /**
     * Does this component/Widget have the focus?
     *
     * @return  true if the component has the focus
     */
    public boolean hasFocus()
    {
	return hasFocus;
    }





    /**
     * Is the component/Widget capable of having the focus?
     *
     * @return  true if the component can/should get the focus
     */
    public boolean isFocusTraversable()
    {
	return true;
    }







    /**
     * Paint this component/Widget
     *
     * @param g  The Graphics context to use
     */
    public void paint(Graphics g)
    {
	if (doubleBuffered) 
        {
	    if ( (bufferedImage == null) || 
		 (getSize().width  != bufferedImage.getWidth(null)) || 
		 (getSize().height != bufferedImage.getHeight(null))   )
            {
		bufferedImage = createImage(getSize().width, 
					    getSize().height);

		bufferedGraphics = bufferedImage.getGraphics();
	    }

	    bufferedGraphics.setFont(g.getFont());
	    getView().paint(bufferedGraphics);
	    g.drawImage(bufferedImage, 0, 0, null);
	} 
        else 
        {
	    getView().paint(g);
	}
    }





    /**
     * Pause (i.e., sleep) for the specified amount of time
     *
     * @param   millis   The number of millseconds to pause
     */
    public void pause(int millis)
    {
	try 
        {
	    Thread.sleep(millis);
	} 
        catch (InterruptedException ie) 
        {
	    // Ignore
	}
    }



    /**
     * Set a color for this widget/Component
     *
     * @param part   The part of the component (e.g., BORDER_COLOR)
     * @param state  The state (e.g., DISABLED_COLOR)
     * @param color  The Color
     */
    public void setColor(int part, int state, Color color)
    {
	getView().setColor(part, state, color);
    }



    /**
     * Set whether this component has the focus
     *
     * @param hasFocus     true if it has the focus, false otherwise
     */
    public void setHasFocus(boolean hasFocus)
    {
	this.hasFocus = hasFocus;
	repaint();
    }



    /**
     * Set the height of this component/Widget
     *
     * @param height  The height (in pixels)
     */
    public void setHeight(int height)
    {
	getView().setHeight(height);
    }






    /**
     * Setup the event handlers for this Widget
     */
    public void setupEventHandlers()
    {
	addFocusListener(this);
	requestFocus();
    }



    /**
     * Update this component
     *
     * @param g   The Graphics context
     */
    public void update(Graphics g)
    {
	paint(g);
    }
}
