package clases;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import clases.Carta;
//import com.roshka.bootcamp004.poker.MyClass;

public class Poker {
	
	// TH, TC, 5S, 5H, AD, AH, 2S  
	public String mejorJugada(Carta[] mano)
	{
		ArrayList<Carta[]> candidatas = new ArrayList<Carta[]>();
		ArrayList<Carta[]> mejores = new ArrayList<Carta[]>();
		String mejoresString="";
		Carta[] cartas = mano;

        //Crea una mano de 5 cartas que va a seguir igual siempre
        Carta [] manoPrincipal = new Carta[5];

        //Crea una mano de 5 cartas que va a variar para crear las
        //distintas combinaciones
        Carta [] manoVariante = new Carta[5];

        //Carga las primeras 5 cartas en la mano
        for (int i = 0; i < 5; i++) {
            manoPrincipal[i] = new Carta(cartas[i].valor+cartas[i].palo);           
        }
        manoVariante = manoPrincipal.clone();
        //Se agrega la primera combinación a las manos candidatas
        candidatas.add(manoVariante.clone());

        //Las dos ultimas cartas las guarda en variables diferentes
        Carta x = cartas[5];
        Carta y = cartas[6];
        
        //Se crean las combinaciones
        for (int i = 0; i < 5; i++) {
            //Rota la x
            manoVariante[i] = x;
            //Agrego una copia de la mano variante para no tener problemas
            //Con la modificacion de los valores
            //Por el tema de paso por referencia
            candidatas.add(manoVariante.clone());
           
            //Es para no repetir combinaciones. Esta repeticion
            //se da en la cuarta iteración
            //if(i!=4){
                for(int j = i; j < 5; j++){                
                    //Se usa una variable auxiliar para volver a poner el valor
                    //que se cambió como estaba
                    Carta aux = manoVariante[j];
    
                    //Rota la y cuando la x está rotando
                    manoVariante[j]= y;
                    //Se agrega una copia a las candidatas
                    candidatas.add(manoVariante.clone());
                    //Vuelve la mano variante a su estado original
                    manoVariante[j] = aux;
                }
            /*}else{
                //Solo faltaría agregar una rotación, cuando la y está al final
                manoVariante[i]=y;    
                candidatas.add(manoVariante.clone());
            }*/
            manoVariante = manoPrincipal.clone();
        }

		/*
        for (int i = 0; i < candidatas.size(); i++) {
            System.out.println("Combinacion número: "+(i+1));
            System.out.println(candidatas.get(i)[0].valor+candidatas.get(i)[0].palo);
            System.out.println(candidatas.get(i)[1].valor+candidatas.get(i)[1].palo);
            System.out.println(candidatas.get(i)[2].valor+candidatas.get(i)[2].palo);
            System.out.println(candidatas.get(i)[3].valor+candidatas.get(i)[3].palo);
            System.out.println(candidatas.get(i)[4].valor+candidatas.get(i)[4].palo);
            System.out.println("******");
        }
		*/
        //System.out.println(candidatas.size());

        //Crea una instancia de MyClass, que contiene
        //el método que elige cuál es la mejor jugada
        //MyClass mc = new MyClass();
        
        //Crea un vector string con los índices de los ganadores
        String[] mejoresCombinaciones = ganadores(candidatas).split(" ");
        //System.out.println("Cantidad de ganadores: "+ mejoresCombinaciones.length);
        
        //System.out.println("Indice de los ganadores: "+mc.ganadores(candidatas));

		//Imprime las mejores combinaciones
        /*for (int j = 0; j < mejoresCombinaciones.length; j++) {
            //Convierte los indices de los ganadores que están en String
            //a int
            int index = Integer.parseInt(mejoresCombinaciones[j]);
            for (int i = 0; i < 5; i++) {
                System.out.print(candidatas.get(index)[i].valor+candidatas.get(index)[i].palo+" ");
            }
            System.out.println();
        }*/

		for (int j = 0; j < mejoresCombinaciones.length; j++) {
            //Convierte los indices de los ganadores que están en String
            //a int
			int index = Integer.parseInt(mejoresCombinaciones[j]);
			mejores.add(candidatas.get(index).clone());            
		}
		
		//Carga mejoresString, que contiene los resultados del vector mejores
		//pero en String, todo concatenado
		//También imprime el contenido de "mejores"
		for (int j = 0; j < mejores.size(); j++) {
            //Convierte los indices de los ganadores que están en String
            //a int
            //int index = Integer.parseInt(mejoresCombinaciones[j]);
            for (int i = 0; i < 5; i++) {
                mejoresString += mejores.get(j)[i].valor+mejores.get(j)[i].palo;
                
                //System.out.print(candidatas.get(j)[i].valor+candidatas.get(j)[i].palo);
                if(i!=4){
                    //System.out.print(",");
                    mejoresString += ",";

                } 
            }
			//System.out.println();
            if(j!=mejores.size()-1)
                mejoresString += ";";
        }
	

        return mejoresString;
		//return "AD,AH,TH,TC,5S;AD,AH,TH,TC,5H";
	}


