package com.jidesoft.swing;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * This util class has several methods related to <code>Overlayable</code>.
 */
public class OverlayableUtils {
    /**
     * Gets the overlayable associated with this component and its parents. This method will find the first overlayable
     * that contains the component or its parents.
     *
     * @param component the component.
     * @return the overlayable.
     */
    public static Overlayable getOverlayable(JComponent component) {
        Container parent = component;
        while (true) {
            Object o = ((JComponent) parent).getClientProperty(DefaultOverlayable.CLIENT_PROPERTY_OVERLAYABLE);
            if (o instanceof Overlayable) {
                return (Overlayable) o;
            }
            parent = parent.getParent();
            if (!(parent instanceof JComponent)) {
                break;
            }
        }
        return null;
    }

    /**
     * Gets all overlayables associated with this component and its parents. Different from {@link
     * #getOverlayable(javax.swing.JComponent)}, this method will find the all overlayables that contain the component
     * or its parents.
     *
     * @param component the component
     * @return all the overlayables.
     */
    public static Overlayable[] getAllOverlayables(JComponent component) {
        List<Overlayable> list = new ArrayList<Overlayable>();
        Container parent = component;
        while (true) {
            Object o = ((JComponent) parent).getClientProperty(DefaultOverlayable.CLIENT_PROPERTY_OVERLAYABLE);
            if (o instanceof Overlayable) {
                if (!list.contains(o)) {
                    list.add((Overlayable) o);
                }
            }
            parent = parent.getParent();
            if (parent == null) {
                break;
            }
        }
        return list.toArray(new Overlayable[list.size()]);
    }

    /**
     * Repaints the overlayable component associated with component. Because the overlay component is shown above the
     * component and its child components, if any of the components repaint, the overlay component will be covered if
     * the overlay component doesn't know to repaint immediately. Due to way Swing repaintManager works, there isn't any
     * other better way to solve the issue other than the component has code to trigger the repaint of the overlay
     * component. That's one reason we provide this way to repaint the overlay component easily.
     * <p/>
     * See below for an example of how to prepare the component to be ready for the overlayable.
     * <pre><code>
     * public OverlayTextField() {
     * ...
     * public void repaint(long tm, int x, int y, int width, int height) {
     *     super.repaint(tm, x, y, width, height);
     *     OverlayableUtils.repaintOverlayable(this);
     * }
     * </code></pre>
     *
     * @param component the component that has an overlayable.
     */
    public static void repaintOverlayable(JComponent component) {
        Overlayable overlayable = getOverlayable(component);
        if (overlayable != null && overlayable instanceof Component) {
            ((Component) overlayable).repaint();
        }
    }

    /**
     * Repaints all the overlayables associated with the component or its parents.
     *
     * @param component the component.
     */
    public static void repaintAllOverlayables(JComponent component) {
        Overlayable[] overlayables = getAllOverlayables(component);
        for (Overlayable overlayable : overlayables) {
            if (overlayable != null && overlayable instanceof Component) {
                ((Component) overlayable).repaint();
            }
        }
    }

    /**
     * Gets the predefined icon that can be used as the overlay icon for the Swing component. Available icon names are
     * <ul> <li>{@link OverlayableIconsFactory#CORRECT} <li>{@link OverlayableIconsFactory#ERROR} <li>{@link
     * OverlayableIconsFactory#ATTENTION} <li>{@link OverlayableIconsFactory#INFO} <li>{@link
     * OverlayableIconsFactory#QUESTION} </ul>
     *
     * @param name name defined in {@link com.jidesoft.swing.OverlayableIconsFactory}.
     * @return the icon
     */
    public static Icon getPredefinedOverlayIcon(String name) {
        return OverlayableIconsFactory.getImageIcon(name);
    }
}
