/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ManicMiner;

import javax.microedition.lcdui.game.*;

/**
 *
 * @author supervisor
 */
public class Personaje {

    private int vidas;

    //Sprite del personaje
    private Sprite sp;

    boolean saltando;
    boolean enPasarela;
    boolean cayendo;

    int salto[] = {-4,-4,-3,-3,-2,-2,-1,-1,0,0,1,1,2,2,3,3,4,4}; //Indica cuanto tiene que avanzar en y cada iteracion

    int cuentaSalto;

    //OBJETOS
    int llavesCogidas;
    int llavesTotales;
    int mecanismosActivos;

    //Desplazamientos
    int ultimodx;
    int ultimody;

    boolean muerto;


    int despH;

    //BOTONES
    private    int izq = GameCanvas.LEFT_PRESSED;
    private    int der = GameCanvas.RIGHT_PRESSED;
    private    int botonSalto = GameCanvas.FIRE_PRESSED;

    /* ////////////////TILES DE COLISION: /////////////////////////////////////////////////
      0.	Nada  -		Transparente
        1.	BLOQUE –	 	Rojo
        2.	SUELO  - 			Negro
        3.	SUELO QUE SE CAE – Naranja
        4.	Cinta IZQ -	      	Verde con I
        5.	LLAVE -			Amarillo
        6.	MUERTE - 			PURPURA OSCURO
        7.	Mecanismo - 		GRIS
        8.      Cinta der-             Verde con D
        9.      Puerta -              MARRON CON PICAPORTE

     *
     *
     * */
    final int BLOQUE = 1;
    final int SUELO = 2;
    final int SUELOCAIBLE = 3;
    final int CINTAIZQ = 4;
    final int LLAVE = 5;
    final int MUERTE = 6;
    final int MECANISMO = 7;
    final int CINTADER = 8;
    final int PUERTA = 9;


     int movPixel = 2; //Cantidad de pixeles de desplazamientos del muñeco en horizontal

     int xanterior; //posicion anterior en la que estaba

     //Miro con que tiles tengo que comprobar la colision
     int [][] matrizEspacio;


     //Tile del suelo caible

     int tileSueloCaible;

     boolean miraDer;


     //Pasar nivel
     boolean nivelPasado;

     //La altura maxima es de caida es de 5 tiles -> 5tiles*8 pixeles/tile = 40 pixeles
     int MAXCAIDA = 40;

     int alturaCayendo; //altura que lleva cayendo

    Personaje(Sprite sp){
        vidas = 3;
        this.sp = sp;
        cuentaSalto = 0;
        ultimodx = 0;
        ultimody = 0;

        muerto = false;

        mecanismosActivos = 0;

       matrizEspacio =  tilesCuadrado();
       miraDer= true;
       this.xanterior = sp.getX();
       nivelPasado = false;
       
       alturaCayendo = MAXCAIDA;
    }


    int getVidas(){
        return vidas;
    }

    Sprite getSprite(){
        return sp;
    }

    int getSueloCaible(){
        return tileSueloCaible;
    }

    boolean estaMuerto(){
        return this.muerto;
    }

   
    public boolean getNivelPasado(){
        return this.nivelPasado;
    }

    public int getMecanismosActivos(){
        return this.mecanismosActivos;
    }
    boolean getMiraDer(){
        return this.miraDer;
    }
    public boolean estaSinVidas(){
        if(getVidas() == 0)
            return true;
        else
            return false;
    }
    void setSueloCaible(int tile){
        tileSueloCaible = tile;
    }

    void setMiraDer(boolean miraDer){
        this.miraDer = miraDer;
    }

    void setPos(int x, int y){
        sp.setPosition(x, y);
    }

    public void setTotalLlaves(int llavesTotales){
        this.llavesTotales = llavesTotales;
    }
    int getPosx(){
        return sp.getX();
    }

    int getPosy(){
        return sp.getY();
    }

    int getWidth(){
        return sp.getWidth();
    }

    int getHeigth(){
        return sp.getHeight();
    }