	public String ganadores(List<Carta[]> jugadas)
    {
        //System.out.println("Cantidad de jugadas: " + jugadas.size());
        ArrayList<Carta[]> ganadores = new ArrayList<Carta[]>();
        //Indica que es la primera mano
        boolean esPrimero=true;
        //Array para almacenar los índices
        ArrayList<Integer> indices = new ArrayList<Integer>();
        //Contador que mantiene el valor del indice
        int index=0;
        
        for (Carta[] mano : jugadas) {
        // System.out.println("JUGADA ======================");
           
            if(esPrimero){
                ganadores.add(mano);
                indices.add(index);
                esPrimero=false;
            }
            else{
                ArrayList<Integer> calificacionMayor= calificacion(ganadores.get(ganadores.size()-1));
                ArrayList<Integer> calificacionActual= calificacion(mano);
                if(calificacionMayor.get(0)<calificacionActual.get(0)){
                    ganadores.clear();
                    indices.clear();
                    indices.add(index);
                    ganadores.add(mano);
                }
                else if(calificacionMayor.get(0)==calificacionActual.get(0)){
                    for (int i = 1; i < calificacionMayor.size(); i++) {
                        if(calificacionMayor.get(i)<calificacionActual.get(i)){
                            ganadores.clear();
                            indices.clear();
                            indices.add(index);
                            ganadores.add(mano);
                            break;
                        }
                        else if(calificacionMayor.get(i)>calificacionActual.get(i)){
                            break;
                        }
                        //Si la i llega al tamaño máximo del array, quiere decir
                        //que son todos iguales
                        else if(i==calificacionMayor.size()-1){
                            ganadores.add(mano);
                            indices.add(index);
                        }
                    }
                }
            } 
            index++;
        }

        //imprimirGanadores(ganadores);
        String stringGanadores="";
        for (int i = 0; i < indices.size(); i++) {
            stringGanadores += indices.get(i)+" ";
        }
        return stringGanadores;
    }

