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

import time
import random

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

import Util
import Gestor
import ControlPosicion
import Partida
import Jugada

import QT.QTUtil2 as QTUtil2
import QT.FormLayout as FormLayout
import QT.Iconos as Iconos

#==========================================================================================================================================
class ConfigNivel :
    def __init__( self, mate ) :

        self.mate = mate

        eduardo = "Trainings/De Eduardo Sadier 120536 posiciones de mate en dos.fns"
        pascal3 = "Trainings/De Pascal Georges en Scid/Mate en tres.fns"
        pascal4 = "Trainings/De Pascal Georges en Scid/Mate en cuatro y mas.fns"
        dicFicheros = { 1 : eduardo, 2 : eduardo, 3 : pascal3, 4 : pascal4 }

        self.fichero = dicFicheros[mate]

        liNivelMaximo = [ 500, 700, 80, 30 ]
        self.nivelMaximo = liNivelMaximo[mate-1]
        liNivelPosiciones = [ 15, 10, 7, 5 ]
        self.posicionesNivel = liNivelPosiciones[mate-1]
        liDepth = [ 2, 4, 6, 10 ]
        self.depth = liDepth[mate-1]

    def leeDKV( self ) :
        dic = Util.recuperaVar( "mate.dkv" )
        clave = "m2" if self.mate <= 2 else "m%d"%self.mate
        self.lista = list(dic[clave])
        random.seed( "%d"%self.mate )
        random.shuffle( self.lista )

    def dameFenPV( self, nivel, bloque ) :

        self.nivel = nivel
        self.bloque = bloque

        self.leeDKV()

        bqnum = nivel*10 + bloque

        n = bqnum*self.posicionesNivel
        li = self.lista[n:n+self.posicionesNivel]

        liFenPV = []
        f = open( self.fichero, "rb")
        for pos, pv in li :
            f.seek( pos )
            txt = f.read(100)
            fen = txt.split("\n")[0]
            if self.mate == 2 :
                pv = pv.split(" ")[0]
            elif self.mate == 1 :
                cp = ControlPosicion.ControlPosicion()
                cp.leeFen( fen )
                uno, dos, tres = pv.split(" ")
                cp.mover( uno[:2], uno[2:4], uno[4:] )
                cp.mover( dos[:2], dos[2:4], dos[4:] )
                fen = cp.fen()
                pv = tres
            liFenPV.append( (fen, pv) )
        f.close()
        return liFenPV

#==========================================================================================================================================

#==========================================================================================================================================
class MateBloque :
    def __init__( self ) :
        self.errores = None
        self.tiempo = None

    def ponDatos( self, errores, tiempo ) :
        self.errores = errores
        self.tiempo = tiempo

    def siTerminado( self ) :
        return not( (self.errores is None) or (self.errores > 0) )

#------------------------------------------------------------------------------------------------------
class MateNivel :
    def __init__( self, nivel ) :
        self.nivel = nivel
        self.liMateBloques = [ MateBloque() for x in range(10) ]

    def ponBloque( self, bloque, mateBloque ) :
        self.liMateBloques[bloque] = mateBloque

    def dameBloque( self, bloque ) :
        return self.liMateBloques[bloque]

    def grabaBloque( self, bloque, errores, tiempo ) :
        mateb = self.liMateBloques[bloque]
        siGraba = False
        if mateb.errores is None :
            siGraba = True
        elif mateb.errores > errores :
            siGraba = True
        elif mateb.errores == errores and mateb.tiempo > tiempo :
            siGraba = True

        if siGraba :
            mateb.errores = errores
            mateb.tiempo = tiempo

        return siGraba # Si nuevo record

    def siTerminado( self ) :
        for mateb in self.liMateBloques :
            if not mateb.siTerminado() :
                return False
        return True

    def numBloqueSinHacer( self ) :
        for n, mateb in enumerate(self.liMateBloques) :
            if not mateb.siTerminado() :
                return n
        return 0

#==========================================================================================================================================

