/*
 * Created on Feb 27, 2005
 */
package org.flexdock.plaf.theme;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;

import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.border.Border;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.UIResource;

import org.flexdock.plaf.FlexViewComponentUI;
import org.flexdock.plaf.icons.IconMap;
import org.flexdock.plaf.icons.IconResource;
import org.flexdock.plaf.icons.IconResourceFactory;
import org.flexdock.plaf.resources.paint.Painter;
import org.flexdock.view.Button;
import org.flexdock.view.Titlebar;
import org.flexdock.view.View;

/**
 * @author Christopher Butler
 */
public class TitlebarUI extends FlexViewComponentUI {

    public static final String DEFAULT_HEIGHT = "default.height";
    public static final String FONT = "font";
    public static final String FONT_COLOR = "font.color";
    public static final String FONT_COLOR_ACTIVE = "font.color.active";
    public static final String BACKGROUND_COLOR = "bgcolor";
    public static final String BACKGROUND_COLOR_ACTIVE = "bgcolor.active";
    public static final String BORDER = "border";
    public static final String BORDER_ACTIVE = "border.active";
    public static final String PAINTER = "painter";
    public static final String INSETS = "insets";
    private static final String BUTTON_MARGIN = "button.margin";
    public static final String ICON_INSETS = "icon.insets";
    public static final String ANTIALIASING = "antialiasing";
    public static final int MINIMUM_HEIGHT = 12;

    protected Font font;
    protected Color activeFont;
    protected Color inactiveFont;
    protected Color activeBackground;
    protected Color inactiveBackground;
    protected Border activeBorder;
    protected Border inactiveBorder;
    protected IconMap defaultIcons;
    protected Painter painter;
    protected Insets insets;
    protected int buttonMargin;
    protected Insets iconInsets;
    protected Object antialiasing;
    protected int defaultHeight = MINIMUM_HEIGHT;


    public void installUI(JComponent c) {
        super.installUI(c);
        Dimension d = c.getPreferredSize();
        d.height = getDefaultHeight();
        c.setPreferredSize(d);

        reconfigureActions(c);

        if (font != null) {
            Font current = c.getFont();

            if (current == null || current instanceof UIResource) {
                c.setFont(new FontUIResource(font));
            }
        }
    }

    public void uninstallUI(JComponent c) {
        super.uninstallUI(c);
    }

    public void paint(Graphics g, JComponent jc) {
        Titlebar titlebar = (Titlebar) jc;
        paintBackground(g, titlebar);
        paintIcon(g, titlebar);
        paintTitle(g, titlebar);
        paintBorder(g, titlebar);
    }

    protected void paintBackground(Graphics g, Titlebar titlebar) {
        Rectangle paintArea = getPaintRect(titlebar);
        g.translate(paintArea.x, paintArea.y);
        painter.paint(g, paintArea.width, paintArea.height, titlebar.isActive(), titlebar);
        g.translate(-paintArea.x, -paintArea.y);
    }

    protected Rectangle getPaintRect(Titlebar titlebar) {
        if (getInsets() == null)
            return new Rectangle(0, 0, titlebar.getWidth(), titlebar.getHeight());

        Insets paintInsets = getInsets();
        return new Rectangle(paintInsets.left, paintInsets.top,
                             (titlebar.getWidth() - paintInsets.right - paintInsets.left), (titlebar.getHeight()
                                     - paintInsets.bottom - paintInsets.top));
    }

    protected void paintTitle(Graphics g, Titlebar titlebar) {
        if (titlebar.getText() == null)
            return;

        Graphics2D g2 = (Graphics2D) g;
        Object oldAAValue = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antialiasing);

        g2.setFont(titlebar.getFont());
        Rectangle iconRect = getIconRect(titlebar);
        Rectangle paintRect = getPaintRect(titlebar);

        int x = getTextLocation(iconRect);

        //Center text vertically.
        FontMetrics fm = g.getFontMetrics();
        int y = (paintRect.height + fm.getAscent() - fm.getLeading() -
                 fm.getDescent()) / 2;

