/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package game;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 *
 * @author A KUMA
 */
public class SpaceInvaders extends JFrame {
    int xLienzo=45*16,yLienzo=600,xShooter=300,maxB=60,i,j;
    boolean controls[]={false,false,false};//almacena teclas de control{left-right-spacebar}
    boolean GameOver=false;//medio de control para gameover
    Bullet bullets[]=new Bullet[maxB];//array for bullets
    shot shots[]=new shot[maxB];//array for threads of bullets       
    JLabel info,infoBullet,infoGrl;
    int velG=700,velB=400,nLInv=5,nInv=10;
    boolean demo=false;//es area demo
    
    lienzo lienzoD;
    Score score=new Score(xLienzo,yLienzo);
    
                //area pruevas
    shooter shot=new shooter(xShooter,570);//  shoter
    Invader invaders=new Invader(xLienzo/4,40,nInv,nLInv);//invaders
    //posicion inicial 100,100 grid (posicion de inv solo cambi desde inv!?)
    //controles del game
    ControlGameMov left=new ControlGameMov();
    ControlGameShot right=new ControlGameShot();
    shotInv shotInv=new shotInv();
    Acert acertInv=new Acert();
    
    MoveGridInv MoveGridInvaders=new MoveGridInv();//mueve grid de invaders
    SpaceInvaders(boolean UNdemo) {
        demo=UNdemo;

        this.getContentPane().setLayout (new BorderLayout());//crea layout gral
        if(demo){
        infoBullet=new JLabel("- B[xx]X[x][x]Inv - ");
        info=new JLabel("--------------------");
        infoGrl=new JLabel("gral");
        JPanel infoP=new JPanel(new FlowLayout(0));
        infoP.add(infoBullet);
        infoP.add(info);
        infoP.add(infoGrl);
        
        this.add(  infoP ,BorderLayout.SOUTH);
        }
        lienzoD=new lienzo();
        this.getContentPane().add ( lienzoD,BorderLayout.CENTER);//agrega lienzo principal
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
        
this.addWindowListener(new WindowAdapter(){
    @Override
    public void windowClosing(WindowEvent we){
        GameOver=true;//termina Threads
        Sound.Back6.stop();
        Sound.Acert.stop();
        Sound.Shot.stop();
        Sound.ShotInv.stop();
    }
    });
        this.setTitle("Space Invaders Game");
        pack();
        setVisible(true);
        setResizable(false);
    }
    /*ver la posibilidad de crar todaas las clases afuera
     * y solo arrancarlas desde aca.. 
     */
    class lienzo extends JPanel{//lienzo contruye todo...

        public lienzo()  {
            int i;

            this.setBackground(Color.BLACK);
            this.setPreferredSize(new Dimension(xLienzo, yLienzo));
            //notese que no se uso this para rferir el keyEvent a 'this'
            addKeyListener((KeyListener)new ControlGame());
            setFocusable(true);//recibe foco
            MoveGridInvaders.start();
            left.start();
            right.start();
            for(i=0;i<maxB;i++){//inicializa bullets
                bullets[i]=new Bullet(0,0,0);
            }
            shotInv.start();
            acertInv.start();
            //Sound.Back4.loop();
            Sound.Back6.loop();
        }

