package Engine;

import Sprites.*;

import javax.swing.*;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Random;
import java.util.Vector;

/**
 * Created by sagi on 12/18/15.
 */



public class GameEngine extends MouseAdapter {
	private final int PIPE_ACC = 10, PIPE_WIDTH = 90, PIPE_INTERVAL_TIME = 2000;
	public boolean gameOn , gameOver, isFirstGame, canScore;
	private Bird bird;
	private Vector<Sprite> pipes; //will save all laser shots and asteroids which are currently on the screen.
	private int pWidth, pHeight;	//panel dimensions
	private Timer pipeTimer;		//interval to create new pipe
	private Random r;
	private int score;
	private BufferedImage sceneImage;
	private int heighScore;

	private Vector<SideScollerBackground> backgrounds; //Background elements
	private Vector<AudioClip> successSounds;

	private AudioClip themeAudioClip;
	private final URL themeURL= getClass().getResource("/Sounds/theme.wav");

	public GameEngine(int width, int height){


		//initialize variables and load audio\image files.
		this.canScore = true;
		this.isFirstGame = true;
		this.gameOver = true;
		this.pWidth = width;
		this.pHeight = height;
		try {
			themeAudioClip = Applet.newAudioClip(themeURL);
		}catch (Exception e){
			themeAudioClip = null;
		}

		if(themeAudioClip != null) {

			themeAudioClip.loop();
		}
		r = new Random();
		sceneImage = new BufferedImage(width, height, Image.SCALE_SMOOTH);
		loadSuccessSounds();
		startNewGame();
		heighScore = 0;


	}



	/**
	 * initialize and reset vars and timers to "new game" configuration. 
	 */
	private void startNewGame(){
		this.gameOn = true;
		pipeTimer = new Timer(PIPE_INTERVAL_TIME, new PipeTimerListener());
		backgrounds = new Vector<>();
		initBackgrounds();
		initGame();
	}

	/**
	 * Setup all actors in the game to a new game - reset timer
	 */
	private void initGame(){
		pipes = new Vector<>();

		this.bird = new Bird(100, this.pWidth, this.pHeight, 45);
		this.score = 0;
		gameOn = true;
		pipeTimer.start();


	}

	// Loads soundFX Vector
	private void loadSuccessSounds(){
		successSounds = new Vector<>();
		for (int i = 1 ; i < 5 ; i++){
			successSounds.add(Applet.newAudioClip(getClass().getResource("/Sounds/pass"+i+".wav")));
		}
	}
	//initialize background Sprites
	private void initBackgrounds(){
		backgrounds.add(new SideScollerBackground(pWidth, pHeight, 2, "skyLine.png", pWidth, pHeight));
		backgrounds.add(new SideScollerBackground(pWidth, pHeight, 5, "trees.png", pWidth + 50, pHeight));
		backgrounds.add(new SideScollerBackground(pWidth, pHeight, 10, "ground.png", pWidth, 45));

	}



	/**
	 * returns score
	 * @return
	 * int
	 */
	public int getScore(){
		return score;
	}

	/**
	 * returns gameOver flag
	 * @return
	 * boolean
	 */
	public boolean isGameOver(){
		return this.gameOver;
	}

	public int getHeighScore() { return this.heighScore;}


	/**
	 * Create a new Pipe on a random position.
	 */
	private void createPipe(){
		int pipeLoc = (r.nextInt(pHeight-40)+40) * -1;
		pipes.add(new Pipe(pipeLoc, pWidth, pHeight, PIPE_ACC, PIPE_WIDTH, pHeight * 2));
	}



	/**
	 * Update all sprites, including collision handling.
	 */
	public void update(){
		if(!gameOver) {
			bird.update();
			for(int i=0; i<pipes.size(); i++){
				pipes.elementAt(i).update();
			}

			for(int i = 0 ; i < backgrounds.size() ; i++){
				backgrounds.elementAt(i).update();
			}
			collisionHandler();
		}
	}

	/**
	 * Checks if a collision has occurred.
	 * in case of missile hitting an asteroid - they are both removed.
	 * in case of asteroid hitting the ship - round over.
	 */
	private void collisionHandler() {

		//Ikaros - dont fly too high, dont fly to low.
		if (bird.getLocY() >= pHeight - ( bird.getSWidth() + backgrounds.lastElement().getsHeight())|| bird.getLocY() <= 0) {
			pipeTimer.stop();
			gameOver = true;
			heighScore = score > heighScore ? score : heighScore;

		}

		//pipe out of screen
		if (!pipes.isEmpty() && pipes.elementAt(0).getLocX() + PIPE_WIDTH < 0) {
			canScore = true;
			pipes.remove(0);
		}


		//pipe vs. bird
		if (!pipes.isEmpty() && CollisionUtil.collidesWith(bird, pipes.elementAt(0))){
			gameOver = true;
			pipeTimer.stop();
			heighScore = score > heighScore ? score : heighScore;
		}

		//passed the pipe?
		if(canScore && !pipes.isEmpty() && bird.getLocX() >= pipes.elementAt(0).getLocX() + pipes.elementAt(0).getSWidth()) {
			score++;
			canScore = false;
			successSounds.elementAt(r.nextInt(4)).play();
			heighScore = score > heighScore ? score : heighScore;

		}

	}

	/**
	 * render buffered image.
	 * @param panel
	 * JPanel
	 */
	public void render(JPanel panel){
		sceneImage = new BufferedImage(this.pWidth, this.pHeight, Image.SCALE_FAST); // Empty Scene
		renderScene(sceneImage.getGraphics(), panel); // Paint new Scene
	}


	/**
	 * Draws all sprites
	 * @param g
	 * Graphics
	 * @param panel
	 * Jpanel
	 */
	public void renderScene(Graphics g, JPanel panel){
		backgrounds.elementAt(0).drawSprite(g, panel);
		backgrounds.elementAt(1).drawSprite(g, panel);
		bird.drawSprite(g, panel);
		for(int i=0; i<pipes.size(); i++){
			pipes.elementAt(i).drawSprite(g, panel);
		}
		backgrounds.elementAt(2).drawSprite(g, panel);


	}

	/**
	 * creates an new asteroid each 5 seconds	 *
	 */
	private class PipeTimerListener implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent actionEvent) {
			createPipe();
		}
	}

	//mouse clicked starts game Or jumps
	public void mousePressed(MouseEvent e){
		if(gameOver){
			this.isFirstGame = false;
			gameOver = false;
			initGame();
		} else {
			bird.jump();
		}
	}



	/**
	 * returns sceneImage
	 * @return
	 * BufferedImage
	 */
	public BufferedImage getScene(){
		return this.sceneImage;
	}


}