#==========================================================================================================================================
class MateDB( Util.DicDisk ) :
    def __init__( self, gestor, mate ) :
        nomFichero = gestor.configuracion.ficheroMate
        Util.DicDisk.__init__( self, nomFichero, tabla = "m%d"%mate )

    def ultimoNivel( self ) :
        li = self.keys()

        if li :
            li.sort()
            mateNivel = self.__getitem__(li[-1])
        else :
            mateNivel = MateNivel( 0 )

        return mateNivel

    def nivel( self, nivel ) :
        clave = "%04d"%(nivel,)
        if clave in self.dic :
            mateNivel = self.__getitem__(clave)
        else :
            mateNivel = MateNivel( nivel )
        return mateNivel

#==========================================================================================================================================

#==========================================================================================================================================
class ControlMate :
    def __init__( self, gestor, mate ) :

        self.db = MateDB( gestor, mate)

        self.mate = mate

        self.mateNivel = self.db.ultimoNivel()

        self.configNivel = ConfigNivel(mate)

    def basadoEn( self ) :
        fich = self.configNivel.fichero[:-4]
        li = fich.split("/")
        txt = tr( li[1] )
        if len(li) == 3 :
            txt += ", " + tr(li[2])
        return txt

    def numDatos( self ) :
        return 10 # 1 grupo = siempre 10 bloques

    def analisis(self, fila, clave) : # compatibilidad
        return ""

    def conInformacion(self, fila, clave) : # compatibilidad
        return None

    def mueve(self, fila, clave) : # compatibilidad
        return False

    def dato( self, fila, clave ) :
        if clave == "NIVEL" :
            return str( fila + 1 )
        else  :
            mateBloque = self.mateNivel.dameBloque( fila )

            if clave == "ERRORES" :
                errores = mateBloque.errores
                return "-" if errores is None else str(errores)
            if clave == "TIEMPO" :
                tiempo = mateBloque.tiempo
                return "-" if tiempo is None else str(tiempo)
        return ""

    def inicia( self, bloque ) :

        self.bloque = bloque

        self.liFenPV = self.configNivel.dameFenPV(  self.mateNivel.nivel, bloque )
        self.posFenPV = -1

        self.tiempoInicial = time.clock()

    def final( self, errores ) :
        tiempo = int(time.clock()-self.tiempoInicial)

        siRecord = self.mateNivel.grabaBloque( self.bloque, errores, tiempo )

        # Grabamos, si Record
        if siRecord :
            nivel = self.mateNivel.nivel
            clave = "%04d"%(nivel,)
            self.db[clave] = self.mateNivel

        return siRecord, tiempo

    def siguienteFenPV( self ) :
        self.posFenPV += 1
        return (None, None) if self.posFenPV == self.configNivel.posicionesNivel else self.liFenPV[self.posFenPV]

    def repiteFenPV( self ) :
        return self.liFenPV[self.posFenPV]

    def ultimoNivel( self ) :
        return self.db.ultimoNivel()

    def ponNivel( self, nivel ) :
        self.mateNivel = self.db.nivel(nivel)

    def depth( self ) :
        return self.configNivel.depth

