/*
 * @(#)PaintableTools.java    2.3.5  23 February 2005
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.gui;

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
import java.beans.*;

/**
 * <p>The class <code>PaintableTools</code> collects static methods that
 * construct objects of other types from <code>Paintable</code> objects.
 * </p>
 *
 * <p>Class <code>PaintableTools</code> cannot be instantiated.</p>
 *
 * <p>In 2.3.5, the class was refactored to be consistent with
 * the new <code>Paintable</code> interface and
 * the new <code>AbstractPaintable</code> class.
 *
 * @author  Richard Rasala
 * @version 2.3.5
 * @since   2.3
 */
public class PaintableTools {

    /** Private constructor to prevent instantiation. */
    private PaintableTools() {}
    
    
    /**
     * <p>Returns a <code>Paintable</code> that wraps the given object
     * in a <code>Tile</code> object if needed.
     *
     * <p>If the given object is non-<code>null</code>, then it is
     * returned as is.</p>
     *
     * <p>If the given object is <code>null</code>, it is wrapped in a
     * <code>Tile</code>.
     *
     * <p>Since 2.3.5, the code is basically trivial but it does avoid
     * breaking certain existing code.</p>
     *
     * @param  object the object to wrap as a paintable
     * @return the associated paintable
     */
    public static Paintable wrapPaintable(Paintable object) {
        if (object != null)
            return object;
        
        return new Tile(object);
    }
    
    
    /**
     * <p>Returns an <code>Icon</code> constructed using the paint operation
     * and bounds of the given <code>Paintable</code> object.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableComponent</code>,
     * viewed as an <code>Icon</code>, or <code>null</null>.</p>
     *
     * @param paintable the paintable used in the construction
     * @return the <code>Icon</code> constructed from the paintable
     * @see #makeButton(Paintable, Action)
     * @see #makeButton(Paintable, Action, Color)
     */
    public static Icon makeIcon(Paintable paintable) {
        if (paintable == null)
            return null;
    
        return new PaintableComponent(paintable);
    }
    
    
    /**
     * <p>Returns a <code>BufferedImage</code> whose size equals the size of
     * the bounds rectangle of the given paintable and whose contents have
     * been determined by one execution of the <code>paint</code> method
     * on the graphics context of the <code>BufferedImage</code>.
     *
     * <p>In effect, this method creates a snapshot of the paintable that is
     * encapsulated in the <code>BufferedImage</code> data.  Hence, even if
     * the paintable should later change, the <code>BufferedImage</code> is
     * unaffected.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * @param paintable the paintable used in the construction
     * @return the <code>BufferedImage</code> constructed from the paintable
     * @see #makeTexturePaint(Paintable)
     */
    public static BufferedImage makeBufferedImage(Paintable paintable) {
        if (paintable == null)
            return null;
        
        Rectangle2D bounds = paintable.getBounds2D();
        int x = (int) bounds.getX();
        int y = (int) bounds.getY();
        int w = (int) bounds.getWidth();
        int h = (int) bounds.getHeight();
        
        BufferedImage b = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        
        Graphics2D g = b.createGraphics();
        g.translate(-x, -y);
        
        paintable.paint(g);
        
        return b;
    }
    
    
    /**
     * <p>Returns a <code>TexturePaint</code> whose <code>BufferedImage</code>
     * is constructed using the method <code>makeBufferedImage</code> and
     * whose anchor rectangle is the bounds rectangle of the given paintable.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * @param paintable the paintable used in the construction
     * @return the <code>TexturePaint</code> constructed from the paintable
     * @see #makeBufferedImage(Paintable)
     */
    public static TexturePaint makeTexturePaint(Paintable paintable) {
        if (paintable == null)
            return null;
        
        return new TexturePaint(
            makeBufferedImage(paintable), paintable.getBounds2D());
    }
    
    
    /**
     * <p>Returns a <code>JButton</code> using
     * the given <code>Paintable</code> to construct the button icon,
     * no specified action for the button behavior,
     * the Java default background color,
     * and insets of 2, 2, 2, 2.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableButton</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable that defines the button
     * @return the button constructed from the paintable
     * @see #makeIcon(Paintable)
     * @see #makeButton(Paintable, Action)
     * @see #makeButton(Paintable, Action, Color)
     * @see #makeButton(Paintable, Action, Color, Insets)
     */
    public static JButton makeButton(Paintable paintable) {
        return makeButton(paintable, null, null, null);
    }
    
    
    /**
     * <p>Returns a <code>JButton</code> using
     * the given <code>Paintable</code> to construct the button icon,
     * the given <code>Action</code> for the button behavior,
     * the Java default background color,
     * and insets of 2, 2, 2, 2.</p>
     *
     * <p>The action is used only to supply behavior not to set the
     * button icon or text.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableButton</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable that defines the button
     * @param action    the action to define the button behavior
     * @return the button constructed from the paintable
     * @see #makeIcon(Paintable)
     * @see #makeButton(Paintable)
     * @see #makeButton(Paintable, Action, Color)
     * @see #makeButton(Paintable, Action, Color, Insets)
     */
    public static JButton makeButton(Paintable paintable, Action action) {
        return makeButton(paintable, action, null, null);
    }
    
    
    /**
     * <p>Returns a <code>JButton</code> using
     * the given <code>Paintable</code> to construct the button icon,
     * the given <code>Action</code> for the button behavior,
     * the given background color,
     * and insets of 2, 2, 2, 2.</p>
     *
     * <p>The action is used only to supply behavior not to set the
     * button icon or text.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableButton</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable that defines the button
     * @param action    the action to define the button behavior
     * @param color     the button background color
     * @return the button constructed from the paintable
     * @see #makeIcon(Paintable)
     * @see #makeButton(Paintable)
     * @see #makeButton(Paintable, Action)
     * @see #makeButton(Paintable, Action, Color, Insets)
     */
    public static JButton makeButton
        (final Paintable paintable, Action action, final Color color)
    {
        return makeButton(paintable, action, color, null);
    }
    
    
    /**
     * <p>Returns a <code>JButton</code> using
     * the given <code>Paintable</code> to construct the button icon,
     * the given <code>Action</code> for the button behavior,
     * the given background color,
     * and the given insets.</p>
     *
     * <p>The action is used only to supply behavior not to set the
     * button icon or text.</p>
     *
     * <p>If the given insets is <code>null</code>, then the insets
     * are set to 2, 2, 2, 2.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableButton</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable that defines the button
     * @param action    the action to define the button behavior
     * @param color     the button background color
     * @param insets    the button insets
     * @return the button constructed from the paintable
     * @see #makeIcon(Paintable)
     * @see #makeButton(Paintable)
     * @see #makeButton(Paintable, Action)
     * @see #makeButton(Paintable, Action, Color)
     */
    public static JButton makeButton(
        final Paintable paintable,
        final Action    action,
        final Color     color,
        final Insets    insets)
    {
        if (paintable == null)
            return null;
    
        return new PaintableButton(paintable, action, color, insets);
    }
    
    
    /**
     * <p>Returns a <code>JPTComponent</code> using the given
     * <code>Paintable</code> to define its location and paint
     * behavior.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableComponent</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable to encapsulate
     * @return the component constructed from the paintable
     * @see #makeComponent(Paintable, Color)
     * @see #makeComponent(Paintable, Color, boolean)
     * @see #makeComponent(Paintable, Color, boolean, Border)
     */
    public static JPTComponent makeComponent(Paintable paintable) {
        return makeComponent(paintable, null, false, null);
    }
    
    
    /**
     * <p>Returns a <code>JPTComponent</code> using the given
     * <code>Paintable</code> to define its location and paint
     * behavior
     * and the optional background color.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableComponent</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable to encapsulate
     * @param color     the optional background color
     * @return the component constructed from the paintable
     * @see #makeComponent(Paintable)
     * @see #makeComponent(Paintable, Color, boolean)
     * @see #makeComponent(Paintable, Color, boolean, Border)
     */
    public static JPTComponent makeComponent
        (Paintable paintable, Color color)
    {
        return makeComponent(paintable, color, false, null);
    }
    
    
    /**
     * <p>Returns a <code>JPTComponent</code> using the given
     * <code>Paintable</code> to define its location and paint
     * behavior,
     * the optional background color,
     * and the opacity setting.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableComponent</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable to encapsulate
     * @param color     the optional background color
     * @param opaque    whether or not to paint the component background
     * @return the component constructed from the paintable
     * @see #makeComponent(Paintable)
     * @see #makeComponent(Paintable, Color)
     * @see #makeComponent(Paintable, Color, boolean, Border)
     */
    public static JPTComponent makeComponent
        (Paintable paintable, Color color, boolean opaque)
    {
        return makeComponent(paintable, color, opaque, null);
    }
    
    
    /**
     * <p>Returns a <code>JPTComponent</code> using the given
     * <code>Paintable</code> to define its location and paint
     * behavior,
     * the optional background color,
     * the opacity setting,
     * and the component border.</p>
     *
     * <p>If the given paintable is <code>null</code>, then returns
     * <code>null</code>.
     *
     * <p>As of 2.3.2, this method returns a <code>PaintableComponent</code>
     * or <code>null</null>.</p>
     *
     * @param paintable the paintable to encapsulate
     * @param color     the optional background color
     * @param opaque    whether or not to paint the component background
     * @param border    the border for the component
     * @return the component constructed from the paintable
     * @see #makeComponent(Paintable)
     * @see #makeComponent(Paintable, Color)
     * @see #makeComponent(Paintable, Color, boolean)
     */
    public static JPTComponent makeComponent
        (Paintable paintable, Color color, boolean opaque, Border border)
    {
        if (paintable == null)
            return null;
        
        return new PaintableComponent(paintable, color, opaque, border);
    }
    
}
