
package ludumdare.game;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.PriorityQueue;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.crusty.math.Vec2double;
import org.crusty.math.Vec2int;

import sun.audio.AudioPlayer;
import sun.audio.AudioStream;

public class Game extends Canvas {

	public static ParticleManager pm = new ParticleManager();
	
	static PriorityQueue<Entity> entities;
	
	public DepthComparator depthComparator = new DepthComparator();
	
	public static boolean[] keys;
	
	Font mainFont = new Font("Courier New", Font.BOLD, 24);
	static Font smallFont = new Font("Courier New", Font.BOLD, 12);
	
	/* GRAPHICS VARIABLES */
	
	BufferStrategy strategy;
	private long lastTime;
	private long dt;
	private long accumulator;
	private long deltaTime = 10000000; // 1 / (10 000 000 / 1 000 000 000) = 100 FPS;
	private GraphicsConfiguration gc;
	
	private long songStart;
	
	Vec2int screen = new Vec2int(0, 0);
	
	// Entities
	
	Rocket rocket;
	Entity ground;
	
	PieceOfRocket rocketBottom;
	PieceOfRocket rocketMiddle;
	PieceOfRocket rocketCapsule;
	PieceOfRocket rocketTip;
	
	private long genPurpAccum = 0;
	
	static Player player;
	
	static boolean notifyUpdateScreen = false;
	
	public Game() {
		loadImages();
		init();
		gameLoop();
	}
	
	public void init() {
		
		player = new Player(SpriteManager.getSprite("capsule.png"));
		
		keys = new boolean[150];
		entities = new PriorityQueue<Entity>(10, depthComparator);
		
		//screenMan = new ScreenManager();
		
		//entities.add(new Entity(SpriteManager.getSprite("ground.png")));
		PriorityQueue<Entity> rootEnts = new PriorityQueue<Entity>(10, depthComparator);
		rocket = new Rocket();
		rocket.depth = 1;
		rootEnts.add(rocket);
		ground = new Entity(SpriteManager.getSprite("ground.png"));
		rootEnts.add(ground);
		String[] rootMessages = { "Hold Space bar to take off!",
									"Good Luck Astroman!" };
		ScreenManager.setRoot(rootEnts, rootMessages);
		
		ScreenManager.currentScreen = ScreenManager.getRoot();
//		ScreenManager.currentScreen.backgroundStars = false;
		ScreenManager.currentScreen.setupBackgroundStars();
		
		PriorityQueue<Entity> screen2Entities = new PriorityQueue<Entity>(10, depthComparator);
		rocketBottom = new PieceOfRocket("rocketBottom.png");
		rocketMiddle = new PieceOfRocket("rocketMiddle.png");
		rocketCapsule = new PieceOfRocket("rocketCapsule.png");
		rocketTip = new PieceOfRocket("rocketTip.png");
		
		
		screen2Entities.add(rocketBottom);
		rocketBottom.pos.x = 200;
		rocketBottom.pos.y = 180;
		rocketBottom.bottom = true;
		rocketBottom.rotatePoint.set(47, 140);
		screen2Entities.add(rocketMiddle);
		rocketMiddle.pos.x = 200;
		rocketMiddle.pos.y = 180;
		rocketMiddle.rotatePoint.set(43, 72);
		screen2Entities.add(rocketCapsule);
		rocketCapsule.pos.x = 200;
		rocketCapsule.pos.y = 180;
		rocketCapsule.rotatePoint.set(45, 35);
		screen2Entities.add(rocketTip);
		rocketTip.pos.x = 200;
		rocketTip.pos.y = 180;
		rocketTip.rotatePoint.set(45, 14);
		
		String[] screen2Messages = {
				"To infinity, and behond.",
				"Press F to jettison fuel.",
				"To go where none have gone.", // Jettison time
				"Press B to jettison body.",
				"May the force be with you.", // 
				"Press T to jettison tip.",
				"Live long, and prosper.",
				"Congrats! You're in SPACE!",
				"Mission: 'Wormhole Discovery'"
		};
		Screen screen2 = new Screen(screen2Entities, screen2Messages);
//		screen2.backgroundStars = false;
		screen2.stars = true;
		screen2.nextScreen = ScreenManager.getFirstScreen(new Vec2int(0, 0), new Vec2double(240, 237)); // First randomly generated screen
		
		ScreenManager.currentScreen.nextScreen = screen2;
		entities.clear();
		entities.addAll(ScreenManager.currentScreen.entitiesInScreen);

		//currentScreen.notifyMessage("inc");
		
		/* SET UP WINDOW */
		
		JFrame container = new JFrame("The Adventures of ASTROMAN! - by Elliot Walmsley");
		
		JPanel panel = (JPanel) container.getContentPane();
		panel.setPreferredSize(new Dimension(500, 500));
		panel.setLayout(null);
		setBounds(0, 0, 500, 500);
		panel.add(this);
		
		setIgnoreRepaint(true);
		
		container.pack();
		container.setResizable(false);
		container.setVisible(true);
		container.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		addKeyListener(new KeyInputHandler());
		
		requestFocus();
		
		/* GRAPHICS SETUP */
		
		createBufferStrategy(2);
		strategy = getBufferStrategy();
		
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
	    GraphicsDevice gd = ge.getDefaultScreenDevice();
	    gc = gd.getDefaultConfiguration();
		
	}
	
