/*
 * Copyright 2015-2020 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.util;

/**
 * Provides constants and utility methods in order to position a graphical object considering its alignment within an
 * area or with an anchor point.
 */
public class Alignment {

    /**
     * Constant for positioning on the left.
     */
    public static final int LEFT = 0;

    /**
     * Constant for centering horizontally.
     */
    public static final int HCENTER = 1;

    /**
     * Constant for positioning on the right.
     */
    public static final int RIGHT = 2;

    /**
     * Constant for positioning on the top.
     */
    public static final int TOP = 3;

    /**
     * Constant for centering vertically.
     */
    public static final int VCENTER = 4;

    /**
     * Constant for positioning on the bottom.
     */
    public static final int BOTTOM = 5;

    /**
     * Validates that the given value represents a valid horizontal alignment.
     * <p>
     * This method is equivalent to {@link #checkHorizontalAlignment(int)} except that it throws an exception rather
     * than return a boolean.
     *
     * @param horizontalAlignment
     *            the horizontal alignment to check.
     * @throws IllegalArgumentException
     *             if the given horizontal alignment is not valid.
     */
    public static void validateHorizontalAlignment(int horizontalAlignment) {
        if (!checkHorizontalAlignment(horizontalAlignment)) {
            throw new IllegalArgumentException();
        }
    }

    /**
     * Validates that the given value represents a valid vertical alignment.
     * <p>
     * This method is equivalent to {@link #checkVerticalAlignment(int)} except that it throws an exception rather than
     * return a boolean.
     *
     * @param verticalAlignment
     *            the vertical alignment to check.
     * @throws IllegalArgumentException
     *             if the given vertical alignment is not valid.
     */
    public static void validateVerticalAlignment(int verticalAlignment) {
        if (!checkVerticalAlignment(verticalAlignment)) {
            throw new IllegalArgumentException();
        }
    }

    /**
     * Checks whether the given value represents a valid horizontal alignment.
     * <p>
     * A value represents a valid horizontal alignment if it is equal to either {@link #LEFT}, {@link #HCENTER} or
     * {@link #RIGHT}.
     *
     * @param horizontalAlignment
     *            the horizontal alignment to check.
     * @return <code>true</code> if the given horizontal alignment is valid, <code>false</code> otherwise.
     */
    public static boolean checkHorizontalAlignment(int horizontalAlignment) {
        switch(horizontalAlignment) {
            case RIGHT:
            case HCENTER:
            case LEFT:
                return true;
            default:
                return false;
        }
    }

    /**
     * Checks whether the given value represents a valid vertical alignment.
     * <p>
     * A value represents a valid vertical alignment if it is equal to either {@link #TOP}, {@link #VCENTER} or
     * {@link #BOTTOM}.
     *
     * @param verticalAlignment
     *            the vertical alignment to check.
     * @return <code>true</code> if the given vertical alignment is valid, <code>false</code> otherwise.
     */
    public static boolean checkVerticalAlignment(int verticalAlignment) {
        switch(verticalAlignment) {
            case BOTTOM:
            case VCENTER:
            case TOP:
                return true;
            default:
                return false;
        }
    }

    /**
     * Computes the x coordinate of the left edge of an object aligned in an area.
     * <p>
     * If the horizontal alignment is invalid or not set, the object is aligned on the left.
     *
     * @param width
     *            the object width.
     * @param areaX
     *            the area x coordinate.
     * @param areaWidth
     *            the area width.
     * @param horizontalAlignment
     *            the horizontal alignment.
     * @return the x coordinate of the left of the object.
     * @see #checkHorizontalAlignment(int)
     */
    public static int computeLeftX(int width, int areaX, int areaWidth, int horizontalAlignment) {
        return computeLeftX(-(areaWidth - width), areaX, horizontalAlignment);
    }

    /**
     * Computes the y coordinate of the top edge of an object aligned in an area.
     * <p>
     * If the vertical alignment is invalid or not set, the object is aligned on the top.
     *
     * @param height
     *            the object height.
     * @param areaY
     *            the area y coordinate.
     * @param areaHeight
     *            the area height.
     * @param verticalAlignment
     *            the vertical alignment.
     * @return the y coordinate of the top of the object.
     * @see #checkVerticalAlignment(int)
     */
    public static int computeTopY(int height, int areaY, int areaHeight, int verticalAlignment) {
        return computeTopY(-(areaHeight - height), areaY, verticalAlignment);
    }

    /**
     * Computes the x coordinate of the left edge of an object aligned on an anchor point.
     * <p>
     * If the horizontal alignment is invalid, the object is aligned on the left.
     *
     * @param width
     *            the object width.
     * @param anchorX
     *            the anchor x coordinate.
     * @param horizontalAlignment
     *            the horizontal alignment.
     * @return the x coordinate of the left of the object.
     */
    public static int computeLeftX(int width, int anchorX, int horizontalAlignment) {
        switch(horizontalAlignment) {
            case RIGHT:
                return anchorX - width;
            case HCENTER:
                return anchorX - (width >> 1);
            case LEFT:
            default:
                return anchorX;
        }
    }

    /**
     * Computes the y coordinate of the top edge of an object aligned on an anchor point.
     * <p>
     * If the vertical alignment is invalid, the object is aligned on the top.
     *
     * @param height
     *            the object height.
     * @param anchorY
     *            the anchor y coordinate.
     * @param verticalAlignment
     *            the vertical alignment.
     * @return the y coordinate of the top of the object.
     */
    public static int computeTopY(int height, int anchorY, int verticalAlignment) {
        switch(verticalAlignment) {
            case BOTTOM:
                return anchorY - height;
            case VCENTER:
                return anchorY - (height >> 1);
            case TOP:
            default:
                return anchorY;
        }
    }
}
