package org.jboss.resteasy.plugins.providers;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.Variant;

import org.jboss.resteasy.annotations.providers.img.ImageWriterParams;
import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages;
import org.jboss.resteasy.spi.util.FindAnnotation;

/**
 * A IIOImageProviderHelper.
 *
 * @author <a href="ryan@damnhandy.com">Ryan J. McDonough</a>
 * @version $Revision:$
 */
public final class IIOImageProviderHelper {

    private IIOImageProviderHelper() {
    }

    /**
     * FIXME Comment this
     *
     * @param mediaType media type
     * @return image writer
     */
    public static ImageWriter getImageWriterByMediaType(MediaType mediaType) {
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByMIMEType(mediaType.toString());
        ImageWriter writer = writers.next();
        if (writer == null) {
            Response response = Response.serverError().entity("").build();
            throw new WebApplicationException(response);
        }
        return writer;
    }

    /**
     * FIXME Comment this
     *
     * @param in         input stream
     * @param reader     image reader
     * @param imageIndex index
     * @return {@link IIOImage}
     * @throws IOException if I/O error occurred
     */
    public static IIOImage readImage(InputStream in, ImageReader reader, int imageIndex)
            throws IOException {
        ImageInputStream iis = ImageIO.createImageInputStream(in);
        reader.setInput(iis, false);
        return reader.readAll(imageIndex, null);
    }

    /**
     * FIXME Comment this
     *
     * @param mediaType media type
     * @return image reader
     */
    public static ImageReader getImageReaderByMediaType(MediaType mediaType) {
        Iterator<ImageReader> readers = ImageIO.getImageReadersByMIMEType(mediaType.toString());

        ImageReader reader = null;
        while (readers.hasNext()) {
            reader = (ImageReader) readers.next();
        }

        if (reader == null) {
            String[] availableTypes = ImageIO.getReaderMIMETypes();
            LogMessages.LOGGER.readerNotFound(mediaType, availableTypes);
            List<Variant> variants = ProviderHelper.getAvailableVariants(availableTypes);
            Response response = Response.notAcceptable(variants).status(Status.NOT_ACCEPTABLE).build();
            throw new WebApplicationException(response);
        }
        return reader;
    }

    /**
     * FIXME Comment this
     *
     * @param annotations array of annotations
     * @param mediaType   media type
     * @param writer      image writer
     * @param out         output stream
     * @param image       {@link IIOImage}
     * @throws IOException if I/O error occurred
     */
    public static void writeImage(Annotation[] annotations,
            MediaType mediaType,
            ImageWriter writer,
            OutputStream out,
            IIOImage image)
            throws IOException {
        ImageWriteParam param;
        if (mediaType.equals(MediaType.valueOf("image/jpeg"))) {
            param = new JPEGImageWriteParam(Locale.US);
        } else {
            param = writer.getDefaultWriteParam();
        }

        /*
         * If the image output type supports compression, set it to the highest
         * maximum
         */
        ImageWriterParams writerParams = FindAnnotation.findAnnotation(annotations, ImageWriterParams.class);
        if (writerParams != null) {
            if (param.canWriteCompressed()) {
                param.setCompressionMode(writerParams.compressionMode());
                param.setCompressionQuality(writerParams.compressionQuality());
            }
        } else if (param.canWriteCompressed()) {
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionQuality(1.0f);
        }
        BufferedOutputStream buff = new BufferedOutputStream(out, 2048);
        ImageOutputStream ios = ImageIO.createImageOutputStream(buff);
        try {
            writer.setOutput(ios);
            writer.write(null, image, param);
        } finally {
            writer.dispose();
        }
    }
}