    private ArrayList<Integer> calificacion(Carta[] mano){
        ArrayList<Integer> calificacion= new ArrayList<Integer>();
        /**
         * La calificacion numérica de cada carta estará en el lugar 0 del array retornado
         * Escalera color -> 9
         * Poker -> 8
         * Full -> 7
         * Color -> 6
         * Escalera -> 5
         * Trio -> 4
         * Par Doble -> 3
         * Par -> 2
         * Carta alta -> 1
         */

        //Array para almacenar la cantidad de apariciones de cada número
        int[] valores = new int[13];
        //Array para almacenar la cantidad de apariciones de cada palo
        int[] palos = new int[4];
        inicializarArrays(valores, palos, mano);    
        
        //Si es escalera, solo basta ver el valor de la escalera    
        if(esEscaleraColor(valores, palos)){
            int[] ordenado = ordenarMano(mano);
            calificacion.add(9);
            //Si el AS actúa como 14, entonces el AS vale 14
            if(ordenado[4]==12 && ordenado[0]==0){
                calificacion.add(14);
            }
            else{
                calificacion.add(ordenado[4]);
            }
            
        }
        else if(esPoker(valores)){
            //Si es poker, se envia la calificacion en el primer elemento, seguido del
            //valor que hizo que sea poker, seguido del valor diferente
            calificacion.add(8);
            if(indiceDe(4,valores)==0){
                calificacion.add(14);
                calificacion.add(indiceDe(1,valores));
            }
            else{
                calificacion.add(indiceDe(4,valores));

                if(indiceDe(1, valores)==0){
                    calificacion.add(14);
                }
                else{
                    calificacion.add(indiceDe(1, valores));
                }
            }          
            
        }
        else if(esFull(valores)){
            //No hay empate en full, por lo tanto solo hace falta
            //el valor de la mano
            calificacion.add(7);
            if(indiceDe(3,valores)==0){
                calificacion.add(14);
                calificacion.add(indiceDe(2,valores));
            }
            else{
                calificacion.add(indiceDe(3,valores));

                if(indiceDe(2, valores)==0){
                    calificacion.add(14);
                }
                else{
                    calificacion.add(indiceDe(2,valores));
                }
            }
        }
        else if(esColor(palos)){
            int aux=0;
            calificacion.add(6);
            int[] ordenado = ordenarMano(mano);
            if(ordenado[0]==0){
                calificacion.add(14);
                aux=1;
            }
            for (int i = 4; i >= aux; i--) {
                calificacion.add(ordenado[i]);                
            }
        }
        else if(esEscalera(valores)){
            int[] ordenado = ordenarMano(mano);
            calificacion.add(5);
            if(ordenado[4]==12 && ordenado[0]==1){
                calificacion.add(14);
            }
            else{
                calificacion.add(ordenado[4]);
            }
        }
        else if(esTrio(valores)){
            calificacion.add(4);

            //Convierte el AS al mayor valor, en lugar de 1 vale 14
            if(indiceDe(3,valores)==0){
                calificacion.add(14);
            }else{
                calificacion.add(indiceDe(3, valores));
            }
            
            int[] ordenado = ordenarMano(mano);

            int aux = 0;
            if(ordenado[0]==0){
                calificacion.add(14);
                aux = 1;
            }


            for (int i = 4; i >=aux; i--) {
                if(calificacion.get(1)!=ordenado[i]){
                    calificacion.add(ordenado[i]);
                }
            }
        }
        else if(esParDoble(valores)){
            calificacion.add(3);

            //Si es un par doble de AS, se le asigna 14
            if(indiceDe(2,valores)==0){
                calificacion.add(14);
                calificacion.add(indiceDeReversa(2, valores));
            }
            else{
                calificacion.add(indiceDeReversa(2, valores));
                calificacion.add(indiceDe(2, valores));
            }

            if(indiceDe(1,valores)==0){
                calificacion.add(14);
            }
            else{
                calificacion.add(indiceDe(1,valores));
            }
            
        }
        else if(esPar(valores)){
            calificacion.add(2);

            //Si el par es de AS, se setea su valor a 14
            if(indiceDe(2,valores)==0){
                calificacion.add(14);
            }
            else{
                calificacion.add(indiceDe(2, valores));
            }
            
            
            int[] ordenado = ordenarMano(mano);
            int aux=0;

            if(ordenado[0]==0){
                calificacion.add(14);
                aux=1;
            }
            

            for (int i = 4; i >=aux; i--) {
                if(calificacion.get(1)!=ordenado[i]){
                    calificacion.add(ordenado[i]);
                }
            }
        }
        else{
            int aux=0;
            calificacion.add(1);
            //Si hay un AS, se coloca directamente después de la
            //calificación
            int[] ordenado = ordenarMano(mano);

            if(ordenado[0]==0){
                calificacion.add(14);
                aux=1;
            }
            for (int i = 4; i >= aux; i--) {
                calificacion.add(ordenado[i]);
            }
        }


        return calificacion;
    }

    private int indiceDe(int elemento, int[] vector){    

        for (int i = 0; i < vector.length; i++) {
            if(vector[i]==elemento) return i;
        }

        //retorna -1 si no encuentra;
        return -1;
    }
    private int indiceDeReversa(int elemento, int[] vector){    

        for (int i = vector.length-1; i >=0; i--) {
            if(vector[i]==elemento) return i;
        }

        //retorna -1 si no encuentra;
        return -1;
    }

    private int[] ordenarMano(Carta[] mano){
        int[] ordenado = new int[5];

        for (int i = 0; i < 5; i++) {
            
            String valorString= mano[i].valor;
            if(valorString.equals("A") || valorString.equals("a")){
                ordenado[i]=0;
            }
            else if(valorString.equals("T") || valorString.equals("t")){
                ordenado[i]=9;
            }
            else if(valorString.equals("J") || valorString.equals("j")){
                ordenado[i]=10;
            }
            else if(valorString.equals("Q") || valorString.equals("q")){
                ordenado[i]=11;
            }
            else if(valorString.equals("K") || valorString.equals("k")){
                ordenado[i]=12;
            }
            else{
                ordenado[i] = Integer.parseInt(valorString)-1;
            }
        }
        Arrays.sort(ordenado);
        return ordenado;
    }

