import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.net.URL;

import javax.swing.ImageIcon;

/**
 * An <CODE>Icon</CODE> that scales its image to fill the component area, excluding any border or insets, optionally maintaining the image's
 * aspect ratio by padding and centering the scaled image horizontally or vertically.
 * <P>
 * The class is a drop-in replacement for <CODE>ImageIcon</CODE>, except that the no-argument constructor is not supported.
 * <P>
 * As the size of the Icon is determined by the size of the component in which it is displayed, <CODE>StretchIcon</CODE> must only be used
 * in conjunction with a component and layout that does not depend on the size of the component's Icon.
 *
 * @version 1.1 01/15/2016
 * @author Darryl
 */
public class StretchIcon extends ImageIcon
{
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    /**
     * Determines whether the aspect ratio of the image is maintained. Set to <code>false</code> to allow th image to distort to fill the
     * component.
     */
    protected boolean         proportionate    = true;

    /**
     * Creates a <CODE>StretchIcon</CODE> from an array of bytes.
     *
     * @param imageData an array of pixels in an image format supported by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
     *
     * @see ImageIcon#ImageIcon(byte[])
     */
    public StretchIcon(byte[] imageData)
    {
        super(imageData);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from an array of bytes with the specified behavior.
     *
     * @param imageData an array of pixels in an image format supported by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(byte[])
     */
    public StretchIcon(byte[] imageData, boolean proportionate)
    {
        super(imageData);
        this.proportionate = proportionate;
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from an array of bytes.
     *
     * @param imageData an array of pixels in an image format supported by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
     * @param description a brief textual description of the image
     *
     * @see ImageIcon#ImageIcon(byte[], java.lang.String)
     */
    public StretchIcon(byte[] imageData, String description)
    {
        super(imageData, description);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from an array of bytes with the specified behavior.
     *
     * @see ImageIcon#ImageIcon(byte[])
     * @param imageData an array of pixels in an image format supported by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
     * @param description a brief textual description of the image
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(byte[], java.lang.String)
     */
    public StretchIcon(byte[] imageData, String description, boolean proportionate)
    {
        super(imageData, description);
        this.proportionate = proportionate;
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the image.
     *
     * @param image the image
     *
     * @see ImageIcon#ImageIcon(java.awt.Image)
     */
    public StretchIcon(Image image)
    {
        super(image);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the image with the specified behavior.
     *
     * @param image the image
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(java.awt.Image)
     */
    public StretchIcon(Image image, boolean proportionate)
    {
        super(image);
        this.proportionate = proportionate;
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the image.
     *
     * @param image the image
     * @param description a brief textual description of the image
     *
     * @see ImageIcon#ImageIcon(java.awt.Image, java.lang.String)
     */
    public StretchIcon(Image image, String description)
    {
        super(image, description);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the image with the specified behavior.
     *
     * @param image the image
     * @param description a brief textual description of the image
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(java.awt.Image, java.lang.String)
     */
    public StretchIcon(Image image, String description, boolean proportionate)
    {
        super(image, description);
        this.proportionate = proportionate;
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified file.
     *
     * @param filename a String specifying a filename or path
     *
     * @see ImageIcon#ImageIcon(java.lang.String)
     */
    public StretchIcon(String filename)
    {
        super(filename);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified file with the specified behavior.
     *
     * @param filename a String specifying a filename or path
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(java.lang.String)
     */
    public StretchIcon(String filename, boolean proportionate)
    {
        super(filename);
        this.proportionate = proportionate;
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified file.
     *
     * @param filename a String specifying a filename or path
     * @param description a brief textual description of the image
     *
     * @see ImageIcon#ImageIcon(java.lang.String, java.lang.String)
     */
    public StretchIcon(String filename, String description)
    {
        super(filename, description);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified file with the specified behavior.
     *
     * @param filename a String specifying a filename or path
     * @param description a brief textual description of the image
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(java.awt.Image, java.lang.String)
     */
    public StretchIcon(String filename, String description, boolean proportionate)
    {
        super(filename, description);
        this.proportionate = proportionate;
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified URL.
     *
     * @param location the URL for the image
     *
     * @see ImageIcon#ImageIcon(java.net.URL)
     */
    public StretchIcon(URL location)
    {
        super(location);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified URL with the specified behavior.
     *
     * @param location the URL for the image
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(java.net.URL)
     */
    public StretchIcon(URL location, boolean proportionate)
    {
        super(location);
        this.proportionate = proportionate;
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified URL.
     *
     * @param location the URL for the image
     * @param description a brief textual description of the image
     *
     * @see ImageIcon#ImageIcon(java.net.URL, java.lang.String)
     */
    public StretchIcon(URL location, String description)
    {
        super(location, description);
    }

    /**
     * Creates a <CODE>StretchIcon</CODE> from the specified URL with the specified behavior.
     *
     * @param location the URL for the image
     * @param description a brief textual description of the image
     * @param proportionate <code>true</code> to retain the image's aspect ratio, <code>false</code> to allow distortion of the image to
     *            fill the component.
     *
     * @see ImageIcon#ImageIcon(java.net.URL, java.lang.String)
     */
    public StretchIcon(URL location, String description, boolean proportionate)
    {
        super(location, description);
        this.proportionate = proportionate;
    }

    /**
     * Paints the icon. The image is reduced or magnified to fit the component to which it is painted.
     * <P>
     * If the proportion has not been specified, or has been specified as <code>true</code>, the aspect ratio of the image will be preserved
     * by padding and centering the image horizontally or vertically. Otherwise the image may be distorted to fill the component it is
     * painted to.
     * <P>
     * If this icon has no image observer,this method uses the <code>c</code> component as the observer.
     *
     * @param c the component to which the Icon is painted. This is used as the observer if this icon has no image observer
     * @param g the graphics context
     * @param x not used.
     * @param y not used.
     *
     * @see ImageIcon#paintIcon(java.awt.Component, java.awt.Graphics, int, int)
     */
    @Override
    public synchronized void paintIcon(Component c, Graphics g, int x, int y)
    {
        Image image = getImage();
        if (image == null)
        {
            return;
        }
        Insets insets = ((Container) c).getInsets();
        x = insets.left;
        y = insets.top;

        int w = c.getWidth() - x - insets.right;
        int h = c.getHeight() - y - insets.bottom;

        if (proportionate)
        {
            int iw = image.getWidth(c);
            int ih = image.getHeight(c);

            if ((iw * h) < (ih * w))
            {
                iw = (h * iw) / ih;
                x += (w - iw) / 2;
                w = iw;
            }
            else
            {
                ih = (w * ih) / iw;
                y += (h - ih) / 2;
                h = ih;
            }
        }
        ImageObserver io = getImageObserver();
        g.drawImage(image, x, y, w, h, io == null ? c : io);
    }

    /**
     * Overridden to return 0. The size of this Icon is determined by the size of the component.
     *
     * @return 0
     */
    @Override
    public int getIconWidth()
    {
        return 0;
    }

    /**
     * Overridden to return 0. The size of this Icon is determined by the size of the component.
     *
     * @return 0
     */
    @Override
    public int getIconHeight()
    {
        return 0;
    }
}