/*
 * Copyright 2015-2024 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.outline;

import ej.annotation.Nullable;
import ej.bon.XMath;
import ej.microui.display.GraphicsContext;
import ej.mwt.util.Outlineable;
import ej.mwt.util.Size;

/**
 * Flexible outline that has a different thickness for each edge.
 * <p>
 * The thicknesses are stored as a <code>char</code> for heap optimization and therefore cannot exceed
 * <code>65535</code>.
 */
public class FlexibleOutline implements Outline {

	private final char top;
	private final char bottom;
	private final char left;
	private final char right;

	/**
	 * Creates a flexible outline specifying its thickness for each edge.
	 * <p>
	 * The given thickness values are clamped between <code>0</code> and <code>Character.MAX_VALUE</code>.
	 *
	 * @param top
	 *            the top thickness.
	 * @param right
	 *            the right thickness.
	 * @param bottom
	 *            the bottom thickness.
	 * @param left
	 *            the left thickness.
	 */
	public FlexibleOutline(int top, int right, int bottom, int left) {
		this.top = (char) XMath.limit(top, 0, Character.MAX_VALUE);
		this.right = (char) XMath.limit(right, 0, Character.MAX_VALUE);
		this.bottom = (char) XMath.limit(bottom, 0, Character.MAX_VALUE);
		this.left = (char) XMath.limit(left, 0, Character.MAX_VALUE);
	}

	/**
	 * Gets the top thickness.
	 *
	 * @return the top thickness.
	 */
	public int getTop() {
		return this.top;
	}

	/**
	 * Gets the bottom thickness.
	 *
	 * @return the bottom thickness.
	 */
	public int getBottom() {
		return this.bottom;
	}

	/**
	 * Gets the left thickness.
	 *
	 * @return the left thickness.
	 */
	public int getLeft() {
		return this.left;
	}

	/**
	 * Gets the right thickness.
	 *
	 * @return the right thickness.
	 */
	public int getRight() {
		return this.right;
	}

	@Override
	public void apply(Outlineable outlineable) {
		outlineable.removeOutline(this.left, this.top, this.right, this.bottom);
	}

	@Override
	public void apply(GraphicsContext g, Size size) {
		size.removeOutline(this.left, this.top, this.right, this.bottom);

		g.translate(this.left, this.top);
		g.intersectClip(0, 0, size.getWidth(), size.getHeight());
	}

	@Override
	public boolean equals(@Nullable Object obj) {
		if (obj != null && getClass() == obj.getClass()) {
			FlexibleOutline outline = (FlexibleOutline) obj;
			return this.top == outline.top && this.bottom == outline.bottom && this.left == outline.left
					&& this.right == outline.right;
		}
		return false;
	}

	@Override
	public int hashCode() {
		return this.top * this.bottom * this.left * this.right;
	}

}
