/*
 * Copyright 2022-2023 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 com.microej.painter;

import ej.microui.display.GraphicsContext;
import ej.microui.display.Image;
import ej.microvg.BlendMode;
import ej.microvg.Matrix;

/**
 * The <code>TransformedImagePainter</code> class provides static methods to draw an image with a transformation defined
 * by a {@link Matrix}.
 * <p>
 * In all the provided drawing APIs, the image pixels color is multiplied with the graphics context's color.
 * <p>
 * The drawings can be performed either using the bilinear algorithm or the nearest neighbor algorithm. The bilinear
 * algorithm produces a prettier rendering but takes more time.
 */
public class TransformedImagePainter {

    /**
     * Draws the given image with a transformation defined by the given matrix.
     * <p>
     * Equivalent to calling {@link #drawImage(GraphicsContext, Image, Matrix, boolean, int, BlendMode)} with
     * {@link GraphicsContext#OPAQUE} as alpha and {@link BlendMode#SRC_OVER} as blend mode.
     *
     * @param gc
     *            the graphics context to use.
     * @param image
     *            the image to render.
     * @param matrix
     *            the transformation matrix to apply.
     * @param bilinear
     *            whether to use the bilinear algorithm or the nearest neighbor algorithm.
     */
    public static void drawImage(GraphicsContext gc, Image image, Matrix matrix, boolean bilinear) {
        drawImage(gc, image, 0, 0, image.getWidth(), image.getHeight(), matrix, bilinear, GraphicsContext.OPAQUE, BlendMode.SRC_OVER);
    }

    /**
     * Draws the given image with a transformation defined by the given matrix.
     * <p>
     * In addition with {@link #drawImage(GraphicsContext, Image, Matrix, boolean)}, this method allows to
     * specify the global opacity value to apply during the image rendering. The blend mode specifies the algorithm to
     * use when blending the pixels of the source and destination.
     *
     * @param gc
     *            the graphics context to use.
     * @param image
     *            the image to render.
     * @param matrix
     *            the transformation matrix to apply.
     * @param bilinear
     *            whether to use the bilinear algorithm or the nearest neighbor algorithm.
     * @param alpha
     *            the global opacity rendering value.
     * @param blendMode
     *            the blend mode.
     * @throws IllegalArgumentException
     *             if the given alpha is not a value between {@link GraphicsContext#TRANSPARENT} and
     *             {@link GraphicsContext#OPAQUE}.
     */
    public static void drawImage(GraphicsContext gc, Image image, Matrix matrix, boolean bilinear, int alpha, BlendMode blendMode) {
        checkAlpha(alpha);
        drawImage(gc, image, 0, 0, image.getWidth(), image.getHeight(), matrix, bilinear, alpha, blendMode);
    }

    /**
     * Draws a region of the given image with a transformation defined by the given matrix.
     *
     * @param gc
     *            the graphics context to use.
     * @param image
     *            the image to render.
     * @param regionX
     *            the x coordinate of the region in the image.
     * @param regionY
     *            the y coordinate of the region in the image.
     * @param regionWidth
     *            the width of the region.
     * @param regionHeight
     *            the height of the region.
     * @param matrix
     *            the transformation matrix to apply.
     * @param bilinear
     *            whether to use the bilinear algorithm or the nearest neighbor algorithm.
     * @param alpha
     *            the global opacity rendering value.
     * @param blendMode
     *            the blend mode.
     * @throws IllegalArgumentException
     *             if the given alpha is not a value between {@link GraphicsContext#TRANSPARENT} and
     *             {@link GraphicsContext#OPAQUE}.
     */
    public static void drawImageRegion(GraphicsContext gc, Image image, int regionX, int regionY, int regionWidth, int regionHeight, Matrix matrix, boolean bilinear, int alpha, BlendMode blendMode) {
        checkAlpha(alpha);
        drawImage(gc, image, regionX, regionY, regionWidth, regionHeight, matrix, bilinear, alpha, blendMode);
    }
}