#==========================================================================================================================================
class GestorMate( Gestor.Gestor ) :

    #--------------------------------------------------------------------------------------------------------------------------------
    def inicio( self, mate ) :

        self.mate = mate

        self.controlMate = self.pgn = ControlMate( self, mate ) # El pgn lo usamos para mostrar el nivel actual

        self.pantalla.columnas60( True, cNivel = "MATE_ABBLOQUE" )

        self.pantalla.activaJuego(True, False)
        self.quitaAyudas(True, False)
        self.quitaCapturas()
        self.ponPiezasAbajo( True )
        self.ponMensajero( self.mueveHumano )
        self.pgnRefresh( True )
        self.pantalla.base.pgn.gotop()

        self.pantalla.ponRotulo1( "<center><h1>%s</h1></center>"%tr("MATE_EN",str(mate)) )
        self.pantalla.ponRotulo2( tr( "MATE_BASADO", self.controlMate.basadoEn() ) )
        self.tablero.exePulsadoNum = None

        self.lbNivel = self.pantalla.base.lbJugBlancas.ponColorFondoN( "black", "#EDEFF1" )

        # self.lbBloque = self.pantalla.base.lbJugNegras.ponColorFondoN( "black", "#EDEFF1" )

        self.finJuego()

        rival = self.configuracion.buscaRival( self.configuracion.tutorInicial )
        rival.ponMultiPV( 0 )

        self.xrival = self.procesador.creaRival( rival, None, self.controlMate.depth() )

        self.refresh()

    #--------------------------------------------------------------------------------------------------------------------------------
    def numDatos( self ) :
        return self.pgn.numDatos()

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

        if clave == k_finpartida : # No es al modo estandar porque hay una partida dentro de la partida
            self.finJuego()

        elif clave == k_terminar :
            self.finPartida()

        elif clave == k_mateNivel :
            self.cambiarJuego()

        elif clave == k_abandonar :
            self.finJuego()

        elif clave == k_reiniciar :
            self.repiteMate( False, self.numMov > 0 )

        elif clave == k_ayuda :
            self.ayudaMate(  )

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

    #--------------------------------------------------------------------------------------------------------------------------------
    def finalX( self ) :
        self.finPartida()
        return False

    #--------------------------------------------------------------------------------------------------------------------------------
    def finPartida( self ) :
        self.lbNivel.ponColorFondoN( "black", "white" )

        self.tablero.quitaFlechas()
        self.pantalla.columnas60( False )
        self.procesador.inicio()

    #--------------------------------------------------------------------------------------------------------------------------------
    def finJuego( self ) :

        self.ponRotuloNivel()
        self.ponRotuloBloque(False)
        self.pantalla.base.pgn.show()

        self.pantalla.ponToolBar( ( k_terminar, k_mateNivel ) )
        self.desactivaTodas( )
        self.estado = kFinJuego
        self.refresh()

    #--------------------------------------------------------------------------------------------------------------------------------
    def cambiarJuego( self ) :
        mateg = self.controlMate.ultimoNivel()
        ult_nivel = mateg.nivel+1
        ult_bloque = mateg.numBloqueSinHacer() + 1
        if mateg.siTerminado() :
            ult_nivel += 1
            ult_bloque = 1

        liGen = [ (None,None) ]

        config = FormLayout.Spinbox( tr( "MATE_NIVEL" ), 1, ult_nivel, 50 )
        liGen.append( ( config, ult_nivel ) )

        config = FormLayout.Spinbox( tr( "MATE_BLOQUE" ), 1, 10, 50 )
        liGen.append( ( config, ult_bloque ) )

        resultado = FormLayout.fedit( liGen, title= tr( "MATE_NIVEL" ), parent = self.pantalla, \
                        icon = Iconos.TB_Jugar(), siDefecto = False )

        if resultado :
            nv, bl = resultado[1]
            nv -= 1
            bl -= 1
            self.controlMate.ponNivel( nv )
            self.ponRotuloNivel()
            self.refresh()
            self.jugar( bl )

    #--------------------------------------------------------------------------------------------------------------------------------
    def ponRotuloNivel( self ) :

        nivel = self.controlMate.mateNivel.nivel

        txt = "%s : %d/%d"%( tr("MATE_NIVEL"), nivel+1, self.controlMate.configNivel.nivelMaximo )

        self.lbNivel.ponTexto(txt)
        self.lbNivel.show()

    #--------------------------------------------------------------------------------------------------------------------------------
    def ponRotuloBloque( self, siPoner ) :
        txt = "<center><h1>%s</h1>"%tr("MATE_EN",str(self.mate))
        if siPoner :

            bloque = self.controlMate.bloque+1
            posicion = self.controlMate.posFenPV+1
            errores = self.errores
            totbloques = self.controlMate.configNivel.posicionesNivel

            txt += "<h3>%s : %d </h3><h3> %s : %d </h3><h3> %d / %d</h3>"%( tr("MATE_BLOQUE"), bloque, tr("MATE_ERRORES"), errores, posicion, totbloques )
        self.pantalla.ponRotulo1( txt + "</center>" )

    #--------------------------------------------------------------------------------------------------------------------------------
    def siguienteMate( self ) :
        fen, pv = self.controlMate.siguienteFenPV()
        if fen is None :
            # Hemos terminado el bloque
            siRecord, tiempo = self.controlMate.final( self.errores )
            txt = "<center><h3> %s : %d</h3><h3>%s : %d </h3></center>"%( tr("MATE_ERRORES"), self.errores, tr("SEGUNDOS"), tiempo )

            if siRecord :
                txt += "<h3>%s</h3>"%tr( "MATE_ENHORABUENA" )

            QTUtil2.mensaje( self.pantalla, txt )
            self.finJuego()

        else :
            self.iniciaPosicion( fen )

    #--------------------------------------------------------------------------------------------------------------------------------
    def repiteMate( self, siMensaje, siError ) :

        if siError :
            self.errores += 1
        fen,pv = self.controlMate.repiteFenPV()

        if siMensaje :
            QTUtil2.mensError( self.pantalla, tr( "MATE_ERROR" ) )

        self.iniciaPosicion( fen )

    #--------------------------------------------------------------------------------------------------------------------------------
    def ayudaMate( self ) :
        self.errores += 1
        self.ponRotuloBloque(True)
        self.siAyuda = True

        if self.numMov == 0 :
            fen,pv = self.controlMate.repiteFenPV()

        else :
            rm = self.xrival.juega()
            if rm.mate != self.mate-self.numMov :
                self.repiteMate(False, False)
                self.ayudaMate()
                return

            pv = rm.pv.split(" ")[0]

        self.tablero.creaFlechaMov( pv[:2], pv[2:4], "2" )

    #--------------------------------------------------------------------------------------------------------------------------------
    def iniciaPosicion( self, fen ) :

        cp = ControlPosicion.ControlPosicion()
        cp.leeFen( fen )
        self.ponPosicion( cp )
        self.activaColor( True )
        self.siJugamosConBlancas = cp.siBlancas
        self.tablero.quitaFlechas()
        self.partida = Partida.Partida( cp )
        li = [ k_finpartida ]
        if self.mate > 1 :
            li.append( k_reiniciar )
        li.append( k_ayuda )
        self.pantalla.ponToolBar( li )
        self.numMov = 0
        self.siAyuda = False

        self.ponRotuloBloque(True)

        self.refresh()

    #--------------------------------------------------------------------------------------------------------------------------------
    def jugar( self, bloque ) :

        if self.estado == kJugando :
            self.estado = kFinJuego
            self.desactivaTodas()
            self.finJuego()
            return

        self.controlMate.inicia( bloque )
        self.errores = 0

        self.estado = kJugando

        self.pantalla.base.pgn.hide()

        self.siguienteMate()

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

        if not coronacion and self.partida.ultPosicion.siPeonCoronando( desde, hasta ) :
            coronacion = self.tablero.peonCoronando(self.partida.ultPosicion.siBlancas)
            if coronacion is None :
                return False

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

        self.partida.ultPosicion = jg.posicion
        self.partida.liJugadas.append( jg )
        if self.siAyuda :
            self.tablero.quitaFlechas()
        self.movimientosPiezas( jg.liMovs, False )
        if self.siTerminada() :
            self.siguienteMate()
            return

        self.numMov += 1
        if self.numMov == self.mate :
            self.repiteMate(True, True)
            return

        # Juega rival con depth 3
        rm = self.xrival.juega()
        desde = rm.desde
        hasta = rm.hasta
        coronacion = rm.coronacion

        siBien, mens, jg = Jugada.dameJugada( self.partida.ultPosicion, desde, hasta, coronacion )
        self.partida.ultPosicion = jg.posicion
        if self.siTerminada() :
            self.repiteMate(True, True)
            return
        self.ponFlechaSC( jg.desde, jg.hasta )
        self.movimientosPiezas( jg.liMovs, False )

    #--------------------------------------------------------------------------------------------------------------------------------
    def analizaPosicion( self, fila, clave ) :
        if self.estado == kJugando :
            self.finJuego()
            return
        self.jugar( fila )

