import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.IndexColorModel;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.concurrent.Semaphore;

public class GifReuseFormerlyTransPixelTest {
    public static void main(String[] args) throws Exception {
        URL srcURL = GifReuseFormerlyTransPixelTest.class.getResource("leo.gif");
        BufferedImage[] frames = getFrames(srcURL, 3);

        boolean pass = true;

        // these first two conditions have never failed. The second frame is always fine
        if ( !Integer.toUnsignedString(frames[1].getRGB(100, 50), 16).equals("ff005bbb") ) {
            System.err.println("On frame #2, the top stripe should be opaque blue");
            pass = false;
        }

        if ( !Integer.toUnsignedString(frames[1].getRGB(5, 5), 16).equals("0") ) {
            System.err.println("On frame #2, the top-left corner should be transparent");
            pass = false;
        }

        // these two conditions failed when we start looking at frame 3
        if ( !Integer.toUnsignedString(frames[2].getRGB(100, 50), 16).equals("ff005bbb") ) {
            System.err.println("On frame #3, the top stripe should be opaque blue");
            pass = false;
        }

        if ( !Integer.toUnsignedString(frames[2].getRGB(5, 5), 16).equals("0") ) {
            System.err.println("On frame #3, the top-left corner should be transparent");
            pass = false;
        }

        if (!pass) {
            throw new Error("See log for details");
        }
    }

    private static BufferedImage[] getFrames(URL gifURL, int numberOfFrames) {
        Image image = Toolkit.getDefaultToolkit().createImage(gifURL);
        ArrayList<BufferedImage> returnValue = new ArrayList<>(numberOfFrames);

        Semaphore semaphore = new Semaphore(1);
        semaphore.acquireUninterruptibly();
        image.getSource().startProduction(new ImageConsumer() {
            BufferedImage bi;
            int frameCtr = 0;

            @Override
            public void setDimensions(int width, int height) {
                bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            }

            @Override
            public void setProperties(Hashtable<?, ?> props) {}

            @Override
            public void setColorModel(ColorModel model) {}

            @Override
            public void setHints(int hintflags) {}

            @Override
            public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) {
                try {
                    final int yMax = y + h;
                    final int xMax = x + w;

                    IndexColorModel icm = (IndexColorModel) model;
                    int[] colorModelRGBs = new int[icm.getMapSize()];
                    icm.getRGBs(colorModelRGBs);
                    int[] argbRow = new int[bi.getWidth()];

                    for (int y_ = y; y_ < yMax; y_++) {
                        int i = y_ * scansize + off;
                        for (int x_ = x; x_ < xMax; x_++, i++) {
                            int pixel = pixels[i] & 0xff;
                            argbRow[x_ - x] = colorModelRGBs[pixel];
                        }
                        bi.getRaster().setDataElements(x, y_, w, 1, argbRow);
                    }
                } catch (RuntimeException e) {
                    // we don't expect this to happen, but if something goes
                    // wrong nobody else will print our stacktrace for us:
                    e.printStackTrace();
                    throw e;
                }
            }

            @Override
            public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) {}

            @Override
            public void imageComplete(int status) {
                try {
                    frameCtr++;

                    BufferedImage copy = new BufferedImage(bi.getWidth(),
                            bi.getHeight(), BufferedImage.TYPE_INT_ARGB);
                    Graphics2D g = copy.createGraphics();
                    g.drawImage(bi, 0, 0, null);
                    g.dispose();
                    returnValue.add(copy);

                    if (frameCtr == numberOfFrames) {
                        semaphore.release();
                        // if we don't detach this consumer the producer will
                        // loop forever
                        image.getSource().removeConsumer(this);
                        image.flush();
                    }
                } catch(Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        });

        semaphore.acquireUninterruptibly();

        return returnValue.toArray(new BufferedImage[0]);
    }
} 