	public BufferedImage loadImage(String str) {
		BufferedImage image = null;
		URL url = this.getClass().getClassLoader().getResource(str);
		try {
			image = ImageManager.makeColorTransparent(ImageIO.read(url), Color.RED);
			return image;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public void loadImages() {
		String[] images = { "rocket.png",
							"rocketBottom.png",
							"rocketCapsule.png",
							"rocketMiddle.png",
							"rocketTip.png",
							"ground.png",
							"fire.png",
							"star.png",
							"capsule.png",
							"planet1.png",
							"smoke.png",
							"jet.png",
							"bigstar.png",
							"blackhole.png",
							"bluestar.png",
							"planet2.png",
							"wormhole.png",
							"stationalpha.png"};
		for (String s : images) {
			SpriteManager.addSprite(s, new Sprite(loadImage(s)));
		}
	}
	
	public void gameLoop() {
		
		boolean running = true;
		boolean firstTime = true;
		
		// Load the tune and play it
		AudioStream song = null;
		InputStream in;
		try {
			in = new FileInputStream("test.mid");
			song = new AudioStream(in);
			AudioPlayer.player.start(song);
			songStart = System.currentTimeMillis();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// Create off-screen drawing surface
	    BufferedImage bi = gc.createCompatibleImage(500, 500);
	    
	    Graphics2D g = null;
	    Graphics graphics = null;
		
		while (running) {
			long now = System.nanoTime();
			dt = now - lastTime;
			float fps = 1000000000/dt;
			lastTime = now;
			
			accumulator += dt;
			
			if (firstTime) {
				accumulator = 0;
				firstTime = false;
			}
//			int count = 0;
			while (accumulator >= deltaTime) {
//				count++;
				logic(deltaTime);
				accumulator -= deltaTime;
			}
//			System.out.println("Count: " + count);
			
			g = bi.createGraphics();
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
			        RenderingHints.VALUE_ANTIALIAS_ON);
			
			// Clear
			g.setColor(Color.BLACK);
			g.fillRect(0, 0, 500, 500);
			
			// Stars
			g.setColor(Color.WHITE);
			if (ScreenManager.currentScreen.stars) {
				StarController.update(dt);
				StarController.draw(g);
			}
			if (ScreenManager.currentScreen.backStars) {
				ScreenManager.currentScreen.draw(g);
			}
			
			// Draw Entities
			Iterator<Entity> it = entities.iterator();
			while (it.hasNext()) {
				it.next().draw(g);
			}
			
			// Draw particles
			pm.draw(g);
			
			// Draw FPS
			g.setFont(smallFont);
			g.setColor(Color.WHITE);
			g.drawString("FPS: " + fps, 15, 20);
			
			// Intro Message
			
			if (MessageManager.getNum() == 0) {
				g.setFont(this.mainFont);
				g.drawString("The", 200, 100);
				g.drawString("Adventures", 150, 130);
				g.drawString("of", 210, 160);
				g.drawString("ASTROMAN.", 170, 190);
				g.setFont(Game.smallFont);
				g.drawString("a 48 hour game.", 50, 300);
				g.drawString("by Elliot Walmsley", 50, 320);
				g.drawString("Ludum Dare 19.", 50, 340);
			}
			
			// Draw Message
			g.setFont(this.mainFont);
			g.drawString("> " + MessageManager.getMessage(), 20, 50);

			// Song restart
			if (System.currentTimeMillis() > songStart + 1000 * 70) { // 60 seconds
				AudioPlayer.player.stop(song);
				
				// Reload (only way to loop)
				try {
					in = new FileInputStream("test.mid");
					song = new AudioStream(in);
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				AudioPlayer.player.start(song);
				AudioPlayer.player.start(song);
				songStart = System.currentTimeMillis();
				System.out.println("SONG RESTART");
			}
			
			// Blit image and flip...
			if (!strategy.contentsLost())
				graphics = strategy.getDrawGraphics();
	        graphics.drawImage(bi, 0, 0, null);
			
			if (!strategy.contentsLost())
				strategy.show();
			
			Thread.yield();
	        if (graphics != null) 
	            graphics.dispose();
			if (g != null)
				g.dispose();
		}
		
	}
	
	public void logic(long dt) {
		pm.update(dt);
		Iterator<Entity> it = entities.iterator();
		while (it.hasNext()) {
			it.next().logic(dt);
		}
		
//		if (keys[KeyEvent.VK_BACK_SPACE])
//			ScreenManager.notifyIncrement();
		
		// STATE SWITCHING
		switch (MessageManager.getNum()) {
			case 0: {
				if (keys[KeyEvent.VK_SPACE]) {
					ScreenManager.notifyIncrement();
					
					InputStream in;
					try {
						in = new FileInputStream("rocketLaunch.wav");
						AudioStream as = new AudioStream(in);       
						AudioPlayer.player.start(as);
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				break;
					}
			case 1: {
				if (rocket.pos.y < -400)
					ScreenManager.notifyIncrement();
				break;
			}
			case 2: {
				if (genPurpAccum < 5000000000L) {
					genPurpAccum += dt;
				} else {
					ScreenManager.notifyIncrement();
					genPurpAccum = 0;
				}
				break;
			}
			case 3: { // Jettison Fuel
				if (keys[KeyEvent.VK_F]) {
					ScreenManager.notifyIncrement();
					rocketBottom.activated = false;
					rocketBottom.acc.y = 0.4f;
					rocketBottom.acc.x = 0.1f;
					rocketBottom.rotationalVel = 0.001f;
					ParticleManager.addParticle(10, SpriteManager.getSprite("star.png"), 
							rocketBottom.pos.add(rocketBottom.rotatePoint.clone()), "jettisonSparks"); // Sparks
					ParticleManager.addParticle(1, SpriteManager.getSprite("smoke.png"), 
							rocketBottom.pos.add(rocketBottom.rotatePoint.clone()), "rocketSmoke");
					InputStream in;
					try {
						in = new FileInputStream("detatch.wav");
						AudioStream as = new AudioStream(in);       
						AudioPlayer.player.start(as);
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				break;
			}
			case 4: {
				if (genPurpAccum < 5000000000L) {
					genPurpAccum += dt;
				} else {
					ScreenManager.notifyIncrement();
					genPurpAccum = 0;
				}
				break;
			}
			case 5: {
				if (keys[KeyEvent.VK_B]) {
					ScreenManager.notifyIncrement();
					rocketMiddle.activated = false;
					rocketMiddle.acc.y = 0.4f;
					rocketMiddle.acc.x = 0.1f;
					rocketMiddle.rotationalVel = 0.001f;
					ParticleManager.addParticle(10, SpriteManager.getSprite("star.png"), 
							rocketMiddle.pos.add(rocketMiddle.rotatePoint.clone()), "jettisonSparks");
					ParticleManager.addParticle(1, SpriteManager.getSprite("smoke.png"), 
							rocketBottom.pos.add(rocketMiddle.rotatePoint.clone()), "rocketSmoke");
					InputStream in;
					try {
						in = new FileInputStream("detatch.wav");
						AudioStream as = new AudioStream(in);       
						AudioPlayer.player.start(as);
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				break;
			}
			case 6: {
				if (genPurpAccum < 5000000000L) {
					genPurpAccum += dt;
				} else {
					ScreenManager.notifyIncrement();
					genPurpAccum = 0;
				}
				break;
			}
			case 7: {
				if (keys[KeyEvent.VK_T]) {
					ScreenManager.notifyIncrement();
					rocketTip.activated = false;
					rocketTip.acc.y = 0.4f;
					rocketTip.acc.x = 0.1f;
					rocketTip.rotationalVel = 0.005f;
					ParticleManager.addParticle(10, SpriteManager.getSprite("star.png"), 
							rocketTip.pos.add(rocketTip.rotatePoint.clone()), "jettisonSparks");
					ParticleManager.addParticle(1, SpriteManager.getSprite("smoke.png"), 
							rocketBottom.pos.add(rocketTip.rotatePoint.clone()), "rocketSmoke");
					InputStream in;
					try {
						in = new FileInputStream("detatch.wav");
						AudioStream as = new AudioStream(in);       
						AudioPlayer.player.start(as);
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				break;
			}
			case 8: {
				if (genPurpAccum < 3000000000L) {
					genPurpAccum += dt;
				} else {
					ScreenManager.notifyIncrement();
					genPurpAccum = 0;
				}
				break;
			}
			case 9: {
				if (genPurpAccum < 2000000000L) {
					genPurpAccum += dt;
				} else {
					ScreenManager.notifyIncrement();
					genPurpAccum = 0;
				}
				break;
			}
			case 10: {
				if (genPurpAccum < 2000000000L) {
					genPurpAccum += dt;
				} else {
					ScreenManager.notifyIncrement();
					genPurpAccum = 0;
				}
				break;
			}
		}
		
		// if (notified of change
		if (notifyUpdateScreen) {
			updateScreen();
			notifyUpdateScreen = false;
		}
	}
	
	public static void notifyUpdate() {
		notifyUpdateScreen = true;
	}
	
	public static void main(String args[]) {
		Game g = new Game();
	}
	
	private class KeyInputHandler extends KeyAdapter {
		public void keyPressed(KeyEvent e) {
			if (e.getKeyCode() < 150) {
				keys[e.getKeyCode()] = true;
			}
		} 

		public void keyReleased(KeyEvent e) {
			if (e.getKeyCode() < 150) {
				keys[e.getKeyCode()] = false;
			}
		}
	}

	public static void updateScreen() {
		System.out.println("UPDATESCREEN");
		entities.clear();
		entities.addAll(ScreenManager.currentScreen.entitiesInScreen);
		System.out.println("after");
		
	}
	
}