    private boolean esEscaleraColor(int[] valores, int[] palos){
        /**
         * Funcionamiento: recorre el vector de valores y cuando encuentra un 1
         * enciende una bandera para comenzar a contar.
         * Termina el ciclo cuando ya no quedan elementos o cuando encuentra un número
         * distinto a 1. Si este número es mayor a 1, entonces termina el ciclo.
         * Si el contador termina en 5, se comprueba que todos los palos sean iguales.
         * esto se consigue revisando si en el vector de palos hay un 5, porque esto significa
         * que todos fueron iguales
         * O si hay un 4 en el contador y una A presente, también es verdadero		 
         */

        //bandera para activar sumador
        boolean sumadorActivo=false;

        //Sumador de números contiguos
        int sumador=0;

        //no se comprueba si existe A, porque despues se comprueba
        //si el contador llegó a 4 y existe una A, entonces es una
        //escalera
        for (int i = 1; i < 13; i++) {
            //Si la cantidad de aparición de un valor fue mayor a 1,
            //no es posible que sea una escalera			
            if(valores[i]>1){				
                return false;
            }

            if(valores[i]==1){
                sumadorActivo=true;
            }

            if(valores[i]==0 && sumadorActivo){
                break;
            }
            if(sumadorActivo){
                sumador++;
            }
        }

        //Si el sumador llegó a 5 entra al ciclo que comprueba
        //o si llegó a 4 y existe una A
        //si alguno de los palos vino 5 veces
        if(sumador==5 || (sumador==4 && valores[0]==1 && valores[9]==1 && valores[8]==0)){
            for (int i = 0; i < 4; i++) {
                if(palos[i]==5){
                    return true;
                }
            }
        }
        return false;
    }

    //Comprueba si la mano es póker
    private boolean esPoker(int[] valores){
        /**
         * Funcionamiento: Ordena el array de valores de forma ascendente.
         * Para comprobar si existe poker, basta con mirar el último elemento del array,
         * donde debería encontrarse un 4
         */
        
        //Clona el array de valores
        int [] ordenado = valores.clone();
        //Ordena la copia
        Arrays.sort(ordenado);

        if(ordenado[12]==4){
            return true;
        }

        return false;
    }

    private boolean esFull(int[] valores){
        //Clona el array de valores
        int [] ordenado = valores.clone();
        //Ordena la copia
        Arrays.sort(ordenado);

        if(ordenado[12]==3 && ordenado[11]==2)
            return true;

        return false;
    }

    private boolean esColor(int[] palos){
        //Clona el array de valores
        int [] ordenado = palos.clone();
        //Ordena la copia
        Arrays.sort(ordenado);

        if(ordenado[3]==5)
            return true;

        return false;
    }

    private boolean esEscalera(int[] valores){
        //bandera para activar sumador
        boolean sumadorActivo=false;

        //Sumador de números contiguos
        int sumador=0;

        //no se comprueba si existe A, porque despues se comprueba
        //si el contador llegó a 4 y existe una A, entonces es una
        //escalera
        for (int i = 1; i < 13; i++) {

            //Si la cantidad de aparición de un valor fue mayor a 1,
            //no es posible que sea una escalera			
            if(valores[i]>1){
                return false;
            }

            if(valores[i]==1){
                sumadorActivo=true;
            }

            if(valores[i]==0 && sumadorActivo){
                break;
            }
            if(sumadorActivo){
                sumador++;
            }
        }

        //Si el sumador llegó a 5 entra al ciclo que comprueba
        //o si llegó a 4 y existe una A
        if(sumador==5 || (sumador==4 && valores[0]==1 && valores[9]==1 && valores[8]==0)){
            return true;
        }

        return false;
    }

    private boolean esTrio(int[] valores){
        //Clona el array de valores
        int [] ordenado = valores.clone();
        //Ordena la copia
        Arrays.sort(ordenado);

        if(ordenado[12]==3 && ordenado[11]==1 && ordenado[10]==1)
            return true;

        return false;
    }

    private boolean esParDoble(int[] valores){
        //Clona el array de valores
        int [] ordenado = valores.clone();
        //Ordena la copia
        Arrays.sort(ordenado);

        if(ordenado[12]==2 && ordenado[11]==2 && ordenado[10]==1)
            return true;
        return false;
    }

    private boolean esPar(int[] valores){
        //Clona el array de valores
        int [] ordenado = valores.clone();
        //Ordena la copia
        Arrays.sort(ordenado);

        if(ordenado[12]==2 && ordenado[11]==1 && ordenado[10]==1 && ordenado[9]==1)
            return true;

        return false;
    }