        @Override
        public void paint(Graphics g){
            //if(!GameOver){
            
            super.paint(g);//dibuja a si mismo
            shot.dibuja(g);//dibuja el shoter
            //invaders.getLim();//verif limutes antes de dibujar
            invaders.dibuja(g);//dibuja los inv
            
            for(i=0;i<maxB;i++){//dibuja las balas
                bullets[i].dibuja(g);
            }
            score.dibuja(g);//dibuja el score
            if(GameOver){gameOver(g);}
            //}
        }
    /*clase con keyListener para ver que teclas estan presionadas
     * y cuales dejarin de presionarse
     */
        class ControlGame implements KeyListener{
            @Override
            public void keyTyped(KeyEvent ke) {
            }
            @Override
            public synchronized void keyPressed(KeyEvent ke) {
                switch(ke.getKeyCode()){
                    case KeyEvent.VK_LEFT:
                        controls[0]=true;
                        break;
                    case KeyEvent.VK_RIGHT:
                        controls[1]=true;
                        break;
                    case KeyEvent.VK_SPACE:
                        controls[2]=true;
                        break;
                }
                //notifyAll();
            }
            @Override
            public synchronized void keyReleased(KeyEvent ke) {
                switch(ke.getKeyCode()){
                    case KeyEvent.VK_LEFT:
                        controls[0]=false;
                        break;
                    case KeyEvent.VK_RIGHT:
                        controls[1]=false;
                        break;
                    case KeyEvent.VK_SPACE:
                        controls[2]=false;
                        break;
                }
                //notifyAll();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException{
    new SpaceInvaders(true);
    }
    public void gameOver(Graphics g){
        Sound.Back6.stop();
        Sound.GameOver.play();
        Font boldFont = new Font("Helvetica", Font.BOLD, 70);
        g.setFont(boldFont);
        String mostrar="Game Over";
        String mostrar2="Score :"+score.score;
        g.setColor(Color.RED);
        g.drawString(mostrar, xLienzo/3, yLienzo/3);
        g.drawString(mostrar2, xLienzo/3, 2*yLienzo/4);
        //GameOver=false;
    }
    public void newGrid(){
        if(nLInv<9){nLInv+=1;}
        invaders=new Invader(50,50,nInv,nLInv);//crea nuevos invaders
        velG-=65;
        velB-=18;
        //cambia vel de grid
    }
    /*las si lineas son para el control del shooter
     */
    public  void movShoter(int n){
        int  aux= shot.getX()+n*10;
        if(0<aux&&aux<xLienzo-50){
            shot.setX(shot.getX()+n*10);
            repaint();}
  }
    class ControlGameMov extends Thread{
        @Override
        public void run(){
            while(!GameOver){
            try {
                sleep(10);
            } catch (InterruptedException ex) {}
            while(controls[0]&&!controls[1]){
                movShoter(-1);
                    try {
                        sleep(80);
                    } catch (InterruptedException exx) {}
            }
            while(controls[1]&&!controls[0]){
                movShoter(1);
                    try {
                        sleep(80);
                    } catch (InterruptedException exx) {}
            }
        }
    }
    }
    /*verifica cuando se dispara y controla el tiempo entre disparos
     */
    class ControlGameShot extends Thread{
        int i=0;
        @Override
        public void run(){
            while(!GameOver){
                try {
                    sleep(1);
                } catch (InterruptedException ex) {}
                while(controls[2]){
                    for(i=0;i<maxB;i++){
                    if(bullets[i].disponible()){//busca una bala disponilbe dentro del array
                        bullets[i]=new Bullet(shot.getXB(),shot.getYB(),1);
                        shots[i]=new shot(30,30,i,1);
                        shots[i].start();
                        Sound.Shot.play();
                        
                        break;
                    }
                    }

                        try {
                            sleep(velB);
                            //sleep(150);
                        } catch (InterruptedException exx) {}
                }
            }

        }
    }
    //verifica si se acerto al blanco
    public class Acert extends Thread{
        int i,j,iB;
        @Override
        public void run(){
            while(!GameOver){
                try {
                    //lo dormimos mientras se repinta sig bala y dejar spacio en cpu
                    sleep(99);
                } catch (InterruptedException ex) {
                    Logger.getLogger(SpaceInvaders.class.getName()).log(Level.SEVERE, null, ex);
                }
                for(iB=0;iB<maxB;iB++){//para cada bala
                    if(bullets[iB].getWho()<0){//si bala es desde inv
                        if(bullets[iB].getBalaPosition().intersects(shot.getRectangleBase()) ||
                           bullets[iB].getBalaPosition().intersects(shot.getRectangleCanon()))
                        {
                            if(demo){
                            if(iB<10)infoBullet.setText("- B[0"+iB+"]X["+i+"]["+j+"]Inv -");
                            info.setText(" |LimIzq["+invaders.getIzq()+"] |-| LimDer["+invaders.getDer()+"] |-| LimInf["+invaders.getInf()+"] |-| ");
                             }
                            GameOver=true;
                            repaint();//repintamos
                        }
                    }else{
                        if(bullets[iB].getWho()>0){//si bala es desde shotter
                        for(j=0;j<nInv;j++){//con cda inv
                            for(i=0;i<nLInv;i++){
                                //si inv[i,j] no existe continua con sig...
                                if(invaders.EstadoInv(i, j)){
                                if(bullets[iB].getBalaPosition().intersects(invaders.getRectangleInv(i, j)))
                                {
                                    if(demo){
                                    if(iB<10)infoBullet.setText("- B[0"+iB+"]X["+i+"]["+j+"]Inv -");
                                    else     infoBullet.setText("- B["+iB+"]X["+i+"]["+j+"]Inv -");
                                    info.setText(" |LimIzq["+invaders.getIzq()+"] |-| LimDer["+invaders.getDer()+"] |-| LimInf["+invaders.getInf()+"] |-| ");
                                     }
                                    invaders.setDeadInv(i,j);//muere invader 
                                   if(invaders.win())newGrid();//si murieron all inv nuevagri invaders
                                    bullets[iB].setEstado(true);//cambiamos estado de bala y stop thread
                                    bullets[iB]=new Bullet(0,0,0);//reposicionamos bala
                                    repaint();//repintamos
                                    score.setScore(score.getScore()+1);//agregamos score
                                }
                                }
                            }
                        }
                        }
                    }
                }
            }
        }
    }
    /*Thread/hilo q controla una bala y la mueve hasta  q salga del lienzo
     * entonces la marca como desocupada en el array,ademas de cntrolar su vel
     */
    class shot extends Thread{
        int y0,x0,numB,n;//posiones de la bala
        public shot(int unX, int unY,int i,int UNn){
            y0=unY;
            x0=unX;
            numB=i;
            n=UNn;
        }
        @Override
        public void run(){
            
                bullets[numB].setEstado(false);//cambia estado de bala a no disponible
                    //mientras la bala permanesca en el lienzo y no sea puesta en libertad
                    //al colisionar con un inv
                    while((0<bullets[numB].yb&&bullets[numB].yb<yLienzo)&&!bullets[numB].disponible()&&!GameOver){
                        bullets[numB].mueve(n);
                        repaint();
                        //acert(numB);//verifica si la bala acerto a un inv
                        try {
                            sleep(100);
                        } catch (InterruptedException ex) {}

                    }
                //si no fue liberada por colision se libera por fi de lienzo
                bullets[numB].setEstado(true);//ahora ya esta disponible
            }
        
    }
    /*clase de shot inv
     */
    class shotInv extends Thread{
            Random r = new Random();
               int i,j,b,aux=0,BInv=0;
        @Override
        public void run(){
            while(!GameOver){
                aux=(r.nextInt()%10)*200;
                if(aux<0)aux=aux*-1;//q tiempo duerme hasta sig disp inv
                j=r.nextInt()%10;
                if(j<0){j*=-1;}
                System.out.println(aux+"---"+i+"-"+j);
                try {

                    sleep(aux);//time hasta sig disp d line
                } catch (InterruptedException exx) {}
                for(i=nLInv-1;i>=0;i--){//busca en q line sta el inv inf
                       
                        if(invaders.EstadoInv(i, j)){//busca inv inf 
                        for(b=0;b<maxB;b++){
                            if(bullets[b].disponible()){//busca una bala disponilbe dentro del array
                            bullets[b]=new Bullet(invaders.getXInv(j),invaders.getYInv(i),-1);//dispara
                            shots[b]=new shot(30,30,b,-1);
                            shots[b].start();
                            if(!GameOver){Sound.ShotInv.play();}
                            
                            break;
                            }
                        }
                        break;
                        }
                        
                }
            }
        }
    }
    /*
     la sig class fue disenada para matener la class invader aparte ypoder trabajar
     * aparte.asi la sig class solo se encarga del mov d grid invaders
     */
    class MoveGridInv extends Thread{
     
