package eng;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.util.ArrayList;

import javax.swing.JFrame;

import reference.GameStateDirectory;

import defaults.Default;

import util.Audio;

@SuppressWarnings("serial")
public class Source extends JFrame implements Runnable {
	
	private Thread thread;
	
	private ArrayList<GameState> gameStateStack;
	private GameState currentGameState;
	
	private Data data;
	
	private Audio audio;
	private String currentAudio;
	
	public static void main(String[] args) {
		new Source();
	}
	
	private Source() {
		
		super(Default.getTitle());
		
		data = Default.getInitialData();
		gameStateStack = Default.getInitialStack();
		
		String operatingSystem = System.getProperty("os.name");
		data.addData("Operating System, " + operatingSystem);
		
		audio = new Audio();
		
		currentGameState = gameStateStack.get(gameStateStack.size() - 1);
		currentGameState.initiate(data);
		
		setAudio(currentGameState.getAudio());
		
		if(currentGameState.getCursor() != null)
			setCursor(currentGameState.getCursor());
		
		add(currentGameState);
		
		thread = new Thread(this);
		thread.start();
		
		if(Default.isFullScreen()) {
			
			GraphicsDevice gd =
					GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
			
			if(gd.isFullScreenSupported()) {

				setUndecorated(true);
				
				if(operatingSystem.indexOf("Mac") != -1)
					gd.setFullScreenWindow(this);
				
				else
					setSize((int)(Toolkit.getDefaultToolkit().getScreenSize().getWidth()),
							(int)(Toolkit.getDefaultToolkit().getScreenSize().getHeight()));
			}
			
			else
				setSize(500, 500);
		}
		
		else
			setSize(500, 500);
		
		setVisible(true);
		setFocusable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	public void paintComponent(Graphics g) {
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, getWidth(), getHeight());
	}
	
	@SuppressWarnings("static-access")
	public void run() {
		
		int timer = 0;
		
		while(Thread.currentThread() == thread) {
			
			currentGameState.updateInput();
			currentGameState.update();
			
			timer++;
			
			if(timer == Default.getGarbageCollectionPeriod()) {
				timer = 0;
				System.gc();
			}
			
			try {
				thread.sleep(Default.getFramePeriod());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			String audio = currentGameState.getNewAudio();
			
			if(audio != null)
				setAudio(audio);
			
			if(currentGameState.hasEnded() || currentGameState.isPaused())
				shiftGameState();
		}
	}
	
	public void shiftGameState() {
		
		if(currentGameState.getNextGameState() == null) {
			
			remove(currentGameState);
			
			data = currentGameState.getData();
			ArrayList<Integer> keysDown = currentGameState.getKeysDown();
			
			if(gameStateStack.size() == 1)
				System.exit(0);
			
			currentGameState = gameStateStack.get(gameStateStack.size() - 2);
			
			for(int i = 1; i < gameStateStack.size(); i++)
				if(gameStateStack.get(i).hasEnded())
					gameStateStack.remove(i);
			
			if(!currentGameState.isInitiated())
				currentGameState.initiate(data);
			else
				currentGameState.resume(data);
			
			currentGameState.setKeysDown(keysDown);
			
			setAudio(currentGameState.getAudio());
			
			if(currentGameState.getCursor() != null)
				setCursor(currentGameState.getCursor());
			
			add(currentGameState);
			
			currentGameState.requestFocus();
			
			revalidate();
		}
		
		else {
			
			remove(currentGameState);
			
			data = currentGameState.getData();
			ArrayList<Integer> keysDown = currentGameState.getKeysDown();
			
			currentGameState = GameStateDirectory.getGameState(currentGameState.getNextGameState());
			
			for(int i = 1; i < gameStateStack.size(); i++)
				if(gameStateStack.get(i).hasEnded())
					gameStateStack.remove(i);
			
			gameStateStack.add(currentGameState);
			
			if(!currentGameState.isInitiated())
				currentGameState.initiate(data);
			
			currentGameState.setKeysDown(keysDown);
			
			setAudio(currentGameState.getAudio());
			
			if(currentGameState.getCursor() != null)
				setCursor(currentGameState.getCursor());
			
			add(currentGameState);
			
			currentGameState.requestFocus();
			
			revalidate();
		}
	}
	
	private void setAudio(String str) {
		
		if(!str.equals(currentAudio) && !str.equals("")) {
			
			currentAudio = str;
			
			data.removeData("Current Audio, ");
			data.addData("Current Audio, " + currentAudio);
			
			audio.setAudio(str);
			audio.play();
		}
	}
}