// Copyright 2011-2012 Paulo Augusto Peccin. See licence.txt distributed with this file.

package org.javatari.pc.screen;

import java.awt.BufferCapabilities;
import java.awt.BufferCapabilities.FlipContents;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.ImageCapabilities;
import java.awt.image.BufferStrategy;
import java.lang.reflect.Constructor;
import java.util.Arrays;

import javax.swing.JFrame;

import org.javatari.utils.SwingHelper;

public final class DesktopScreenFullWindow extends JFrame implements MonitorDisplay {

	public DesktopScreenFullWindow(DesktopScreenWindow window) {
		// Creates our Window at the correct GraphicsConfig from the owner's location 
		super(SwingHelper.getGraphicsConfigurationForCurrentLocation(window));
		this.window = window;
		init();
	}

	private void init() {
		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		setLayout(null);
		setUndecorated(true);
		setBackground(Color.BLACK);
		setIgnoreRepaint(true);
		getContentPane().setBackground(Color.BLACK);
		getContentPane().setIgnoreRepaint(true);
		setIconImages(Arrays.asList(new Image[] { window.icon64, window.icon32, window.favicon }));
		setTitle(DesktopScreenWindow.BASE_TITLE + " - Fullwindow");
	}

	@Override
	public void setVisible(boolean visible) {
		super.setVisible(visible);
		if (visible) {
			canvasSetRenderingMode();
			SwingHelper.edtInvokeLater(new Runnable() {  @Override public void run() {
				repaint();
			}});
		}
	}

	@Override
	public void displaySize(Dimension size) {
		canvasOriginX = (getWidth() - size.width) / 2;
		canvasOriginY = (getHeight() - size.height) / 2;
		canvasEffectiveSize = size;
		repaint();
		if (bufferStrategy != null && bufferStrategy.getCapabilities().getFlipContents() != FlipContents.BACKGROUND) {
			clearBackgoundFrames = Monitor.MULTI_BUFFERING + 2;		// Extra 2 frames more than needed
		}
	}

	@Override
	public void displayMinimumSize(Dimension minSize) {
		// Full window is not manually resized
	}

	@Override
	public void displayCenter() {
		// Full window is always centered
	}

	@Override
	public Dimension displayEffectiveSize() {
		return canvasEffectiveSize;
	}

	@Override
	public Graphics2D displayGraphics() {
		Graphics2D canvasGraphics = (Graphics2D) (bufferStrategy != null ? bufferStrategy.getDrawGraphics() : getGraphics());
		// Clears the background when needed, but just for a few frames
		if (clearBackgoundFrames-- > 0) {
			canvasGraphics.setColor(Color.BLACK);
			canvasGraphics.clearRect(0, 0, getWidth(), getHeight());
		}
		canvasGraphics.translate(canvasOriginX, canvasOriginY);
		return canvasGraphics;
	}

	@Override
	public void displayFinishFrame(Graphics2D graphics) {
		graphics.dispose();
		if (bufferStrategy != null) bufferStrategy.show();
	}

	@Override
	public void displayClear() {
		Graphics2D canvasGraphics = displayGraphics();
		canvasGraphics.setColor(Color.BLACK);
		canvasGraphics.clearRect(0, 0, getWidth(), getHeight());
		displayFinishFrame(canvasGraphics);
	}

	@Override
	public Container displayContainer() {
		return this;
	}

	@Override
	// Gets the largest possible size at the default aspect
	public float displayDefaultOpenningScaleX(int displayWidth, int displayHeight) {
		int winW = getWidth();
		int winH = getHeight();
		float scaleX = winW / displayWidth;
		scaleX -= (scaleX % Monitor.DEFAULT_SCALE_ASPECT_X);		// Round multiple of the default X scale
		float h = scaleX / Monitor.DEFAULT_SCALE_ASPECT_X * displayHeight;
		while (h > winH + 35) {										// 35 is a little tolerance
			scaleX -= Monitor.DEFAULT_SCALE_ASPECT_X;				// Decrease one full default X scale
			h = scaleX / Monitor.DEFAULT_SCALE_ASPECT_X * displayHeight;
		}
		return scaleX;
	}

	@Override
	public void displayRequestFocus() {
		requestFocus();
	}

	@Override
	public void displayLeaveFullscreen() {
		window.displayLeaveFullscreen();
	}

	public void canvasSetRenderingMode() {
		if (Monitor.MULTI_BUFFERING <= 0) return;
		BufferCapabilities desiredCaps = new BufferCapabilities(
			new ImageCapabilities(true), new ImageCapabilities(true),
			Monitor.PAGE_FLIPPING ? FlipContents.BACKGROUND : null
		);
		Class<?> extBufCapClass = null;
		try {
			// Creates ExtendedBufferCapabilities via reflection to avoid problems with AccessControl
			extBufCapClass = Class.forName("sun.java2d.pipe.hw.ExtendedBufferCapabilities");
		} catch (Exception ex) {}
		// First try with vSync option
		if (extBufCapClass != null && Monitor.BUFFER_VSYNC != -1)
			try {
				// Creates ExtendedBufferCapabilities via reflection to avoid problems with AccessControl
				Class<?> vSyncTypeClass = Class.forName("sun.java2d.pipe.hw.ExtendedBufferCapabilities$VSyncType");
				Constructor<?> extBufCapConstructor = extBufCapClass.getConstructor(
					new Class[] { BufferCapabilities.class, vSyncTypeClass }
				);
	            Object vSyncType = vSyncTypeClass.getField(Monitor.BUFFER_VSYNC == 1 ? "VSYNC_ON" : "VSYNC_OFF").get(null);
	            BufferCapabilities extBuffCaps = (BufferCapabilities)extBufCapConstructor.newInstance(
	            	new Object[] { desiredCaps, vSyncType }
	            );
	            // Try creating the BufferStrategy
	            this.createBufferStrategy(Monitor.MULTI_BUFFERING, extBuffCaps);
			} catch (Exception ex) {}
		// Then try with remaining options (Flipping, etc)
		if (this.getBufferStrategy() == null)
			try {
				this.createBufferStrategy(Monitor.MULTI_BUFFERING, desiredCaps);
			} catch (Exception ex) {}
		// Last, use the default
		if (this.getBufferStrategy() == null) {
			System.out.println("Could not create desired BufferStrategy. Switching to default...");
			this.createBufferStrategy(Monitor.MULTI_BUFFERING);
		}
		bufferStrategy = this.getBufferStrategy();
		// Show info about the granted BufferStrategy
		if (bufferStrategy != null) System.out.println("Buffer Strategy: " + bufferStrategy.getClass().getSimpleName());
		BufferCapabilities grantedCaps = bufferStrategy.getCapabilities();
		System.out.println("Backbuffer Accelerated: " + grantedCaps.getBackBufferCapabilities().isAccelerated());
		System.out.println("PageFlipping Active: " + grantedCaps.isPageFlipping() + ", " + grantedCaps.getFlipContents());
		if (extBufCapClass != null && grantedCaps.getClass().equals(extBufCapClass))
			try {
				System.out.println("VSynch active: " + extBufCapClass.getMethod("getVSync",(Class<?>[])null).invoke(grantedCaps));
			} catch (Exception ex) {}
	}

	
	private final DesktopScreenWindow window;
	private int canvasOriginX;
	private int canvasOriginY;
	private Dimension canvasEffectiveSize;
	private int clearBackgoundFrames = 0;

	private BufferStrategy bufferStrategy;

	public static final long serialVersionUID = 1L;

}