    private void inicializarArrays(int[] valores, int[] palos, Carta[] mano){
        //Se coloca 1 y 14 para que sea mas facil controlar las Escaleras
        for (int i = 0; i < 13; i++) {
            valores[i]=0;
        }
        for (int i = 0; i < 4; i++) {
            palos[i] = 0;
        }

        //carga los vectores de cantidades de aparición
        for (int i = 0; i < 5; i++) {
            String valorString = mano[i].valor;
            String paloString = mano[i].palo;			
            
            if(valorString.equals("A") || valorString.equals("a")){
                valores[0]++;
            }
            else if(valorString.equals("T") || valorString.equals("t")){
                valores[9]++;
            }
            else if(valorString.equals("J") || valorString.equals("j")){
                valores[10]++;
            }
            else if(valorString.equals("Q") || valorString.equals("q")){
                valores[11]++;
            }
            else if(valorString.equals("K") || valorString.equals("k")){
                valores[12]++;
            }
            else if(valorString.equals("J") || valorString.equals("j")){
                valores[10]++;
            }
            else{
                int index = Integer.parseInt(valorString);
                valores[index-1]++;
            }			

            //Para el array de cantidades de palos
            //S -> 0
            //C -> 1
            //H -> 2
            //D -> 3
            if(paloString.equals("S") || paloString.equals("s")){
                palos[0]++;
            }
            else if(paloString.equals("C") || paloString.equals("c")){
                palos[1]++;
            }
            else if(paloString.equals("H") || paloString.equals("h")){
                palos[2]++;
            }
            else if(paloString.equals("D") || paloString.equals("d")){
                palos[3]++;
            }
        }
    }
    
    //Este metodo genera n cantidad de cartas al azar
    public Carta[] generarCartas(int n) {
    	Carta[] cartas = new Carta[n];
    	
    	Random random = new Random();
     	String nuevaCarta = "";
     	
     	int valor[] = new int[n];
     	int palo[] = new int[n];
     	
     	
     	for(int i=0; i<n; i++) {
     		valor[i] = random.nextInt(13) + 1;
     		 palo[i] = random.nextInt(4) + 1;
     		 
     		 for(int j=0; j<i; j++) {
     			 
     			 if(valor[j]==valor[i] && palo[j]==palo[i]) {
     				valor[i] = random.nextInt(13) + 1;
     	     		 palo[i] = random.nextInt(4) + 1;
     	     		 j=0;
     			 }
     			 
     		 }
     	}
     	
     	
     	for(int i=0; i<n; i++) {
     		//valor = random.nextInt(13) + 1;
     		if(valor[i]==1) {
     			nuevaCarta += "A";
     		}
     		else if(valor[i]==10) {
     			nuevaCarta += "T";
     		}
     		else if(valor[i]==11) {
     			nuevaCarta += "J";
     		}
     		else if(valor[i]==12) {
     			nuevaCarta += "Q";
     		}
     		else if(valor[i]==13) {
     			nuevaCarta += "K";
     		}
     		else {
     			nuevaCarta += valor[i];
             }             
             
             //palo = random.nextInt(4) + 1;

             if(palo[i]==1){
                 nuevaCarta += "H";
             }
             else if(palo[i]==2){
                 nuevaCarta += "S";
             }
             else if(palo[i]==3){
                 nuevaCarta += "D";
             }
             else if(palo[i]==4){
                 nuevaCarta += "C";
             }
             
             cartas[i] = new Carta(nuevaCarta); 
             nuevaCarta = "";
         }
    	
    	
    	return cartas;
    }
    
    public String nombreJugada(Carta[] mano)
	{
		//Array para almacenar la cantidad de apariciones de cada número
		int[] cantidadValores = new int[13];
		//Array para almacenar la cantidad de apariciones de cada palo
		int[] cantidadPalos = new int[4];

		inicializarArrays(cantidadValores, cantidadPalos, mano);
		
		if(esEscaleraColor(cantidadValores, cantidadPalos))
			return "ESCALERA COLOR";		

		if(esPoker(cantidadValores))
			return "POKER";

		if(esFull(cantidadValores))
			return "FULL";

		if(esColor(cantidadPalos))
			return "COLOR";

		if(esEscalera(cantidadValores))
			return "ESCALERA";

		if(esTrio(cantidadValores))
			return "TRIO";

		if(esParDoble(cantidadValores))
			return "PAR DOBLE";

		if(esPar(cantidadValores))
			return "PAR";		

		return "CARTA ALTA";
	}

    //Clase main para probar
    /*
	public static void main(String[] args) {
        Carta[] a = new Carta[7];
        a[0] = new Carta("TH");
        a[1] = new Carta("TC");
        a[2] = new Carta("5S");
        a[3] = new Carta("5H");
        a[4] = new Carta("AD");
        a[5] = new Carta("AH");
        a[6] = new Carta("2S");

        Poker p = new Poker();

		System.out.println(p.mejorJugada(a));
		

	}*/

}

