package spaceinvaders.panels;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JPanel;
import javax.swing.Timer;

import spaceinvaders.images.Images;
import spaceinvaders.objects.Block;
import spaceinvaders.objects.Enemie;
import spaceinvaders.objects.Missile;
import spaceinvaders.objects.Player;

@SuppressWarnings("serial")
public class ContentPanel extends JPanel {
	Player player;
	Timer framestimer, shipstimer, missiletimer;
	BufferedImage[] images;
	ArrayList<Enemie> enemies;
	ArrayList<Missile> missiles;
	ArrayList<Block> blocks;
	int direction;
	boolean gameover;
	
	public ContentPanel(){
		setBackground(Color.black);
		images = new BufferedImage[5];
		images[0] = Images.enemie1;
		images[1] = images[2] = Images.enemie2;
		images[3] = images[4] = Images.enemie3;
		blocks = new ArrayList<Block>();
		player = new Player(200,700);
		enemies = new ArrayList<Enemie>();
		missiles = new ArrayList<Missile>();
		
		this.addKeyListener(player);
		this.addKeyListener(new KeyAdapter() {
			@Override
			public void keyTyped(KeyEvent e) {
				super.keyTyped(e);
				if(e.getKeyChar() == ' '){
					//only send new missile if there aren't any other in the game launched by the player
					boolean launched = false;
					for(Missile m:missiles){
						if(m.getSender() == 'p'){
							launched = true;
							break;
						}
					}
					if(!launched){
						missiles.add(new Missile(player.getX()+player.getWidth()/2-3, player.getY(), -1, 'p'));
					}
				}else if(e.getKeyChar() == 'r'){
					reset();
				}
			}
		});
		this.setFocusable(true);
		
		//update 60fps
		framestimer = new Timer(1000/30, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				repaint();
			}
		});

		//ships moving
		direction =  1;
		shipstimer = new Timer(1000/1, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int tempdirection = direction;
				for(Enemie enemie:enemies){
					enemie.setLocation((int)(enemie.getX()+(8*direction)), enemie.getY());
					if(enemie.getX()+(8*direction) <= 5 || enemie.getBorder().getMaxX()+(8*direction) >= 780){
						tempdirection = direction * -1;
					}
				}
				if(direction != tempdirection){
					direction = tempdirection;
					if(shipstimer.getDelay() -100 > 0) shipstimer.setDelay(shipstimer.getDelay()-100);
					for(Enemie enemie:enemies){
						enemie.setLocation((int)(enemie.getX()), enemie.getY()+15);
						if(enemie.getBorder().getMaxY() > 450){
							gameOver();
						}
					}
				}
				//random missile generate
				double random = Math.random() *shipstimer.getDelay();
				if(random >= 0 && random < 200){
					int column = (int) (Math.random()*12);
					Enemie lowestobject = null;
					boolean first = true;
					for(Enemie enemie:enemies){
						if(enemie.getColumn() == column && (first || enemie.getRow() > lowestobject.getRow())){
							lowestobject = enemie;
							first = false;
						}
					}
					if(lowestobject != null){
						missiles.add(new Missile(lowestobject.getX()+lowestobject.getWidth()/2, lowestobject.getY()+lowestobject.getHeight(), 1, 'c'));
					}
				}
			}
		});
		
		//missile animator
		missiletimer = new Timer(1000/30, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Iterator<Missile> i = missiles.iterator();
				while(i.hasNext()){
					Missile m = i.next();
					m.recalculate();
					Enemie ecollision = m.shipCollision(enemies);
					if(m.outOfScreen(0,0,getWidth(),getHeight())){
						i.remove();
					}else if(m.getSender() != 'p' && m.playerCollision(player)){
						player.explode();
						i.remove();
						if(player.getLives() == 0)	gameOver();
					}else if(m.getSender() != 'c' &&  ecollision != null){
						i.remove();
						player.setScore(player.getScore() + ecollision.getDestroyScore());
						enemies.remove(ecollision);
						if(enemies.size() == 0){
							createEnemies();
							player.setLives(player.getLives()+1);
						}
					}
					for(Block b: blocks){
						if(b.missileCollision(m)){
							i.remove();
						}
					}
				}
			}
		});
		missiletimer.start();
		shipstimer.start();
		framestimer.start();
		
		createBlocks();
		createEnemies();
	}
	public void gameOver(){
		repaint();
		missiletimer.stop();
		shipstimer.stop();
		framestimer.stop();
		gameover = true;
	}
	public void reset(){
		missiles.clear();
		player.reset();
		createEnemies();
		createBlocks();
		gameover=false;
		missiletimer.start();
		shipstimer.start();
		framestimer.start();
	}
	
	public void createEnemies(){
		direction = 1;
		shipstimer.setDelay(1000);
		enemies.clear();
		for(int i = 0; i < 55; i++){
			enemies.add(new Enemie(images[i/11], (50*i)%550 +10, 50*(int)(i/11)+100, i/11, i%11));		
		}
	}
	public void createBlocks(){
		blocks.clear();
		blocks.add(new Block(50,500)); 
		blocks.add(new Block(250,500));
		blocks.add(new Block(450,500));
		blocks.add(new Block(650,500));
	}
	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D)g;
		g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		
		//Draw border
		g2.setStroke(new BasicStroke(10));
		g2.setColor(new Color(0,255,60));
		g2.drawRect(0, 0, getWidth(), getHeight());
		//score and lives
		g.setFont(new Font("TimesRoman", Font.PLAIN, 28)); 
		g2.drawString("Score: " + player.getScore() , 40,40);
		int spacing = 0;
		for(int i = 0; i < player.getLives(); i++){
			g2.drawImage(Images.player, null, 750+spacing,20);
			spacing -= 50;
		}
		
		//Draw player
		player.draw(g2);
		//Draw enemies
		for(Enemie e:enemies){
			e.draw(g2);
		}
		//Draw blocks
		for(Block b:blocks){
			b.draw(g2);
		}
		//draw missiles
		for(Missile m:missiles){
			m.draw(g2);
		}		
		if(gameover){
			g2.setColor(Color.green);
			g.setFont(new Font("TimesRoman", Font.PLAIN, 130)); 
			g2.drawString("Game Over", 30, 300);
			g.setFont(new Font("TimesRoman", Font.PLAIN, 90));
			g2.drawString("Score:" + player.getScore(), 30, 400);
			g2.setPaint(new Color(255, 0, 0,100));
			g2.fillRect(0, 0, getWidth(), getHeight());
		}
		Toolkit.getDefaultToolkit().sync();
	}
}
