package speiger.src.coreengine.utils.io;

import java.awt.image.RenderedImage;
import java.io.File;
import java.util.function.BiConsumer;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;

import org.w3c.dom.NodeList;

public class GifWriter
{
	ImageOutputStream stream;
	ImageWriter writer;
	BiConsumer<ImageWriter, RenderedImage> inserter;
	
	public static GifWriter create(File file, int image, int delay)
	{
		try
		{
			return new GifWriter(file, image, delay);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}
	
	public static GifWriter create(ImageOutputStream stream, int image, int delay)
	{
		try
		{
			return new GifWriter(stream, image, delay);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}
	
	protected GifWriter(File file, int imageType, int delay) throws Exception
	{
		this(new FileImageOutputStream(file), imageType, delay);
	}
	
	protected GifWriter(ImageOutputStream out, int imageType, int delay) throws Exception
	{
		stream = out;
		writer = ImageIO.getImageWritersBySuffix("gif").next();
		final ImageWriteParam parameter = writer.getDefaultWriteParam();
		final IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromBufferedImageType(imageType), parameter);
		IIOMetadataNode root = (IIOMetadataNode)metadata.getAsTree(metadata.getNativeMetadataFormatName());
		IIOMetadataNode graphics = getOrCreateNode(root, "GraphicControlExtension");
		graphics.setAttribute("delayTime", ""+Float.valueOf(((delay / 1000F) * 15F)).intValue());
		graphics.setAttribute("transparentColorFlag", "false");
		graphics.setAttribute("transparentColorIndex", "0");
		graphics.setAttribute("disposalMethod", "none");
		graphics.setAttribute("userInputFlag", "false");
		
		IIOMetadataNode application = new IIOMetadataNode("ApplicationExtension");
		application.setAttribute("applicationID", "NETSCAPE");
		application.setAttribute("authenticationCode", "2.0");
		application.setUserObject(new byte[] {1, 0, 0});
		getOrCreateNode(root, "ApplicationExtensions").appendChild(application);
		metadata.setFromTree(metadata.getNativeMetadataFormatName(), root);
		writer.setOutput(out);
		writer.prepareWriteSequence(null);
		inserter = new BiConsumer<ImageWriter, RenderedImage>(){
			ImageWriteParam param = parameter;
			IIOMetadata meta = metadata;
			@Override
			public void accept(ImageWriter writer, RenderedImage image)
			{
				try
				{
					writer.writeToSequence(new IIOImage(image, null, meta), param);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
			}
		};
	}
	
	public void insertPicture(RenderedImage image)
	{
		inserter.accept(writer, image);
	}
	
	public void close()
	{
		try
		{
			writer.endWriteSequence();
			stream.close();
			inserter = null;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	private IIOMetadataNode getOrCreateNode(IIOMetadataNode parent, String name)
	{
		NodeList list = parent.getElementsByTagName(name);
		if(list.getLength() > 0)
		{
			return (IIOMetadataNode)list.item(0);
		}
		IIOMetadataNode node = new IIOMetadataNode(name);
		parent.appendChild(node);
		return node;
	}
}
