package jp.ac.kyutech.mns.ist;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventListener;
import java.util.Iterator;

import javax.swing.JFrame;

import jp.ac.kyutech.mns.ist.util.FadeTimer;

import edu.umd.cs.piccolo.PCanvas;
import edu.umd.cs.piccolo.nodes.PText;

public class FullScreenableJFrame extends JFrame {
	private static final long serialVersionUID = -7829070254199139114L;
	private static final Dimension DEFAULT_FRAME_DIMENSION = new Dimension(770, 600);
	public transient static Color messageColor = new Color(204,238,255);

	private static final Point DEFAULT_FRAME_POSITION = new Point(0, 30);
	private final GraphicsDevice graphicsDevice;
	private transient EventListener escapeFullScreenModeListener;

	public PCanvas canvas;

	public static void main(String[] arg){
		FullScreenableJFrame jf = new FullScreenableJFrame("hoge");
		jf.setSize(FullScreenableJFrame.DEFAULT_FRAME_DIMENSION);
		jf.setVisible(true);
	}
	public FullScreenableJFrame(String txt){
		this(txt,false,null);
	}
	public FullScreenableJFrame(String txt, boolean isFullScreenMode, PCanvas ca){
		super(txt);
		graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
		if (ca == null) canvas = new PCanvas();
		//		addF11FullScreenModeListener();
	}

	public PCanvas getCanvas(){
		return canvas;
	}
	public Rectangle getDefaultFrameBounds() {
		return new Rectangle(DEFAULT_FRAME_POSITION, DEFAULT_FRAME_DIMENSION);
	}
	public void setFullScreenMode(final boolean fullScreenMode) {
		if (fullScreenMode != isFullScreenMode() || !isVisible()) {
			if (fullScreenMode) {
				switchToFullScreenMode();
			}
			else {
				switchToWindowedMode();
			}
		}
	}
	public boolean isFullScreenMode() {
		return graphicsDevice.getFullScreenWindow() != null;
	}
	public void addF11FullScreenModeListener() {
		removeF11FullScreenModeListener();
		escapeFullScreenModeListener = new KeyAdapter() {
			public void keyPressed(final KeyEvent aEvent) {
				if (aEvent.getKeyCode() == KeyEvent.VK_F11) {
					setFullScreenMode(false);
				}
			}
		};
		getCanvas().addKeyListener((KeyListener) escapeFullScreenModeListener);
	}
	private void switchToFullScreenMode() {
		addF11FullScreenModeListener();

		if (isDisplayable()) {
			dispose();
		}

		setUndecorated(true);
		setResizable(false);
		graphicsDevice.setFullScreenWindow(this);

		if (graphicsDevice.isDisplayChangeSupported()) {
			chooseBestDisplayMode(graphicsDevice);
		}
		validate();
		showFadingMessage("フルスクリーンモードを終了するには[F11]をおしてください", messageColor, Color.black, 5, 0.9f);
	}

	public void showFadingMessage(String s, Color bc, Color fc, float scale, float trans){
		PText pt = new PText(s);
		pt.setScale(scale);
		pt.setTransparency(trans);
		pt.setPaint(bc);
		pt.setTextPaint(fc);

		getCanvas().getCamera().addChild(pt);
		pt.setOffset((getCanvas().getCamera().getBoundsReference().getWidth()-pt.getWidth()*pt.getScale())/2,
				(getCanvas().getCamera().getBoundsReference().getHeight()-pt.getHeight()*pt.getScale())/2);

		new FadeTimer(pt, 2000,1000, true);
	}

	private void switchToWindowedMode() {
		removeF11FullScreenModeListener();

		if (isDisplayable()) {
			dispose();
		}

		setUndecorated(false);
		setResizable(true);
		graphicsDevice.setFullScreenWindow(null);
		validate();
//		setVisible(true);
	}
	public void removeF11FullScreenModeListener() {
		if (escapeFullScreenModeListener != null) {
			canvas.removeKeyListener((KeyListener) escapeFullScreenModeListener);
			escapeFullScreenModeListener = null;
		}
	}

	protected void chooseBestDisplayMode(final GraphicsDevice device) {
		final DisplayMode best = getBestDisplayMode(device);
		if (best != null) {
			device.setDisplayMode(best);
		}
	}

	/**
	 * Finds the best display mode the graphics device supports. Based on the
	 * preferred modes.
	 * 
	 * @param device the device being inspected
	 * 
	 * @return best display mode the given device supports
	 */
	protected DisplayMode getBestDisplayMode(final GraphicsDevice device) {
		final Iterator<?> itr = getPreferredDisplayModes(device).iterator();
		while (itr.hasNext()) {
			final DisplayMode each = (DisplayMode) itr.next();
			final DisplayMode[] modes = device.getDisplayModes();
			for (int i = 0; i < modes.length; i++) {
				if (modes[i].getWidth() == each.getWidth() && modes[i].getHeight() == each.getHeight()
						&& modes[i].getBitDepth() == each.getBitDepth()) {
					return each;
				}
			}
		}
		return null;
	}
	protected Collection<DisplayMode> getPreferredDisplayModes(final GraphicsDevice device) {
		final ArrayList<DisplayMode> result = new ArrayList<DisplayMode>();

		result.add(device.getDisplayMode());
		/*
		 * result.add(new DisplayMode(640, 480, 32, 0)); result.add(new
		 * DisplayMode(640, 480, 16, 0)); result.add(new DisplayMode(640, 480,
		 * 8, 0));
		 */
		return result;
	}
}