    //Movimiento con controles
    void mover(int control)
    {
        
        if(saltando){
            if(ultimody >0){
                alturaCayendo = alturaCayendo - ultimody;
            }
            saltar(despH);
          return;
        }else if(cayendo){
            ultimody = 4;
            ultimodx = 0;
            sp.move(0, 4);
            alturaCayendo = alturaCayendo - ultimody;
            
            return;
        }else if(this.enPasarela){
           if((control & botonSalto) != 0){
                saltar(despH);
                return;
           }

           sp.move(despH, 0);
           ultimodx = despH;

            return;
        }



        //1º si pulso salto y me estoy moviendo a la izquierda
        //2º si pulso salto y me estoy moviendo a la derecha
        //3º si pulso salto y no me estoy moviendo
        //
        if(control == (izq | botonSalto))
        {saltar(-movPixel);}
        else if(control == (der | botonSalto) )
        {saltar(movPixel);}
        else if((control & botonSalto) != 0)
        {saltar(0);}
        else if((control & izq) != 0){
           sp.move(-movPixel, 0);
           ultimodx = -movPixel;
          
        }
        else if((control & der) != 0)
        {
            sp.move(movPixel, 0);
            ultimodx = movPixel;
        }

    }

    void animacionInterna(){
        if(xanterior<sp.getX()){
            animarDer();
        }else if(xanterior>sp.getX()){
            animarIzq();
        }

        xanterior=sp.getX();
    }

    public void mirarIzq(){
         if(miraDer){
                miraDer=false;
                sp.setTransform(Sprite.TRANS_MIRROR);
                sp.move(sp.getHeight()-4, 0);
            }
    }

    public void mirarDer(){
        if(!miraDer){
               miraDer=true;
               sp.setTransform(Sprite.TRANS_NONE);
               sp.move(-sp.getHeight()+4, 0);
           }
    }

    private void animarIzq(){
            mirarIzq();
            sp.prevFrame();
    }

    private void animarDer(){
       
            mirarDer();
             sp.nextFrame();
    }

    boolean estaSaltando(){
        return saltando;
    }

    boolean estaCayendo(){
        return cayendo;
    }

    void saltar(int despx){
        if(!saltando){
            saltando = true;
            cuentaSalto=0;
            despH = despx;
        }

        int despV = salto[this.cuentaSalto];

        sp.move(despH, despV);

        ultimodx = despH;
        ultimody = despV;

        cuentaSalto++;
         //Si ya he hecho el salto, dejo de estar saltando y la cuenta del salto se pone a 0
        if(this.cuentaSalto%salto.length == 0){
            saltando = false;
        }

    }

    //La colision dira si esta sobre el suelo, o si se choca con algo que lo mata
    //Tambien dira la accion a tomar, y el movimiento dependiendo de la situacion
    //Tambien se puede chocar con las llaves
    //La colision devuelve los puntos obtenido
    //Movera los tiles animados que fuesen necesarios, ejemplo suelo q se derrumba
    
    int colision(TiledLayer t, IMonstruo [] monstruos,TiledLayer t2){
       int puntos = 0;

       //PRIMERO MIRO LA COLISION CON LOS TILES ///////////////////////////////

       //Nos dara el tile en el que esta el muñeco en la esquina superior izquierda
       int tilex = conseguirTilex(t);
       int tiley = conseguirTiley(t);

       //Guarda las coordenadas x e y de
       int xaux=0;
       int yaux=0;

       int cara = 0; //Cara 0 aun no inicializada
       //POSIBLES VALORES DE CARAS:
       //1 -> arriba
       //2 -> lado
       //3 -> abajo



       //Tipo de tile con el que colisiona si vale -1 significa que no colisiono
       int tipoT = -1;
       int tipoAux = -1;
      int caraAux = 0;

       for(int i = 0; i < matrizEspacio.length; i++){
           for(int j = 0; j< matrizEspacio[i].length;j++){

               if(tilex+i < t.getColumns() && tiley +j< t.getRows() ){
                   tipoT = tipoColision(t,tilex + i, tiley+j);
                   if(tipoT != -1){
                       xaux = tilex + i;
                       yaux = tiley+j;

                       cara = encontrarCara(t,xaux,yaux);

                       if(tipoT == this.LLAVE)
                           puntos = 100;
                       
                       //si choca con alguna cara
                       if(cara!=0)
                       {

                           tratarColision(tipoT,cara,xaux,yaux, t,t2);
                       }

                   }
               }

           }
       }


      if(monstruos != null){
      //MIRO A VER SI SE CHOCA CON ALGUN MONSTRUO

      for(int i = 0; i < monstruos.length; i++){

          if(sp.collidesWith(monstruos[i].getSprite(), false)){
              vidas--;
              this.muerto=true;
          }

      }
      }
       
       return puntos;


    }


