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

import os
import time

from PySide import QtCore, QtGui
from Constantes import *

import XMotorRespuesta

# ===========================================================================================================================
class XMotor(QtCore.QProcess):

    def __init__( self, nombre, exe, liOpcionesUCI=None, nMultiPV=None, siMaximizaMultiPV=False ) :

        # Lanzamos ya el motor
        QtCore.QProcess.__init__( self )
        self.setWorkingDirectory ( os.path.abspath(os.path.dirname(exe)) )
        # self.start( exe, [], mode = QtCore.QIODevice.Unbuffered | QtCore.QIODevice.ReadWrite )
        self.start( exe, [], mode = QtCore.QIODevice.ReadWrite )
        self.waitForStarted()

        # Control de lectura
        self._buffer = ""

        self.siDebug = False
        self.nomDebug = nombre

        # Configuramos
        self.nombre = nombre
        self.uci = self.orden_uci( )

        if liOpcionesUCI :
            for opcion, valor in liOpcionesUCI :
                if valor is None : # button en motores externos
                    self.orden_ok( "setoption name %s"%opcion )
                else :
                    self.orden_ok( "setoption name %s value %s"%(opcion, valor) )

        if nMultiPV :
            if not siMaximizaMultiPV :
                nMultiPV = min( nMultiPV, 20 )
            self.orden_ok( "setoption name %s value %s"%( "MultiPV", nMultiPV) )

    # -----------------------------------------------------------------------------------------
    def flush( self ) :
        self.readAllStandardOutput()
        self._buffer = ""

    # -----------------------------------------------------------------------------------------
    def buffer( self ) :
        self._lee()
        resp = self._buffer
        self._buffer = ""
        return resp

    # -----------------------------------------------------------------------------------------
    def apagar( self ) :
        try :
            self.escribe( "quit" )
            self.close()
        except :
            pass

    # -----------------------------------------------------------------------------------------
    def _lee( self ) :
        x = str(self.readAllStandardOutput())
        if x :
            self._buffer += x
            if self.siDebug :
                prlkS( x )
            return True
        return False
    # -----------------------------------------------------------------------------------------
    def escribe( self, linea ) :
        self.write( str(linea) + "\n" )
        if self.siDebug :
            prlk( self.nomDebug, "W", linea )

    # -----------------------------------------------------------------------------------------
    # def esperaRespuesta( self, segundos = None ) :
        # if segundos :
            # for x in range(segundos) :
                # if self.waitForReadyRead(1000) :
                    # break
                # if self.dispatch :
                    # self.dispatch()
        # else :
            # self.waitForReadyRead()
        # return str(self.readAllStandardOutput())

    # -----------------------------------------------------------------------------------------
    def espera( self, txt, msStop ) :
        iniTiempo = time.clock()
        siGracia = False
        while True :
            if self._lee() :
                if txt in self._buffer :
                    if self._buffer.endswith( "\n" ) :
                        return True
            QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.ExcludeUserInputEvents)

            queda = msStop - int((time.clock()-iniTiempo)*1000)
            if queda <= 0 :
                if siGracia :
                    return False
                else :
                    queda += 1000
                    msStop += 1000
                    self.escribe( "stop" )
                    siGracia = True
            self.waitForReadyRead(100)

    # -----------------------------------------------------------------------------------------
    def orden_ok( self, orden ) :
        self.escribe( orden )
        self.escribe( "isready" )
        self.espera( "readyok", 1000 )
        return self.buffer()

    # -----------------------------------------------------------------------------------------
    def orden_uci( self ) :
        self.escribe( "uci" )
        self.espera( "uciok", 5000 )
        return self.buffer()

    # -----------------------------------------------------------------------------------------
    def orden_bestmove( self, orden, msMaxTiempo ) :
        self.flush()
        self.escribe( orden )
        resp = self.espera( "bestmove", msMaxTiempo+15000 )
        if not resp :
            return self.orden_ok( "stop" )
        return self.buffer()

    # -----------------------------------------------------------------------------------------
    def orden_infinito( self, busca, msMaxTiempo ) :
        self.flush()
        self.escribe( "go infinite" )
        self.espera( busca, msMaxTiempo )
        return self.orden_ok( "stop" )

    # -----------------------------------------------------------------------------------------
    def mejorMov( self, fen, maxTiempo, maxProfundidad ) :
        # self.orden_ok( "ucinewgame" )
        self.orden_ok( "position fen %s"%fen )
        env = "go"
        if maxTiempo :
            env += " movetime %d"%maxTiempo
        if maxProfundidad :
            env += " depth %d"%maxProfundidad

        msTiempo = maxTiempo if maxTiempo else 10000

        resp = self.orden_bestmove( env, msTiempo )

        mrm = XMotorRespuesta.MRespuestaMotor( self.nombre )
        mrm.dispatch( resp, maxTiempo, maxProfundidad )
        mrm.maxTiempo = maxTiempo
        mrm.maxProfundidad = maxProfundidad
        return mrm

    # -----------------------------------------------------------------------------------------
    def mejorMovInfinito( self, fen, maxProfundidad ) :
        # self.orden_ok( "ucinewgame" )
        self.orden_ok( "position fen %s"%fen )
        busca = " depth %d "%maxProfundidad

        tiempo = maxProfundidad*2000
        if maxProfundidad > 9 :
            tiempo += (maxProfundidad-9)*20000

        resp = self.orden_infinito( busca, tiempo )

        mrm = XMotorRespuesta.MRespuestaMotor( self.nombre )
        mrm.dispatch( resp, None, maxProfundidad )
        mrm.maxTiempo = None
        mrm.maxProfundidad = maxProfundidad
        return mrm

    # -----------------------------------------------------------------------------------------
    def mejorMovTiempo( self, fen, tiempoBlancas, tiempoNegras, tiempoJugada ) :
        # self.orden_ok( "ucinewgame" )
        self.orden_ok( "position fen %s"%fen )
        env = "go wtime %d btime %d"%( tiempoBlancas, tiempoNegras )
        if tiempoJugada :
            env += " winc %d"%tiempoJugada
        maxtiempo = tiempoBlancas if " w " in fen else tiempoNegras
        resp = self.orden_bestmove( env, maxtiempo )
        mrm = XMotorRespuesta.MRespuestaMotor( self.nombre )
        mrm.dispatch( resp, None, None )
        return mrm
