# -*- coding: latin-1 -*-

#==========================================================================================================================================
import random
import operator
import datetime

from Code.Constantes import *
from Code.Traducir import tr

import Util
import Jugada
import MotorInternoGM
import XMotorRespuesta

import Apertura

import Gestor

import QT.QTUtil2 as QTUtil2

#==========================================================================================================================================
class MotorElo :
    def __init__( self, elo, nombre, clave, depth ) :
        self.elo = elo
        self.nombre = nombre
        self.clave = clave
        self.depth = depth
        self.siInterno = depth == 0

    def rotulo( self ) :
        resp = self.nombre
        if self.depth :
            resp += " %d"%self.depth
        resp += " (%d)"%self.elo
        return resp
#==========================================================================================================================================

#==========================================================================================================================================
class GestorElo( Gestor.Gestor ) :
    def valores( self ) :

        self.liMotores = []
        for x in range( 1, 8 ) :
            self.liMotores.append( MotorElo( x*108+50, tr( "RIVAL_%d"%x ), x-1, 0 ) )
        def m( elo, clave, depth ) :
            self.liMotores.append( MotorElo( elo, Util.primeraMayuscula(clave), clave, depth ) )

        m( 1029, "gaia", 1 )
        m( 1046, "pawny", 1 )
        m( 1053, "tarrasch", 2 )
        m( 1060, "tarrasch", 3 )
        m( 1063, "daydreamer", 2 )
        m( 1087, "lime", 1 )
        m( 1100, "clarabit", 1 )
        m( 1104, "chispa", 1 )
        m( 1146, "alaric", 1 )
        m( 1146, "bikjump", 1 )
        m( 1166, "pawny", 2 )
        m( 1178, "gaia", 2 )
        m( 1200, "garbochess", 1 )
        m( 1215, "chispa", 2 )
        m( 1227, "bikjump", 2 )
        m( 1237, "umko", 1 )
        m( 1251, "clarabit", 2 )
        m( 1274, "cyrano", 1 )
        m( 1278, "ufim", 1 )
        m( 1296, "alaric", 2 )
        m( 1303, "toga", 1 )
        m( 1318, "tarrasch", 4 )
        m( 1325, "stockfish", 1 )
        m( 1337, "lime", 2 )
        m( 1396, "komodo", 1 )
        m( 1403, "gaia", 3 )
        m( 1406, "critter", 1 )
        m( 1423, "clarabit", 3 )
        m( 1423, "pawny", 3 )
        m( 1435, "glaurung", 2 )
        m( 1438, "garbochess", 2 )
        m( 1470, "bikjump", 3 )
        m( 1477, "glaurung", 1 )
        m( 1479, "chispa", 3 )
        m( 1497, "lime", 3 )
        m( 1511, "ufim", 2 )
        m( 1519, "alaric", 3 )
        m( 1521, "umko", 2 )
        m( 1526, "stockfish", 2 )
        m( 1546, "toga", 2 )
        m( 1548, "komodo", 2 )
        m( 1555, "cyrano", 2 )
        m( 1558, "daydreamer", 3 )
        m( 1575, "critter", 2 )
        m( 1602, "pawny", 4 )
        m( 1626, "clarabit", 4 )
        m( 1646, "gaia", 4 )
        m( 1683, "stockfish", 3 )
        m( 1685, "bikjump", 4 )
        m( 1685, "glaurung", 3 )
        m( 1690, "daydreamer", 4 )
        m( 1702, "garbochess", 3 )
        m( 1727, "alaric", 4 )
        m( 1744, "umko", 3 )
        m( 1746, "komodo", 3 )
        m( 1754, "lime", 4 )
        m( 1759, "cyrano", 3 )
        m( 1781, "toga", 3 )
        m( 1783, "chispa", 4 )
        m( 1798, "critter", 3 )
        m( 1805, "stockfish", 4 )
        m( 1830, "rybka", 1 )
        m( 1849, "ufim", 3 )
        m( 1854, "glaurung", 4 )
        m( 1879, "garbochess", 4 )
        m( 1901, "komodo", 4 )
        m( 1908, "umko", 4 )
        m( 1925, "critter", 4 )
        m( 1928, "rybka", 2 )
        m( 1933, "toga", 4 )
        m( 1933, "ufim", 4 )
        m( 1955, "cyrano", 4 )
        m( 2026, "rybka", 3 )
        m( 2055, "rybka", 4 )

        li = []
        for k, v in self.configuracion.dicRivales.iteritems() :
            if v.elo > 2000 :
                li.append( ( v.clave, v.elo ) )
        li = sorted(li, key=operator.itemgetter(1))
        for clave, elo in li :
            m( elo, clave, None ) # ponemos depth a None, para diferenciar del 0 de los motores internos

        self.liT = ( (0,50,3), (20,53,5), (40,58,4), (60,62,4), (80,66,5), (100,69,4), (120,73,3), (140,76,3), (160,79,3), (180,82,2), (200,84,9), (300,93,4), (400,97,3) )
        self.liK = ( (0,60), (800,50), (1200,40), (1600,30), (2000,30), (2400, 10) )

    def calcDifElo( self, eloJugador, eloRival, resultado ) :
        kj = 60

        for df, k in self.liK :
            if eloJugador < df :
                break
            kj = k

        difElo = abs(eloJugador-eloRival)
        km = 3
        kd = kk = 0
        for df, k, md in self.liT :
            if difElo < df :
                kk += int((difElo-kd)*km/(df-kd))
                break
            kd = df
            kk = k
            km = md
        if eloJugador < eloRival :
            kk = 100-kk
        if resultado == kGanamos :
            v = 100
        elif resultado == kTablas :
            v = 50
        else :
            v = 0

        return int(float(kj*(v-kk))/100.0)

    def listaMotores( self, elo ) :
        self.valores()
        li = []
        numX = len(self.liMotores)
        for num,mt in enumerate(self.liMotores) :
            mtElo = mt.elo
            mt.siJugable = abs(mtElo-elo) <= 400
            if mt.siJugable or (mtElo > elo):
                def rot( res ) :
                    return self.calcDifElo( elo, mtElo, res )

                mt.pgana = rot(kGanamos)
                mt.ptablas = rot(kTablas)
                mt.ppierde = rot(kGanaRival)

                mt.numero = numX-num

                li.append( mt )

        return li

    #--------------------------------------------------------------------------------------------------------------------------------
    def inicio( self, datosMotor, aplazamiento = None ) :

        self.tipoJuego = kJugElo

        self.resultado = None
        self.siJuegaHumano = False
        self.estado = kJugando

        if aplazamiento :
            siBlancas = aplazamiento["SIBLANCAS"]
        else :
            siBlancas = random.randint(0,1) == 0

        self.siJugamosConBlancas = siBlancas
        self.siRivalConBlancas = not siBlancas

        self.rmRival = None

        self.siTutorActivado = False
        self.pantalla.ponActivarTutor( self.siTutorActivado )

        self.ayudas = 0
        self.ayudasPGN = self.ayudas

        self.siApertura = True
        self.apertura = Apertura.AperturaPol(100)

        self.datosMotor = datosMotor

        #-Aplazamiento 1/2--------------------------------------------------
        if aplazamiento :
            self.partida.recuperaDeTexto( aplazamiento["JUGADAS"] )

            self.siApertura = aplazamiento["SIAPERTURA"]
            self.partida.pendienteApertura = aplazamiento["PENDIENTEAPERTURA"]
            self.partida.apertura = None if aplazamiento["APERTURA"] is None else self.listaAperturasStd.dic[aplazamiento["APERTURA"]]
            self.apertura.recuperaEstado( aplazamiento["ESTADOAPERTURA"] )

            self.datosMotor = MotorElo( aplazamiento["ELO"],aplazamiento["NOMBRE"],aplazamiento["CLAVE"], aplazamiento["DEPTH"] )
            self.datosMotor.pgana = aplazamiento["PGANA"]
            self.datosMotor.ppierde = aplazamiento["PPIERDE"]
            self.datosMotor.ptablas = aplazamiento["PTABLAS"]

        #-------------------------------------------------------------------

        self.siRivalInterno = self.datosMotor.siInterno
        if self.siRivalInterno :
            self.xrival = MotorInternoGM.GestorMotor( self.datosMotor.clave, self )

        else :
            rival = self.configuracion.buscaRival( self.datosMotor.clave )
            self.xrival = self.procesador.creaRival( rival, None, self.datosMotor.depth )

        self.pantalla.ponToolBar( ( k_rendirse,k_aplazar,k_otros  ) )
        self.pantalla.activaJuego(True, False)
        self.ponMensajero( self.mueveHumano )
        self.ponPosicion( self.partida.ultPosicion )
        self.ponPiezasAbajo( siBlancas )
        self.quitaAyudas( True )
        self.mostrarIndicador( True )
        rotulo = "%s: <b>%s</b>"%(tr( "RIVAL" ), self.datosMotor.rotulo() )
        self.ponRotulo1( rotulo )
        self.ponRotulo2( "" )
        self.pgnRefresh( True )
        self.ponCapturasPorDefecto()

        #-Aplazamiento 2/2--------------------------------------------------
        if aplazamiento :
            self.mueveJugada( "f" )
        #-------------------------------------------------------------------

        self.ponPosicionDGT()

        self.siguienteJugada()
    #--------------------------------------------------------------------------------------------------------------------------------
    def procesarAccion( self, clave ) :

        if clave == k_rendirse :
            self.rendirse()

        elif clave == k_otros :
            self.otros(siSonidos = True)

        elif clave == k_aplazar :
            self.aplazar()

        elif clave in self.procesador.liOpcionesInicio :
            self.procesador.procesarAccion( clave )

        else :
            Gestor.Gestor.rutinaAccionDef( self, clave )

    #--------------------------------------------------------------------------------------------------------------------------------
    def aplazar( self ) :
        if self.partida.numJugadas() and QTUtil2.pregunta( self.pantalla, tr( "PREGUNTA_APLAZAMOS" ) ) :

            aplazamiento = {}
            aplazamiento["TIPOJUEGO"] = self.tipoJuego
            aplazamiento["SIBLANCAS"] = self.siJugamosConBlancas
            aplazamiento["JUGADAS"] = self.partida.guardaEnTexto()

            aplazamiento["SIAPERTURA"] = self.siApertura
            aplazamiento["PENDIENTEAPERTURA"] = self.partida.pendienteApertura
            aplazamiento["APERTURA"] = self.partida.apertura.a1h8 if self.partida.apertura else None
            aplazamiento["ESTADOAPERTURA"] = self.apertura.marcaEstado()

            aplazamiento["ELO"] = self.datosMotor.elo
            aplazamiento["NOMBRE"] = self.datosMotor.nombre
            aplazamiento["CLAVE"] = self.datosMotor.clave
            aplazamiento["DEPTH"] = self.datosMotor.depth
            aplazamiento["PGANA"] = self.datosMotor.pgana
            aplazamiento["PPIERDE"] = self.datosMotor.ppierde
            aplazamiento["PTABLAS"] = self.datosMotor.ptablas

            self.configuracion.graba( aplazamiento )
            self.pantalla.accept()

    #--------------------------------------------------------------------------------------------------------------------------------
    def finalX( self ) :
        return self.rendirse()

    #--------------------------------------------------------------------------------------------------------------------------------
    def rendirse( self ) :
        if self.estado == kFinJuego :
            return True
        siJugadas = self.partida.numJugadas() > 0
        if siJugadas :
            if not QTUtil2.pregunta( self.pantalla, tr( "TE_RINDES" ) + " (%d)"%self.datosMotor.ppierde) :
                return False # no abandona
            self.resultado = kGanaRival
            self.partida.liJugadas[-1].siAbandono = True
            self.ponResultado( kGanaRival )
        else :
            self.procesador.inicio()

        return False

    #--------------------------------------------------------------------------------------------------------------------------------
    def siguienteJugada( self ) :

        if self.estado == kFinJuego :
            return

        self.estado = kJugando

        self.siJuegaHumano = False
        self.ponVista()
        siBlancas = self.partida.ultPosicion.siBlancas

        if self.partida.numJugadas() > 0 :
            jgUltima = self.partida.liJugadas[-1]
            if jgUltima :
                if jgUltima.siJaqueMate :
                    self.ponResultado( kGanaRival if self.siJugamosConBlancas == siBlancas else kGanamos )
                    return
                if jgUltima.siAhogado :
                    self.ponResultado( kTablas )
                    return
                if jgUltima.siTablasRepeticion :
                    self.ponResultado( kTablasRepeticion )
                    return
                if jgUltima.siTablas50 :
                    self.ponResultado( kTablas50 )
                    return
                if jgUltima.siTablasFaltaMaterial :
                    self.ponResultado( kTablasFaltaMaterial )
                    return

        siRival = siBlancas == self.siRivalConBlancas
        self.ponIndicador( siBlancas )

        self.refresh()

        if siRival :
            self.pensando( True )
            self.desactivaTodas( )

            siPensar = True

            if self.siApertura :

                siBien, desde, hasta, coronacion = self.apertura.juegaMotor( self.partida.fenActual() )

                if siBien :
                    self.rmRival = XMotorRespuesta.RespuestaMotor("Apertura")
                    self.rmRival.desde = desde
                    self.rmRival.hasta = hasta
                    self.rmRival.coronacion = coronacion
                    siPensar = False

            if siPensar :
                if self.siRivalInterno :
                    self.rmRival = self.xrival.juega()
                else :
                    nJugadas = self.partida.numJugadas()
                    if nJugadas > 30 :
                        tp = 300
                    else :
                        tp = 600
                    self.rmRival = self.xrival.juegaTiempo( tp, tp, 0 ) # engloba juega + juega Tiempo

            self.pensando( False )
            if self.mueveRival( self.rmRival ) :
                self.siguienteJugada()

        else :

            self.siJuegaHumano = True
            self.activaColor( siBlancas )

    #--------------------------------------------------------------------------------------------------------------------------------
    def mueveHumano( self, desde, hasta, coronacion = None ) :

        if self.siJuegaHumano :
            self.paraHumano()
        else :
            self.sigueHumano()
            return False

        movimiento = desde + hasta

        # Peón coronando
        if not coronacion and self.partida.ultPosicion.siPeonCoronando( desde, hasta ) :
            coronacion = self.tablero.peonCoronando(self.partida.ultPosicion.siBlancas)
            if coronacion is None :
                self.sigueHumano()
                return False
        if coronacion :
            movimiento += coronacion

        siBien, mens, jg = Jugada.dameJugada( self.partida.ultPosicion, desde, hasta, coronacion )

        if self.siTeclaPanico :
            self.sigueHumano()
            return False

        if siBien :

            if self.siTeclaPanico :
                self.sigueHumano()
                return False

            if self.siApertura :
                self.siApertura = self.apertura.compruebaHumano( self.partida.fenActual(), desde, hasta )

            self.movimientosPiezas( jg.liMovs )

            self.partida.ultPosicion = jg.posicion
            self.masJugada( jg )
            self.error = ""
            self.siguienteJugada()
            return True
        else :
            self.sigueHumano()
            self.error = mens
            return False

    #--------------------------------------------------------------------------------------------------------------------------------
    def masJugada( self, jg ) :

        # Preguntamos al mono si hay movimiento
        if self.siTerminada() :
            jg.siJaqueMate = jg.siJaque
            jg.siAhogado = not jg.siJaque

        self.partida.liJugadas.append( jg )
        if self.partida.pendienteApertura :
            self.listaAperturasStd.asignaApertura( self.partida )

        resp = self.partida.si3repetidas()
        if resp :
            jg.siTablasRepeticion = True
            rotulo = ""
            for j in resp :
                rotulo += "%d,"%(j/2+1,)
            rotulo = rotulo.strip(",")
            self.rotuloTablasRepeticion = rotulo

        if self.partida.ultPosicion.movPeonCap >= 50 :
            jg.siTablas50 = True

        if self.partida.ultPosicion.siFaltaMaterial() :
            jg.siTablasFaltaMaterial = True

        self.ponFlechaSC( jg.desde, jg.hasta )
        self.ponAyudas( self.ayudas )

        self.pgnRefresh(self.partida.ultPosicion.siBlancas)
        self.refresh()

        self.ponPosicionDGT()

    #--------------------------------------------------------------------------------------------------------------------------------
    def mueveRival( self, respMotor ) :
        desde = respMotor.desde
        hasta = respMotor.hasta

        coronacion = respMotor.coronacion

        siBien, mens, jg = Jugada.dameJugada( self.partida.ultPosicion, desde, hasta, coronacion )
        if siBien :
            self.partida.ultPosicion = jg.posicion

            self.masJugada( jg )
            self.beepExtendido()
            self.movimientosPiezas( jg.liMovs, True )

            self.error = ""

            return True
        else :
            self.error = mens
            return False

    #--------------------------------------------------------------------------------------------------------------------------------
    def ponResultado( self, quien ) :
        self.resultado = quien
        self.desactivaTodas( )
        self.siJuegaHumano = False

        self.estado = kFinJuego

        self.beepResultado( quien )

        nombreContrario = self.datosMotor.rotulo()

        mensaje = tr("PARTIDA_TERMINADA")
        if quien == kGanamos :
            mensaje = tr( "ENHORABUENA", nombreContrario )

        elif quien == kGanaRival :
            mensaje = tr( "HA_GANADO", nombreContrario )

        elif quien == kTablas :
            mensaje = tr( "TABLAS_CONTRA", nombreContrario )

        elif quien == kTablasRepeticion :
            mensaje = tr( "TABLAS_3REPETICION", self.rotuloTablasRepeticion, nombreContrario )
            self.resultado = kTablas

        elif quien == kTablas50 :
            mensaje = tr( "TABLAS_50", nombreContrario )
            self.resultado = kTablas

        elif quien == kTablasFaltaMaterial :
            mensaje = tr( "TABLAS_FALTA_MATERIAL", nombreContrario )
            self.resultado = kTablas

        elif quien == kGanamosTiempo :
            mensaje = tr( "ENHORABUENA_TIEMPO", nombreContrario )
            self.resultado = kGanamos

        elif quien == kGanaRivalTiempo :
            mensaje = tr( "HA_GANADO_TIEMPO", nombreContrario )
            self.resultado = kGanaRival

        elo = self.configuracion.eloActivo()
        if self.resultado == kGanamos :
            difelo = self.datosMotor.pgana

        elif self.resultado == kGanaRival :
            difelo = self.datosMotor.ppierde

        else :
            difelo = self.datosMotor.ptablas

        nelo = elo + difelo
        if nelo < 0 :
            nelo = 0
        self.configuracion.ponEloActivo( nelo )

        self.historial( elo, nelo)
        self.configuracion.graba()

        mensaje += "<br><br>%s : %d<br>"%(tr("ELO_RESULTADO" ),self.configuracion.eloActivo())

        self.guardarGanados(quien==kGanamos)
        QTUtil2.mensaje( self.pantalla, mensaje )
        self.ponFinJuego( )

    #--------------------------------------------------------------------------------------------------------------------------------
    def ponFinJuego( self ) :
        self.estado = kFinJuego
        self.pantalla.ponTitulo()
        self.desactivaTodas()
        liOpciones = self.procesador.liOpcionesInicio[:]
        if self.partida.numJugadas() :
            liOpciones.insert( 2, k_otros )
        else :
            self.quitaCapturas()
        self.pantalla.ponToolBar( liOpciones )

    #--------------------------------------------------------------------------------------------------------------------------------
    def historial( self, elo, nelo ) :
        dic = {}
        dic["FECHA"] = datetime.datetime.now()
        dic["RIVAL"] = self.datosMotor.rotulo()
        dic["RESULTADO"] = self.resultado
        dic["AELO"] = elo
        dic["NELO"] = nelo
        dic["MODONC"] = self.configuracion.modoNoCompetitivo

        lik = Util.LIdisk( self.configuracion.fichEstadElo )
        lik.append( dic )
        lik.close()