    public void actualizarEstado(TiledLayer t, TiledLayer t2){
        //Si esta saltando no le afecta estas cosas
        if(saltando || cayendo)
            return;

        //Si no esta saltando ni cayendo es que esta en el suelo entonces miro para actualizar el estado

        //1º Miro debajo de que esta
        int tilex = conseguirTilex(t);
        int tiley = conseguirTiley(t) + 2;

        int tipo;
        boolean sinsuelo = true;

        for(int x=tilex; x<tilex+3; x++)
        {
            int pixelx = tileToPixelx(t,x);

           if((tipo = t.getCell(x, tiley))!= 0)
           {

               if((sp.getX() < pixelx + t.getCellWidth()) && (sp.getX() + sp.getWidth() > pixelx)){

                   if(tipo == SUELOCAIBLE || tipo == CINTAIZQ || tipo == CINTADER ||
                           tipo == BLOQUE || tipo == SUELO){
                            sinsuelo = false;

                            //Si ha caido de mucha altura
                            if(alturaCayendo <=0){
                                morirse();
                            }else{ //Sino restauro la caida
                                alturaCayendo = MAXCAIDA;
                            }
                            
                   }
                   
                    switch(tipo)
                    {
                        case SUELOCAIBLE: animarSueloCaible(t,t2,x,tiley); enPasarela=false; break;
                        case CINTAIZQ: enPasarela = true; despH= -this.movPixel; break;
                        case CINTADER: enPasarela = true; despH= this.movPixel; break;
                        default: enPasarela = false;
                    }
               }
           }

        }

        if(sinsuelo){
            enPasarela = false;
            cayendo = true;
        }

    }

    private void animarSueloCaible(TiledLayer tColision, TiledLayer t2,int tilex, int tiley){

        if(t2.getCell(tilex,tiley) < tileSueloCaible + 8)
            t2.setCell(tilex, tiley, t2.getCell(tilex, tiley)+1);
  
        if(t2.getCell(tilex, tiley) >= tileSueloCaible + 8){
            tColision.setCell(tilex, tiley, 0);
            t2.setCell(tilex, tiley, 0);
            tColision.setCell(tilex,tiley,0);
        }

        
    }

    private void tratarColision(int tipo, int cara, int tilex, int tiley , TiledLayer tColision, TiledLayer t2){

       //Tratamientos dependiendo del tipo///////////////////
       switch(tipo){
           case BLOQUE:
               tratamientoBloque(cara); break;
           case SUELO:
               if(this.saltando && ultimody >= 0 || cayendo)
                   tratamientoSuelo(cara); //Debo mirar si se queda o no dependiendo de la posicion del muñeco
                break;
           case SUELOCAIBLE:  tratamientoSuelo(cara);break;
           case CINTAIZQ: tratamientoSuelo(cara);  break;
           case CINTADER: tratamientoSuelo(cara);break;
           case LLAVE: tColision.setCell(tilex,tiley,0); t2.setCell(tilex,tiley,0); llavesCogidas++; break;
           case MUERTE: vidas--; muerto=true; break;
           case MECANISMO: break;
           case PUERTA:
               if(this.llavesCogidas == this.llavesTotales){
                       nivelPasado = true;
               }
               break;

           default:
       }
    }

    private void tratamientoSuelo(int cara){
       //Si esta saltando deja de saltar como si estuviese en el suelo
        if(this.saltando && ultimody >= 0 || cayendo){
             if(cara==1)
                 llegadaAlSuelo();

        }
        //El que el suelo se caiga corresponde a actualizar estado del personaje
        //Ese estado dira si no esta sobre ningun suelo y si esta sobre este suelo hacer
        //que el suelo vaya desapareciendo
        //Tambien mirara si esta en una barra de deslizamiento asi nos ahorramos duplicar código
    }

