package com.sksamuel.scrimage.filter;

import com.sksamuel.scrimage.Dimension;
import com.sksamuel.scrimage.graphics.Graphics2DUtils;
import com.sksamuel.scrimage.ImmutableImage;
import com.sksamuel.scrimage.Position;
import com.sksamuel.scrimage.canvas.Canvas;
import com.sksamuel.scrimage.canvas.drawables.FilledRect;
import com.sksamuel.scrimage.canvas.drawables.Text;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;

public class CaptionFilter implements Filter {

    private final String text;
    private final Position position;
    private final int x;
    private final int y;
    private final Font font;
    private final Color textColor;
    private final double textAlpha;
    private final boolean antiAlias;
    private final boolean fullWidth;
    private final Color captionBackground;
    private final double captionAlpha;
    private final Padding padding;

    public CaptionFilter(String text, Position position, Font font, Color textColor, double textAlpha, boolean antiAlias, boolean fullWidth, Color captionBackground, double captionAlpha, Padding padding) {
        this.text = text;
        this.position = position;
        this.x = -1;
        this.y = -1;
        this.font = font;
        this.textColor = textColor;
        this.textAlpha = textAlpha;
        this.antiAlias = antiAlias;
        this.fullWidth = fullWidth;
        this.captionBackground = captionBackground;
        this.captionAlpha = captionAlpha;
        this.padding = padding;
    }

    public CaptionFilter(String text, int x, int y, Font font, Color textColor, double textAlpha, boolean antiAlias, boolean fullWidth, Color captionBackground, double captionAlpha, Padding padding) {
        this.text = text;
        this.position = null;
        this.x = x;
        this.y = y;
        this.font = font;
        this.textColor = textColor;
        this.textAlpha = textAlpha;
        this.antiAlias = antiAlias;
        this.fullWidth = fullWidth;
        this.captionBackground = captionBackground;
        this.captionAlpha = captionAlpha;
        this.padding = padding;
    }

    @Override
    public void apply(ImmutableImage image) {

        Graphics2D g2 = (Graphics2D) image.awt().getGraphics();
        g2.setFont(font);

        Rectangle2D bounds = g2.getFontMetrics().getStringBounds(text, g2);
        int descent = g2.getFontMetrics().getDescent();

        int captionWidth;
        if (fullWidth) {
            captionWidth = image.width;
        } else {
            captionWidth = (int) (bounds.getWidth() + padding.left + padding.right);
        }

        int captionHeight = (int) (bounds.getHeight() + padding.top + padding.bottom);

        // captionx/y are the top/left coordinates for the caption box
        int captionX, captionY;
        if (position != null) {
            Dimension dim = position.calculateXY(image.width, image.height, captionWidth, captionHeight);
            captionX = dim.getX();
            captionY = dim.getY();
        } else {
            captionX = x;
            captionY = y;
        }

        FilledRect bg = new FilledRect(
                captionX,
                image.height - captionHeight,
                captionWidth,
                captionHeight,
                g -> {
                    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) captionAlpha));
                    g.setColor(captionBackground);
                    Graphics2DUtils.setAntiAlias(g, antiAlias);
                }
        );

        Text string = new Text(
                text,
                captionX + padding.left,
                captionY + padding.top + g2.getFontMetrics().getHeight() - descent,
                g -> {
                    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) textAlpha));
                    g.setColor(textColor);
                    g.setFont(font);
                    Graphics2DUtils.setAntiAlias(g, antiAlias);
                });

        Canvas canvas = new Canvas(image);
        canvas.drawInPlace(bg);
        canvas.drawInPlace(string);
    }
}