/*
 * Copyright 2015-2025 MicroEJ Corp. All rights reserved.
 * This library is provided in source code for use, modification and test, subject to license terms.
 * Any modification of the source code will break MicroEJ Corp. warranties on the whole library.
 */
package ej.mwt.style.background;

import ej.annotation.Nullable;
import ej.bon.XMath;
import ej.microui.display.GraphicsContext;
import ej.microui.display.Painter;

/**
 * Draws a plain color on the background with a round corner.
 * <p>
 * Should be used in association with a {@link ej.mwt.style.outline.border.RoundedBorder} (using same color, corner
 * radius and border thickness) to:
 * <ul>
 * <li>draw the border,</li>
 * <li>anti-alias the corner edges (blending color with background).</li>
 * </ul>
 * <p>
 * The corner radius and border thickness are stored as a <code>char</code> for heap optimization and therefore cannot
 * exceed <code>65535</code>.
 */
public class RoundedBackground implements Background {

    /**
     * Creates a rounded background.
     * <p>
     * The given corner radius is clamped between <code>0</code> and <code>Character.MAX_VALUE</code>.
     *
     * @param color
     *            the color.
     * @param cornerRadius
     *            the corner radius.
     *
     * @deprecated use {@link #RoundedBackground(int, int, int)}
     */
    @Deprecated
    public RoundedBackground(int color, int cornerRadius) {
        this(color, cornerRadius, 0);
    }

    /**
     * Creates a rounded background.
     * <p>
     * The given corner radius and border thickness are clamped between <code>0</code> and
     * <code>Character.MAX_VALUE</code>.
     *
     * @param color
     *            the color.
     * @param cornerRadius
     *            the corner radius.
     * @param borderThickness
     *            the border thickness.
     */
    public RoundedBackground(int color, int cornerRadius, int borderThickness) {
        this.color = color;
        this.cornerRadius = (char) XMath.limit(cornerRadius, 0, Character.MAX_VALUE);
        this.borderThickness = (char) XMath.limit(borderThickness, 0, Character.MAX_VALUE);
    }

    /**
     * Gets the color.
     *
     * @return the color.
     */
    public int getColor() {
        return this.color;
    }

    /**
     * Gets the corner radius.
     *
     * @return the corner radius.
     */
    public int getCornerRadius() {
        return this.cornerRadius;
    }

    /**
     * Gets the border thickness.
     *
     * @return the border thickness.
     */
    public int getBorderThickness() {
        return this.borderThickness;
    }

    @Override
    public boolean isTransparent(int width, int height) {
        // Is transparent because it is usually associated with an anti-aliased border
        // and because its corners are not drawn (if the widget is moved, its corners are not repainted).
        return true;
    }

    @Override
    public void apply(GraphicsContext g, int width, int height) {
        g.setColor(this.color);
        int thickness = this.borderThickness;
        int radius = Math.min(Math.max(this.cornerRadius, thickness + FADE), Math.min(width, height) >> 1);
        int diameter = radius << 1;
        int includedDiameter = diameter - ((thickness + FADE) << 2);
        int originShift = thickness;
        int sizeShift = thickness << 1;
        Painter.fillRoundedRectangle(g, originShift, originShift, width - sizeShift, height - sizeShift, includedDiameter, includedDiameter);
        // Set background color to optimize future anti-aliased drawings.
        g.setBackgroundColor(this.color);
    }

    @Override
    public boolean equals(@Nullable Object obj) {
        if (obj != null && getClass() == obj.getClass()) {
            RoundedBackground background = (RoundedBackground) obj;
            return this.color == background.color && this.cornerRadius == background.cornerRadius && this.borderThickness == background.borderThickness;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return 17 * this.color + this.cornerRadius + this.borderThickness;
    }
}
