/*
 * 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 {

	private static final int FADE = 1;

	private final int color;
	private final char cornerRadius;
	private final char borderThickness;

	/**
	 * 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;
	}

}
