package org.sunflow.image;

import org.sunflow.math.MathUtils;

/**
 * This class contains many static helper methods that may be helpful for
 * encoding colors into files.
 */
public final class ColorEncoder {
    /**
     * Undoes the premultiplication of the specified color array. The original
     * colors are not modified.
     * 
     * @param color an array of premultiplied colors
     * @param alpha alpha values corresponding to the colors
     * @return an array of unpremultiplied colors
     */
    public static final Color[] unpremult(Color[] color, float[] alpha) {
        Color[] output = new Color[color.length];
        for (int i = 0; i < color.length; i++)
            output[i] = color[i].copy().mul(1 / alpha[i]);
        return output;
    }

    /**
     * Moves the colors in the specified array to non-linear space. The original
     * colors are not modified.
     * 
     * @param color an array of colors in linear space
     * @return a new array of the same colors in non-linear space
     */
    public static final Color[] unlinearize(Color[] color) {
        Color[] output = new Color[color.length];
        for (int i = 0; i < color.length; i++)
            output[i] = color[i].copy().toNonLinear();
        return output;
    }

    /**
     * Quantize the specified colors to 8-bit RGB format. The returned array
     * contains 3 bytes for each color in the original array.
     * 
     * @param color array of colors to quantize
     * @return array of quantized RGB values
     */
    public static final byte[] quantizeRGB8(Color[] color) {
        byte[] output = new byte[color.length * 3];
        for (int i = 0, index = 0; i < color.length; i++, index += 3) {
            float[] rgb = color[i].getRGB();
            output[index + 0] = (byte) MathUtils.clamp((int) (rgb[0] * 255 + 0.5f), 0, 255);
            output[index + 1] = (byte) MathUtils.clamp((int) (rgb[1] * 255 + 0.5f), 0, 255);
            output[index + 2] = (byte) MathUtils.clamp((int) (rgb[2] * 255 + 0.5f), 0, 255);
        }
        return output;
    }

    /**
     * Quantize the specified colors to 8-bit RGBA format. The returned array
     * contains 4 bytes for each color in the original array.
     * 
     * @param color array of colors to quantize
     * @param alpha array of alpha values (same length as color)
     * @return array of quantized RGBA values
     */
    public static final byte[] quantizeRGBA8(Color[] color, float[] alpha) {
        byte[] output = new byte[color.length * 4];
        for (int i = 0, index = 0; i < color.length; i++, index += 4) {
            float[] rgb = color[i].getRGB();
            output[index + 0] = (byte) MathUtils.clamp((int) (rgb[0] * 255 + 0.5f), 0, 255);
            output[index + 1] = (byte) MathUtils.clamp((int) (rgb[1] * 255 + 0.5f), 0, 255);
            output[index + 2] = (byte) MathUtils.clamp((int) (rgb[2] * 255 + 0.5f), 0, 255);
            output[index + 3] = (byte) MathUtils.clamp((int) (alpha[i] * 255 + 0.5f), 0, 255);
        }
        return output;
    }

    /**
     * Encode the specified colors using Ward's RGBE technique. The returned
     * array contains one int for each color in the original array.
     * 
     * @param color array of colors to encode
     * @return array of encoded colors
     */
    public static final int[] encodeRGBE(Color[] color) {
        int[] output = new int[color.length];
        for (int i = 0; i < color.length; i++)
            output[i] = color[i].toRGBE();
        return output;
    }
}