         int dx,dy,xgr=44,ygr=44;//xr es el salto de mov; yr es e spaciado entre lineas..!
        public void saltoLineaInv(){
            dy=invaders.getSup()+ygr;
            invaders.setY(dy);
            invaders.limInf+=ygr;
            invaders.limSup+=ygr;
            invaders.camina();
            repaint();
            try {
                sleep(velG);
            } catch (InterruptedException ex) {}
        }
        public void mueveGrid(int n){
            if(n>0){dx=invaders.getX()+xgr;}
            else{dx=invaders.getX()-xgr;}
            invaders.setX(dx);
            invaders.limDer+=n*xgr;
            invaders.limIzq+=n*xgr;
            invaders.camina();
            repaint();
                                
            try {
                sleep(velG);
            } catch (InterruptedException ex) {}
        }
        @Override
        public void run(){
            while(!GameOver){
            while(invaders.getInf() < (yLienzo-110)){//while no llege a yLienzo/4 go
                while(invaders.getDer()<=xLienzo&&!GameOver){//de izq a Der
                   if((invaders.getDer()+xgr)<xLienzo)//si el mov no lo saca del lienzo continua
                   {mueveGrid(1);
                   if(demo){infoGrl.setText(" -Mov[Izq-Der]- ");}}
                   else{break;}//si mov sca del lienzo baja grid
                }
                if(!GameOver){saltoLineaInv();}
                while(invaders.getIzq()>0&&invaders.getIzq()<xLienzo&&!GameOver){//de Der a Izq
                   if((invaders.getIzq()-xgr)>=0)//si el mov no lo saca del lienzo continua    
                   {mueveGrid(-1);
                   if(demo){infoGrl.setText(" -Mov[Der-Izq]- ");}}
                   else{break;}
                }
                if(!GameOver){saltoLineaInv();}
            }

            GameOver=true;
            if(demo){infoGrl.setText("game over");}
            repaint();
        }
            
        }
    }
}