    private int encontrarCara(TiledLayer t, int xtile, int ytile){

        //Tengo que encontrar la cara con la que golpeo primero
        int cara = 0; //0 si no golpea con nada
       
        //donde se encuentra el pixel esquina superior izquierda
        int xpixelT = xtile*t.getCellWidth() + t.getX();
        int ypixelT = ytile*t.getCellHeight() + t.getY();

        int posxAnterior = sp.getX() - ultimodx;
        int posyAnterior = sp.getY() - ultimody;


        if((posxAnterior < xpixelT+t.getCellWidth()) &&
                (posxAnterior + sp.getWidth() > xpixelT)){
            if(posyAnterior + sp.getHeight() - 1 < ypixelT){
                cara =  1; //es la cara de arriba
    
            }
            else if(posyAnterior > ypixelT + t.getCellHeight()-1){
                cara = 3; //es la cara de abajo
               
            }

        }else{
            cara = 2; //es la cara del lado
        }

        return cara;

    }


    public void invisible(){
        sp.setVisible(false);
    }
    public void reiniciar(){
        cuentaSalto = 0;
        ultimodx = 0;
        ultimody = 0;
        muerto = false;
        sp.setVisible(true);

        xanterior=sp.getX();
        mecanismosActivos = 0;
        llavesCogidas = 0;
        nivelPasado = false;
        saltando = false;
        cayendo = false;

        alturaCayendo = MAXCAIDA;

    }

    private void tratamientoBloque(int cara){
     
            switch(cara){
                case 1: llegadaAlSuelo();  break;
                case 2: sp.move(-this.ultimodx, 0); break;
                case 3: sp.move(-this.ultimodx, -this.ultimody); saltando=false; despH=0;
                    break;
            }

    }

    private void llegadaAlSuelo(){
        sp.move(-this.ultimodx, -this.ultimody);
        despH=0;
        saltando = false;
        cayendo = false;
    }

    //tipoColision(....)
    //Da el tipo de objeto con el que colisiona. -1 si no colisiona
    private int tipoColision(TiledLayer t,int tilex, int tiley)
    {
        int tipo = t.getCell(tilex,tiley);


        if(tipo != 0){ //Si es distinto de 0 hay colision!
             //donde se encuentra el pixel esquina superior izquierda
            int xpixelT = tilex*t.getCellWidth() + t.getX();
            int ypixelT = tiley*t.getCellHeight() + t.getY();

            if((sp.getX() < xpixelT + t.getCellWidth()) && (sp.getX() + sp.getWidth() > xpixelT) &&
                (sp.getY() < ypixelT + t.getCellHeight() && (sp.getY() + sp.getHeight() > ypixelT)))
                return tipo;
        }


        return -1;

    }

    private int pixelToTilex(TiledLayer t, int pixelx)
    {
        int tilex = (pixelx + t.getX())/8;

        return tilex;
    }

    private int pixelToTiley(TiledLayer t, int pixely)
    {
        int tiley = (pixely + t.getY())/8;
        
        return tiley;
    }

    //Regresa la posicion x en pixeles del tilex en el espacio global
    private int tileToPixelx(TiledLayer t, int tilex)
    {
        return (tilex*8 + t.getX());
    }

    //Regresa la posicion y en pixeles del tiley en el espacio global
    private int tiletToPixely(TiledLayer t,int tiley)
    {
        return (tiley*8 + t.getY());
    }


    //consigue el tile donde esta el personaje
    private int conseguirTilex(TiledLayer t){
        int pixelsx = sp.getX() - t.getX();
        return pixelsx / 8;
    }

    //consiue el tiel donde esta el personaje
    private int conseguirTiley(TiledLayer t){

        
        int pixelsy = sp.getY() - t.getY();


        return pixelsy / 8;
    }

    //Nos dice los tiles que ocupa el muñeco
    private int[][] tilesCuadrado(){
        int x =  sp.getWidth()/8;
        int y =  sp.getHeight()/8;

        x = x+2;
        y++;

        return new int[x][y];
    }

    int getLLaves(){
        return this.llavesCogidas;
    }



    void morirse(){
        this.muerto = true;
        vidas--;
    }

    void setSprite(Sprite sp){
        this.sp = sp;
    }
    
}
