package net.sf.freecol.client.gui;

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.Rectangle;

import javax.swing.ImageIcon;

import net.sf.freecol.client.gui.i18n.Messages;
import net.sf.freecol.client.gui.panel.InfoPanel;
import net.sf.freecol.common.model.Player;
import net.sf.freecol.common.model.StringTemplate;

/**
 * Custom component to paint turn progress.
 * <p>
 * Currently the component darken out background using alpha channel and
 * then paints the player's icon and wait message.
 */
public class GrayLayer extends Component {

    /** Color for graying out background component */
    private static final Color MASK_COLOR = new Color(0f, 0f, 0f, .6f);
    /** Default font size for message text */
    private static final int DEFAULT_FONT_SIZE = 18;
    /** Font size decrement for message text to reduce length */
    private static final int FONT_SIZE_DECREMENT = 2;
    /**
     * Maximum text width to show. This is additional constraint to the
     * component's bounds
     */
    private static final int MAX_TEXT_WIDTH = 640;

    /** Image library for icon lookup */
    private ImageLibrary imageLibrary;
    /** Player object or <code>null</code> */
    private Player player;

    public GrayLayer(ImageLibrary imageLibrary) {
        this.imageLibrary = imageLibrary;
    }

    /**
     * Executes painting. The method shadows the background image, and
     * paints the message with icon (if available) and text.
     * @param g a <code>Graphics</code> value
     */
    @Override
    public void paint(Graphics g) {
        Rectangle clipArea = g.getClipBounds();
        if (clipArea == null) {
            clipArea = getBounds();
            clipArea.x = clipArea.y = 0;
        }
        if (clipArea.isEmpty()) {
            // we are done - the picture is OK
            return;
        }
        g.setColor(MASK_COLOR);
        g.fillRect(clipArea.x, clipArea.y, clipArea.width, clipArea.height);

        if (player == null) {
            // we are done, no player information
            return;
        }

        ImageIcon coatOfArmsIcon = imageLibrary
                .getCoatOfArmsImageIcon(player.getNation());

        Rectangle iconBounds = new Rectangle();
        if (coatOfArmsIcon != null) {
            iconBounds.width = coatOfArmsIcon.getIconWidth();
            iconBounds.height = coatOfArmsIcon.getIconHeight();
        }

        Font nameFont = getFont();
        FontMetrics nameFontMetrics = getFontMetrics(nameFont);
        StringTemplate t = StringTemplate.template("waitingFor")
            .addStringTemplate("%nation%", player.getNationName());
        String message = Messages.message(t);

        Rectangle textBounds;
        int fontSize = DEFAULT_FONT_SIZE;
        int maxWidth = Math.min(MAX_TEXT_WIDTH, getSize().width);
        do {
            nameFont = nameFont.deriveFont(Font.BOLD, fontSize);
            nameFontMetrics = getFontMetrics(nameFont);
            textBounds = nameFontMetrics.getStringBounds(message, g)
                    .getBounds();
            fontSize -= FONT_SIZE_DECREMENT;
        } while (textBounds.width > maxWidth);

        Dimension size = getSize();
        textBounds.x = (size.width - textBounds.width) / 2;
        textBounds.y = size.height - InfoPanel.PANEL_HEIGHT - 2 * textBounds.height;

        iconBounds.x = (size.width - iconBounds.width) / 2;
        iconBounds.y = textBounds.y + 3 * textBounds.height / 2;

        if (textBounds.intersects(clipArea)) {
            // show message
            g.setFont(nameFont);
            g.setColor(imageLibrary.getColor(player));
            g.drawString(message, textBounds.x, textBounds.y
                    + textBounds.height);
        }
        if (coatOfArmsIcon != null && iconBounds.intersects(clipArea)) {
            // show icon
            coatOfArmsIcon.paintIcon(this, g, iconBounds.x, iconBounds.y);
        }
    }

    /**
     * Set the player for which we paint. If the player is already set, then
     * nothing happens, otherwise a repaint event is sent.
     *
     * @param player
     *            Player for status information
     *
     * @see #paint(Graphics)
     */
    public void setPlayer(Player player) {
        if (this.player == player) {
            return;
        }
        this.player = player;
        repaint();
    }
}
