/*******************************************************************************
 * Copyright (c) 2008, 2016 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.snippets;

/*
 * Create a ToolBar containing animated GIFs
 *
 * For a list of all SWT example snippets see
 * http://www.eclipse.org/swt/snippets/
 */
import java.io.*;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;

public class Snippet288 {

	static Display display;
	static Shell shell;
	static GC shellGC;
	static Color shellBackground;
	static ImageLoader[] loader;
	static ImageData[][] imageDataArray;
	static Thread animateThread[];
	static Image[][] image;
	private static ToolItem item[];
	static final boolean useGIFBackground = false;

	public static void main (String [] args) {
		display = new Display();
		Shell shell = new Shell (display);
		shellBackground = shell.getBackground();
		FileDialog dialog = new FileDialog(shell, SWT.OPEN | SWT.MULTI);
		dialog.setText("Select Multiple Animated GIFs");
		dialog.setFilterExtensions(new String[] {"*.gif"});
		String filename = dialog.open();
		String filenames[] = dialog.getFileNames();
		int numToolBarItems = filenames.length;
		if (numToolBarItems > 0) {
			try {
				loadAllImages(new File(filename).getParent(), filenames);
			} catch (SWTException e) {
				System.err.println("There was an error loading an image.");
				e.printStackTrace();
			}
			ToolBar toolBar = new ToolBar (shell, SWT.FLAT | SWT.BORDER | SWT.WRAP);
			item = new ToolItem[numToolBarItems];
			for (int i = 0; i < numToolBarItems; i++) {
				item[i] = new ToolItem (toolBar, SWT.PUSH);
				item[i].setImage(image[i][0]);
			}
			toolBar.pack ();
			shell.open ();

			startAnimationThreads();

			while (!shell.isDisposed()) {
				if (!display.readAndDispatch ()) display.sleep ();
			}

			for (int i = 0; i < numToolBarItems; i++) {
				for (int j = 0; j < image[i].length; j++) {
					image[i][j].dispose();
				}
			}
		}
		display.dispose ();
	}

	private static void loadAllImages(String directory, String[] filenames) throws SWTException {
		int numItems = filenames.length;
		loader = new ImageLoader[numItems];
		imageDataArray = new ImageData[numItems][];
		image = new Image[numItems][];
		for (int i = 0; i < numItems; i++) {
			loader[i] = new ImageLoader();
			int fullWidth = loader[i].logicalScreenWidth;
			int fullHeight = loader[i].logicalScreenHeight;
			imageDataArray[i] = loader[i].load(directory + File.separator + filenames[i]);
			int numFramesOfAnimation = imageDataArray[i].length;
			image[i] = new Image[numFramesOfAnimation];
			for (int j = 0; j < numFramesOfAnimation; j++) {
				if (j == 0) {
					//for the first frame of animation, just draw the first frame
					image[i][j] = new Image(display, imageDataArray[i][j]);
					fullWidth = imageDataArray[i][j].width;
					fullHeight = imageDataArray[i][j].height;
				}
				else {
					//after the first frame of animation, draw the background or previous frame first, then the new image data
					image[i][j] = new Image(display, fullWidth, fullHeight);
					GC gc = new GC(image[i][j]);
					gc.setBackground(shellBackground);
					gc.fillRectangle(0, 0, fullWidth, fullHeight);
					ImageData imageData = imageDataArray[i][j];
					switch (imageData.disposalMethod) {
					case SWT.DM_FILL_BACKGROUND:
						/* Fill with the background color before drawing. */
						Color bgColor = null;
						if (useGIFBackground && loader[i].backgroundPixel != -1) {
							bgColor = new Color(display, imageData.palette.getRGB(loader[i].backgroundPixel));
						}
						gc.setBackground(bgColor != null ? bgColor : shellBackground);
						gc.fillRectangle(imageData.x, imageData.y, imageData.width, imageData.height);
						if (bgColor != null) bgColor.dispose();
						break;
					default:
						/* Restore the previous image before drawing. */
						gc.drawImage(
							image[i][j-1],
							0,
							0,
							fullWidth,
							fullHeight,
							0,
							0,
							fullWidth,
							fullHeight);
						break;
					}
					Image newFrame = new Image(display, imageData);
					gc.drawImage(newFrame,
							0,
							0,
							imageData.width,
							imageData.height,
							imageData.x,
							imageData.y,
							imageData.width,
							imageData.height);
					newFrame.dispose();
					gc.dispose();
				}
			}
		}
	}

	private static void startAnimationThreads() {
		animateThread = new Thread[image.length];
		for (int ii = 0; ii < image.length; ii++) {
			final int i = ii;
			animateThread[i] = new Thread("Animation "+i) {
				int imageDataIndex = 0;
				@Override
				public void run() {
					try {
						int repeatCount = loader[i].repeatCount;
						while (loader[i].repeatCount == 0 || repeatCount > 0) {
							imageDataIndex = (imageDataIndex + 1) % imageDataArray[i].length;
							if (!display.isDisposed()) {
								display.asyncExec(() -> {
									if (!item[i].isDisposed())
										item[i].setImage(image[i][imageDataIndex]);
								});
							}

							/* Sleep for the specified delay time (adding commonly-used slow-down fudge factors). */
							try {
								int ms = imageDataArray[i][imageDataIndex].delayTime * 10;
								if (ms < 20) ms += 30;
								if (ms < 30) ms += 10;
								Thread.sleep(ms);
							} catch (InterruptedException e) {
							}

							/* If we have just drawn the last image, decrement the repeat count and start again. */
							if (imageDataIndex == imageDataArray[i].length - 1) repeatCount--;
						}
					} catch (SWTException ex) {
						System.out.println("There was an error animating the GIF");
						ex.printStackTrace();
					}
				}
			};
			animateThread[i].setDaemon(true);
			animateThread[i].start();
		}
	}
}
