/* 
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org

This file is part of GeoGebra.

This program is free software; you can redistribute it and/or modify it 
under the terms of the GNU General Public License as published by 
the Free Software Foundation.

*/

package geogebra;

/*
 * Copyright (c) 1999-2003 Werner Randelshofer
 * Staldenmattweg 2, Immensee, CH-6405, Switzerland
 * All rights reserved.
 *
 * This material is provided "as is", with absolutely no warranty expressed
 * or implied. Any use is at your own risk.
 *
 * Permission to use or copy this software is hereby granted without fee,
 * provided this copyright notice is retained on all copies.
 */
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * Splash Window to show an image during startup of an application.<p>
 *
 * Usage:
 * <pre>
 * // open the splash window
 * Frame splashOwner = SplashWindow.splash(anImage);
 *
 * // start the application
 * // ...
 *
 * // dispose the splash window by disposing the frame that owns the window.
 * splashOwner.dispose();
 * </pre>
 *
 * <p>To use the splash window as an about dialog write this:
 * <pre>
 *  new SplashWindow(
 *      this,
 *      getToolkit().createImage(getClass().getResource(GeoGebra.SPLASH_STRING))
 * ).show();
 * </pre>
 *
 * The splash window disposes itself when the user clicks on it.
 *
 * @author Werner Randelshofer, Staldenmattweg 2, Immensee, CH-6405, Switzerland.
 * @version 1.3 2003-06-01 Revised.
 */
public class SplashWindow extends Window {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;


	private Image splashImage;


    /**
     * This attribute indicates whether the method
     * paint(Graphics) has been called at least once since the
     * construction of this window.<br>
     * This attribute is used to notify method splash(Image)
     * that the window has been drawn at least once
     * by the AWT event dispatcher thread.<br>
     * This attribute acts like a latch. Once set to true,
     * it will never be changed back to false again.
     *
     * @see #paint
     * @see #splash
     */
    private boolean paintCalled = false;

    /**
     * Constructs a splash window and centers it on the
     * screen. The user can click on the window to dispose it.
     *
     * @param   owner       The frame owning the splash window.
     * @param   splashImage The splashImage to be displayed.
     * @param	canDispose	If a mouse click should dispose the window
     */
    public SplashWindow(Frame owner, Image splashImage, boolean canDispose) {
        super(owner);
        this.splashImage = splashImage;


        // Load the image
        MediaTracker mt = new MediaTracker(this);
        mt.addImage(splashImage,0);
        try {
            mt.waitForID(0);
        } catch(InterruptedException ie){}

        // Center the window on the screen.
        int imgWidth = splashImage.getWidth(this);
        int imgHeight = splashImage.getHeight(this);
        setSize(imgWidth, imgHeight);
        setLocationRelativeTo(null);

        // Florian Sonner (24.6.09)
        if(canDispose) {
	        // Users shall be able to close the splash window by
	        // clicking on its display area. This mouse listener
	        // listens for mouse clicks and disposes the splash window.
	        MouseAdapter disposeOnClick = new MouseAdapter() {
	            public void mouseClicked(MouseEvent evt) {
	                // Note: To avoid that method splash hangs, we
	                // must set paintCalled to true and call notifyAll.
	                // This is necessary because the mouse click may
	                // occur before the contents of the window
	                // has been painted.
	                synchronized(SplashWindow.this) {
	                    paintCalled = true;
	                    notifyAll();
	                }
	                setVisible(false);
	            }
	        };
	        addMouseListener(disposeOnClick);
        }
    }

    /**
     * Updates the display area of the window.
     */
    public void update(Graphics g) {
        // Note: Since the paint method is going to draw an
        // image that covers the complete area of the component we
        // do not fill the component with its background color
        // here. This avoids flickering.
        g.setColor(getForeground());
        paint(g);
    }
    /**
     * Paints the image on the window.
     */
    public void paint(Graphics g) {
        g.drawImage(splashImage, 0, 0, this);
        
        // Markus Hohenwarter (14. 4. 2006): add border to splashImage
        g.setColor(Color.darkGray);
        g.drawRect(0,0, getWidth()-1, getHeight()-1);

        // Notify method splash that the window
        // has been painted.
        // Note: To improve performance we do not enter
        // the synchronized block unless we have to.
        if (! paintCalled) {
            paintCalled = true;
            synchronized (this) { notifyAll(); }
        }
    }

    /**
     * Constructs and displays a SplashWindow.<p>
     * This method is useful for startup splashs.
     * Dispose the return frame to get rid of the splash window.<p>
     *
     * @param   splashImage The image to be displayed.
     * @return  Returns the frame that owns the SplashWindow.
     */
    public static Frame splash(Image splashImage) {
        Frame f = new Frame();
        SplashWindow w = new SplashWindow(f, splashImage, false);

        // Show the window.
        w.toFront();
        w.setVisible(true);


        // Note: To make sure the user gets a chance to see the
        // splash window we wait until its paint method has been
        // called at least by the AWT event dispatcher thread.
        if (! EventQueue.isDispatchThread()) {
            synchronized (w) {
                while (! w.paintCalled) {
                    try { w.wait(); } catch (InterruptedException e) {}
                }
            }
        }

        return f;
    }
}