        Color c = getFontColor(titlebar.isActive());
        g2.setColor(c);
        g.translate(paintRect.x, paintRect.y);
        g2.drawString(titlebar.getText(), x, y);
        g.translate(-paintRect.x, -paintRect.y);


        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAAValue);
    }

    protected int getTextLocation(Rectangle iconRect) {
        if (iconRect.width > 0)
            return iconRect.x + iconRect.width + getRightIconMargin();
        return 5;
    }

    protected void paintIcon(Graphics g, Titlebar titlebar) {
        if (titlebar.getIcon() == null)
            return;

        Icon icon = titlebar.getIcon();
        Rectangle r = getIconRect(titlebar);

        Rectangle paintRect = getPaintRect(titlebar);
        g.translate(paintRect.x, paintRect.y);
        icon.paintIcon(titlebar, g, r.x, r.y);
        g.translate(-paintRect.x, -paintRect.y);
    }

    protected Rectangle getIconRect(Titlebar titlebar) {
        Icon icon = titlebar.getIcon();
        Rectangle r = new Rectangle(0, 0, 0, 0);
        if (icon == null)
            return r;

        Rectangle paintRect = getPaintRect(titlebar);

        r.x = getLeftIconMargin();
        r.width = icon.getIconWidth();
        r.height = icon.getIconHeight();
        r.y = (paintRect.height - r.height) / 2;
        return r;
    }

    protected int getLeftIconMargin() {
        return getIconInsets() == null ? 2 : getIconInsets().right;
    }

    protected int getRightIconMargin() {
        return getIconInsets() == null ? 2 : getIconInsets().right;
    }

    protected void paintBorder(Graphics g, Titlebar titlebar) {
        Border border = getBorder(titlebar);
        if (border != null) {
            Rectangle rectangle = getPaintRect(titlebar);
            g.translate(rectangle.x, rectangle.y);
            border.paintBorder(titlebar, g, 0, 0, rectangle.width, rectangle.height);
            g.translate(-rectangle.x, -rectangle.y);
        }
    }

    public void layoutComponents(Titlebar titlebar) {
        Rectangle rectangle = getPaintRect(titlebar);
        int margin = getButtonMargin();
        int h = rectangle.height - 2 * margin;
        int x = rectangle.width - margin - h;

        View view = titlebar.getView();
        Component[] c = titlebar.getComponents();
        for (int i = 0; i < c.length; i++) {
            // start out with the preferred width
            int width = c[i].getPreferredSize().width;
            if (c[i] instanceof Button) {
                // org.flexdock.view.Buttons will be rendered as squares
                width = h;
                // don't show the button if its corresponding action is blocked
                if(view!=null && view.isActionBlocked(((Button) c[i]).getActionName())) {
                    c[i].setBounds(0, 0, 0, 0);
                    continue;
                }
            }
            // layout the component over to the right
            c[i].setBounds(x, margin + rectangle.y, width, h);
            // move x to the left for the next component
            x -= width;
        }
    }

    public void configureAction(Action action) {
        if (action == null)
            return;

        IconResource icons = getIcons(action);
        if (icons != null) {
            action.putValue(ICON_RESOURCE, icons);
        }
    }

    private void reconfigureActions(JComponent c) {
        Component[] c1 = c.getComponents();
        for (int i = 0; i < c1.length; i++) {
            if (!(c1[i] instanceof Button))
                continue;
            Button b = (Button) c1[i];
            configureAction(b.getAction());
        }
    }

    protected Color getFontColor(boolean active) {
        Color c = active ? activeFont : inactiveFont;
        return c == null ? inactiveFont : c;
    }

    protected Color getBackgroundColor(boolean active) {
        Color color = active ? activeBackground : inactiveBackground;
        return color == null ? inactiveBackground : color;
    }

    protected Border getBorder(Titlebar titlebar) {
        boolean active = titlebar.isActive();
        return active ? activeBorder : inactiveBorder;
    }

    public int getDefaultHeight() {
        return defaultHeight;
    }

    public void setDefaultHeight(int defaultHeight) {
        defaultHeight = Math.max(defaultHeight, MINIMUM_HEIGHT);
        this.defaultHeight = defaultHeight;
    }

    public Dimension getPreferredSize() {
        return new Dimension(10, getDefaultHeight());
    }

    /**
     * @return Returns the activeBackground.
     */
    public Color getActiveBackground() {
        return activeBackground;
    }

    /**
     * @param activeBackground
     *            The activeBackground to set.
     */
    public void setActiveBackground(Color activeBackground) {
        this.activeBackground = activeBackground;
    }

    /**
     * @return Returns the activeFont.
     */
    public Color getActiveFont() {
        return activeFont;
    }

    /**
     * @param activeFont
     *            The activeFont to set.
     */
    public void setActiveFont(Color activeFont) {
        this.activeFont = activeFont;
    }

    /**
     * @return Returns the inactiveBackground.
     */
    public Color getInactiveBackground() {
        return inactiveBackground;
    }

    /**
     * @param inactiveBackground
     *            The inactiveBackground to set.
     */
    public void setInactiveBackground(Color inactiveBackground) {
        this.inactiveBackground = inactiveBackground;
    }

    /**
     * @return Returns the inactiveFont.
     */
    public Color getInactiveFont() {
        return inactiveFont;
    }

    /**
     * @param inactiveFont
     *            The inactiveFont to set.
     */
    public void setInactiveFont(Color inactiveFont) {
        this.inactiveFont = inactiveFont;
    }

    /**
     * @return Returns the font.
     */
    public Font getFont() {
        return font;
    }

    /**
     * @param font
     *            The font to set.
     */
    public void setFont(Font font) {
        this.font = font;
    }

    public IconMap getDefaultIcons() {
        return defaultIcons;
    }

    public void setDefaultIcons(IconMap defaultIcons) {
        this.defaultIcons = defaultIcons;
    }

    public void setDefaultIcons(String iconMapName) {
        IconMap map = IconResourceFactory.getIconMap(iconMapName);
        setDefaultIcons(map);
    }

    public IconResource getIcons(Action action) {
        String key = action == null ? null : (String) action.getValue(Action.NAME);
        return getIcons(key);
    }

    public IconResource getIcons(String key) {
        return defaultIcons == null ? null : defaultIcons.getIcons(key);
    }

    public Action getAction(String actionKey) {
        IconResource resource = getIcons(actionKey);
        Action action = resource==null? null: resource.getAction();
        if(action!=null)
            action.putValue(Action.NAME, actionKey);
        return action;
    }

    /**
     * @return Returns the inactiveBorder.
     */
    public Border getInactiveBorder() {
        return inactiveBorder;
    }

    /**
     * @param inactiveBorder
     *            The inactiveBorder to set.
     */
    public void setInactiveBorder(Border inactiveBorder) {
        this.inactiveBorder = inactiveBorder;
    }

    /**
     * @return Returns the activeBorder.
     */
    public Border getActiveBorder() {
        return activeBorder;
    }

    /**
     * @param activeBorder
     *            The activeBorder to set.
     */
    public void setActiveBorder(Border activeBorder) {
        this.activeBorder = activeBorder;
    }

    /**
     * @return Returns the iconInsets.
     */
    public Insets getIconInsets() {
        return iconInsets;
    }

    /**
     * @param iconInsets
     *            The iconInsets to set.
     */
    public void setIconInsets(Insets iconInsets) {
        this.iconInsets = iconInsets;
    }

    /**
     * @return Returns the buttonMargin.
     */
    public int getButtonMargin() {
        return buttonMargin;
    }

    /**
     * @param buttonMargin
     *            The buttonMargin to set.
     */
    public void setButtonMargin(int buttonMargin) {
        this.buttonMargin = buttonMargin;
    }

    /**
     * @return Returns the painterResource.
     */
    public Painter getPainter() {
        return painter;
    }

    /**
     * @param painter
     *            The painter to set.
     */
    public void setPainter(Painter painter) {
        this.painter = painter;
    }

    /**
     * @return Returns the insets.
     */
    public Insets getInsets() {
        return insets;
    }

    /**
     * @param insets
     *            The insets to set.
     */
    public void setInsets(Insets insets) {
        this.insets = insets;
    }

    /**
     * @return Returns the antialiasing.
     */
    public boolean isAntialiasing() {
        return antialiasing == RenderingHints.VALUE_ANTIALIAS_ON;
    }

    /**
     * @param antialias
     *            The antialias to set.
     */
    public void setAntialiasing(boolean antialias) {
        antialiasing = antialias ? RenderingHints.VALUE_ANTIALIAS_ON :
                       RenderingHints.VALUE_ANTIALIAS_OFF;
    }

    public void initializeCreationParameters() {
        setActiveBackground(creationParameters.getColor(BACKGROUND_COLOR_ACTIVE));
        setActiveFont(creationParameters.getColor(FONT_COLOR_ACTIVE));
        setInactiveBackground(creationParameters.getColor(BACKGROUND_COLOR));
        setInactiveFont(creationParameters.getColor(FONT_COLOR));
        setDefaultHeight(creationParameters.getInt(DEFAULT_HEIGHT));
        setFont(creationParameters.getFont(FONT));
        setInactiveBorder(creationParameters.getBorder(BORDER));
        setActiveBorder(creationParameters.getBorder(BORDER_ACTIVE));

        setDefaultIcons(creationParameters.getString(IconResourceFactory.ICON_MAP_KEY));
        setPainter((Painter) creationParameters.getProperty(PAINTER));
        setIconInsets((Insets) creationParameters.getProperty(ICON_INSETS));
        setButtonMargin(creationParameters.getInt(BUTTON_MARGIN));
        setPainter((Painter) creationParameters.getProperty(PAINTER));
        setInsets((Insets) creationParameters.getProperty(INSETS));
        setAntialiasing(creationParameters.getBoolean( ANTIALIASING));
    }

    public String getPreferredButtonUI() {
        return creationParameters.getString(UIFactory.BUTTON_KEY);
    }
}