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

#==========================================================================================================================================
import random
import socket
import time

from PySide import QtCore, QtGui

from Code.Traducir import tr
import Code.Util as Util
import Code.Remoto as Remoto
import Code.Usu as Usu

import QTUtil2
import Colocacion
import Iconos
import Controles
import EntMaquina

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

CONEXION, ESPERA_OK, RECIBE_USUARIO_CLAVE, RECIBE_DATOS = range(4)

#==========================================================================================================================================
class WConfServidor( QtGui.QDialog ):

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def __init__(self, gestor )  :
        super(WConfServidor, self).__init__(gestor.pantalla)

        self.setWindowTitle( tr( "REMOTO_SERVIDOR" ) )
        self.setWindowIcon( Iconos.RemotoServidor() )
        self.setWindowFlags( QtCore.Qt.Dialog | QtCore.Qt.WindowTitleHint )

        # Toolbar
        liAcciones = [ ( tr( "ACEPTAR" ), Iconos.TB_Aceptar(), "aceptar" ), None,
                    ( tr( "CANCELAR" ), Iconos.TB_Cancelar(), "cancelar" ), None,
                    ]
        tb = Controles.TB( self, liAcciones )

        lbIP = Controles.LB( tr( "IP_CONEXION" ) + " :" )
        self.edIP = Controles.ED( self, Remoto.miIP() ).anchoMinimo( 80 ).deshabilitado( True )
        btIP = Controles.PB( self, "", self.ponIP ).ponIcono( Iconos.Buscar() )

        minimo, maximo = 15000, 50000
        puerto = random.randint( minimo, maximo )
        self.edPuerto, lbPuerto = QTUtil2.spinBoxLB( puerto, minimo, maximo, maxTam=60, etiqueta=tr( "PUERTO_CONEXION" ) )
        self.edClave = Controles.ED( self ).anchoMinimo( 50 )
        lbClave = Controles.LB( tr( "CLAVE_CONEXION" ) + " :" )

        # Layout
        ## IP
        lyIP = Colocacion.H().control( self.edIP ).control( btIP ).relleno(1)

        ly = Colocacion.G()
        ly.controld( lbPuerto, 0, 0 ).control( self.edPuerto, 0, 1 )
        ly.controld( lbClave, 1, 0 ).control( self.edClave, 1, 1 )
        ly.controld( lbIP, 2, 0 ).otro( lyIP, 2, 1 )
        gbC = Controles.GB( self, tr( "PARAMETROS_CONEXION" ), ly )

        lyResto = Colocacion.V()
        lyResto.control( gbC )
        lyResto.margen( 15 )

        layout = Colocacion.V().control( tb ).otro( lyResto ).margen( 3 )

        self.setLayout( layout )

        self.ficheroDIC = gestor.configuracion.ficheroRemoto
        self.recuperaDic()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def ponIP( self ) :
        self.edIP.ponTexto( Remoto.miIP() )
        self.edIP.deshabilitado( False )
    #--------------------------------------------------------------------------------------------------------------------------------------------
    def procesarTB( self ) :
        accion = self.sender().clave
        if accion == "aceptar" :
            dic = {}
            dic["PUERTO"] = self.edPuerto.value()
            dic["CLAVE"] = self.edClave.texto()
            dic["IP"] = self.edIP.texto()

            self.dic = dic
            self.guardaDic( dic )
            self.accept()

        elif accion == "cancelar" :
            self.reject()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def guardaDic( self, dic ) :
        Util.guardaDIC( dic, self.ficheroDIC )

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def recuperaDic( self ) :
        dic = Util.recuperaDIC( self.ficheroDIC )
        if dic :
            self.edPuerto.setValue(dic["PUERTO"])
            self.edClave.ponTexto(dic["CLAVE"])
            txt = dic["IP"]
            if len(txt) == 0 or txt.replace(".","").isdigit() :
                txt1 = Remoto.miIP()
                if txt1 :
                    txt = txt1
            self.edIP.ponTexto(txt)

# ----------------------------------------------------------------------------------------------
def confServidor( gestor ):

    w = WConfServidor( gestor )
    if w.exec_() :
        return w.dic
    else :
        return None

#==========================================================================================================================================
class WEsperaAlCliente( QtGui.QDialog ):

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def __init__(self, wParent, dicDatos, configuracion )  :
        super(WEsperaAlCliente, self).__init__(wParent)

        self.setWindowTitle( tr( "CONEXION" ) )
        self.setWindowIcon( Iconos.RemotoServidor() )
        self.setWindowFlags( QtCore.Qt.Dialog | QtCore.Qt.WindowTitleHint )

        self.configuracion = configuracion

        self.dicDatos = dicDatos

        self.server = dicDatos["SERVER"]

        self.operacion = CONEXION
        self.timer = QtCore.QTimer(self)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.controlTiempo )
        self.timer.start(200)

        self.cliente = None

        # Cadena de conexión
        cadenaConexion = "IP = <b>%s</b><br>%s = <b>%d</b><br>%s = <b>%s</b>"%( dicDatos["IP"], tr( "PUERTO_CONEXION" ), dicDatos["PUERTO"], tr( "CLAVE_CONEXION" ), dicDatos["CLAVE"] )
        self.lbCadena = Controles.LB( cadenaConexion )
        btClip = Controles.PB( self, "", rutina=self.portapapeles ).ponIcono( Iconos.TB_Copiar(), tamIcon = 64 )
        btClip.ponToolTip( tr( "CLIPBOARD_COPIAR_CONEXION" ) )

        # Conexión
        self.txtEsperando = "... " + tr( "ESPERANDO_CONEXION_RIVAL" ) + " ..."
        self.lbConexion = Controles.LB( self.txtEsperando )
        self.btAceptar = Controles.PB( self, tr( "ACEPTAR_CONEXION" ), rutina = self.aceptarConexion ).ponIcono( Iconos.TB_Aceptar()).ponPlano( False )
        self.btRechazar = Controles.PB( self, tr( "RECHAZAR_CONEXION" ), rutina = self.rechazarConexion ).ponIcono( Iconos.TB_Cancelar()).ponPlano( False )

        # Layout
        ## cadena conexion
        hbox = Colocacion.H().relleno(1).control(self.lbCadena).control(btClip).relleno(1)
        gbPar = Controles.GB( self, tr( "PARAMETROS_CONEXION" ), hbox )

        ## Conexión
        gbox = Colocacion.G().controlc( self.lbConexion, 0, 0, 1, 2 )
        gbox.control( self.btAceptar, 1, 0 ).control( self.btRechazar, 1, 1 )
        gbCon = Controles.GB( self, tr( "CONEXION" ), gbox )

        lyResto = Colocacion.V()
        lyResto.control( gbPar ).espacio( 15 )
        lyResto.control( gbCon ).espacio( 15 )
        lyResto.margen( 15 )

        layout = Colocacion.V().otro( lyResto ).margen( 3 )

        self.setLayout( layout )

        self.ponDatosCliente()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def controlTiempo( self ) :
        if self.operacion == CONEXION :
            try :
                cliente, datos = self.server.accept( )
                self.operacion = None
                self.trasCONEXION( cliente, datos )
            except :
                pass

        elif self.operacion == RECIBE_USUARIO_CLAVE :
            try :
                txt = self.cliente.recv( 1024 )
                self.operacion = None
                self.trasRECIBE_USUARIO_CLAVE( txt )
            except socket.timeout :
                pass
            except socket.error :
                self.rechazarConexion()

        elif self.operacion == ESPERA_OK :
            try :
                txt = self.cliente.recv( 1024 )
                self.operacion = None
                self.trasESPERA_OK( txt )
            except socket.timeout :
                if (time.clock() - self.iniTiempoOK ) > self.maxTiempoOK :
                    self.operacion = None
                    self.trasESPERA_OK( None )
            except socket.error :
                self.rechazarConexion()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def trasCONEXION( self, cliente, datos_cliente ) :
        self.cliente = cliente
        self.dicDatos["CLIENTE_IP"] = datos_cliente[0]

        # Siguiente paso -> Nos tiene que enviar usuario y clave
        self.operacion = RECIBE_USUARIO_CLAVE

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def trasRECIBE_USUARIO_CLAVE( self, txt ) :
        mens = Remoto.Mensaje()
        mens.lee( txt )
        if not mens.siError :
            clave = mens.dameTipo( Remoto.MENS_CLAVE )
            if clave and Usu.dec(clave.texto) == self.dicDatos["CLAVE"] :
                usuario = mens.dameTipo( Remoto.MENS_USUARIO )
                if usuario :
                    self.rival = usuario.texto if usuario.texto else "?"
                else :
                    self.rival = "?"
                self.dicDatos["RIVAL"] = self.rival
                self.ponDatosCliente()
        else :
            self.cliente.close()
            self.cliente = None
            self.ponDatosCliente()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def ponDatosCliente( self ) :
        if self.cliente :
            rotulo = "%s = %s<br>IP = %s"%( tr( "RIVAL" ), self.rival, self.dicDatos[ "CLIENTE_IP"] )
            siActivo = True
        else :
            rotulo = self.txtEsperando
            siActivo = False
        self.btAceptar.setVisible( siActivo )
        self.btRechazar.setVisible( siActivo )
        self.lbConexion.ponTexto( rotulo )

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def portapapeles( self ) :
        cb = QtGui.QApplication.clipboard()
        txt = "[IP=%(IP)s·PORT=%(PUERTO)s·KEY=%(CLAVE)s]"%self.dicDatos
        cb.setText( txt )

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def aceptarConexion( self ) :
        # Mandamos todos los datos
        mens = Remoto.Mensaje()
        mens.ponOK( True )
        mens.nuevo( Remoto.MENS_USUARIO, self.configuracion.jugador )
        self.cliente.send( mens.texto() )

        self.operacion = ESPERA_OK

        # Se espera por tiempo ya que trabajamos directamente contra el ordenador
        self.maxTiempoOK = 3
        self.iniTiempoOK = time.clock()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def trasESPERA_OK( self, txt ) :
        if txt :
            mens = Remoto.Mensaje()
            mens.lee( txt )
            if mens.siOK() :
                self.accept()
                return
        self.rechazarConexion()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def rechazarConexion( self ) :
        if self.cliente :
            self.cliente.close()
        self.cliente = None
        self.ponDatosCliente()
        self.operacion = CONEXION

#==========================================================================================================================================
def esperaAlCliente( parent, dicDatos, configuracion ) :
    w = WEsperaAlCliente( parent, dicDatos, configuracion )
    if w.exec_() :
        return w.dicDatos, w.cliente
    else :
        return None

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

#==========================================================================================================================================
class WConectaAlServidor( QtGui.QDialog ):

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def __init__(self, wParent, configuracion )  :
        super(WConectaAlServidor, self).__init__(wParent)

        self.setWindowTitle( tr( "REMOTO_CLIENTE" ) )
        self.setWindowIcon( Iconos.RemotoCliente() )
        self.setWindowFlags( QtCore.Qt.Dialog | QtCore.Qt.WindowTitleHint )

        self.configuracion = configuracion

        # Toolbar
        liAcciones = [ ( tr( "CONECTAR" ), Iconos.TB_Conectar(), "conectar" ), None,
                    ( tr( "CANCELAR" ), Iconos.TB_Cancelar(), "cancelar" ), None,
                    ]
        tb = Controles.TB( self, liAcciones )

        # Conexión
        minimo, maximo = 15000, 50000
        self.edIP = Controles.ED( self ).anchoMinimo( 80 )
        lbIP = Controles.LB( tr( "IP_CONEXION" ) + " :" )
        self.edPuerto, lbPuerto = QTUtil2.spinBoxLB( minimo, minimo, maximo, maxTam=60, etiqueta=tr( "PUERTO_CONEXION" ) )
        self.edClave = Controles.ED( self ).anchoMinimo( 80 )
        lbClave = Controles.LB( tr( "CLAVE_CONEXION" ) + " :" )
        btClip = Controles.PB( self, "", rutina=self.portapapeles ).ponIcono( Iconos.TB_Pegar(), tamIcon = 64 )
        btClip.ponToolTip( tr( "CLIPBOARD_PEGAR_CONEXION" ) )

        # Layout
        ## Conexion
        ly = Colocacion.G()
        ly.controld( lbIP, 0, 0 ).control( self.edIP, 0, 1 )
        ly.controld( lbPuerto, 1, 0 ).control( self.edPuerto, 1, 1 )
        ly.controld( lbClave, 2, 0 ).control( self.edClave, 2, 1 )
        ly.controlc( btClip, 0, 2, 3, 1 )
        gbCon = Controles.GB( self, tr( "PARAMETROS_CONEXION" ), ly )

        lyResto = Colocacion.V()
        lyResto.control( gbCon ).espacio( 15 )
        lyResto.margen( 15 )

        layout = Colocacion.V().control( tb ).otro( lyResto ).margen( 3 )

        self.setLayout( layout )

        self.ficheroDIC = configuracion.ficheroCliente
        self.recuperaDic()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def procesarTB( self ) :
        accion = self.sender().clave
        if accion == "conectar" :
            dic = {}
            dic["IP"] = self.edIP.texto()
            dic["PUERTO"] = self.edPuerto.value()
            dic["CLAVE"] = self.edClave.texto()
            self.guardaDic( dic )

            self.intentaConectar( dic )

        elif accion == "cancelar" :
            self.reject()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def intentaConectar( self, dicDatos ) :

        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.settimeout(0.1)
        self.dicDatos = dicDatos

        self.operacion = CONEXION

        self.me = QTUtil2.mensEspera.inicio(self,tr("INTENTANDO_CONECTAR"), siCancelar = True)

        self.timer = QtCore.QTimer(self)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.controlTiempo )
        self.timer.start(200)

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def controlTiempo( self ) :

        def corta( siMens ) :
            self.me.final()
            self.timer.stop()
            if siMens :
                QTUtil2.mensError( self, tr( "IMPOSIBLE_CONEXION" ) )

        if self.me.cancelado() :
            corta( False )

        elif self.operacion == CONEXION :
            try :
                self.server.connect( (self.dicDatos["IP"], self.dicDatos["PUERTO"]) )
                self.operacion = None
                self.trasCONEXION( )
            except socket.timeout :
                pass
            except socket.error :
                corta( True )

        elif self.operacion == RECIBE_DATOS :
            try :
                txt = self.server.recv( 1024 )
                self.operacion = None
                self.trasRECIBE_DATOS( txt )

            except socket.timeout :
                pass
            except socket.error :
                corta( True )

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def trasCONEXION( self ) :
        mens = Remoto.Mensaje()
        mens.nuevo( Remoto.MENS_CLAVE, Usu.enc(self.dicDatos["CLAVE"]) )
        mens.nuevo( Remoto.MENS_USUARIO, self.configuracion.jugador )

        self.server.send( mens.texto() )

        self.operacion = RECIBE_DATOS

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def trasRECIBE_DATOS( self, txt ) :
        if txt :
            mens = Remoto.Mensaje()
            mens.lee( txt )
            if not mens.siError :
                if mens.siOK() :

                    usuario = mens.dameTipo( Remoto.MENS_USUARIO )
                    self.dicDatos["RIVAL"] = usuario.texto if usuario.texto else "?"

                    mens.reset()
                    mens.ponOK( True )
                    self.server.send( mens.texto() )
                    self.me.final()
                    self.accept()
                    return
        self.me.final()
        QTUtil2.mensError( self, tr( "IMPOSIBLE_CONEXION" ) )
        self.server.close()
        self.reject()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def guardaDic( self, dic ) :
        Util.guardaDIC( dic, self.ficheroDIC )

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def recuperaDic( self ) :
        dic = Util.recuperaDIC( self.ficheroDIC )
        if dic :
            self.edIP.ponTexto(dic["IP"])
            self.edPuerto.setValue(dic["PUERTO"])
            self.edClave.ponTexto(dic["CLAVE"])

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def portapapeles( self ) :
        cb = QtGui.QApplication.clipboard()
        texto = str(cb.text( ))
        if texto :
            texto = texto.strip("[]")
            for x in texto.split( "·" ) :
                li = x.split( "=" )
                if len(li)==2 :
                    clave, valor = li
                    if clave == "IP" :
                        self.edIP.ponTexto(valor)
                    elif clave == "PORT" :
                        self.edPuerto.setValue(int(valor))
                    elif clave == "KEY" :
                        self.edClave.ponTexto(valor)

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

def conectaAlServidor( parent, configuracion ):

    w = WConectaAlServidor( parent, configuracion )
    if w.exec_() :
        return w.dicDatos, w.server
    else :
        return None

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

#==========================================================================================================================================
class WNuevaPartida( QtGui.QDialog ):

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def __init__(self, wParent, configuracion, colorInicial )  :
        super(WNuevaPartida, self).__init__(wParent)

        self.setWindowTitle( tr( "NUEVA_PARTIDA" ) )
        self.setWindowIcon( Iconos.TB_Nuevo() )
        self.setWindowFlags( QtCore.Qt.Dialog | QtCore.Qt.WindowTitleHint )

        self.configuracion = configuracion

        # Toolbar
        liAcciones = [ ( tr( "ACEPTAR" ), Iconos.TB_Aceptar(), "aceptar" ), None,
                    ( tr( "CANCELAR" ), Iconos.TB_Cancelar(), "cancelar" ), None,
                    ]
        tb = Controles.TB( self, liAcciones )

        # Blancas o negras
        self.rbBlancas = Controles.RB( self, tr( "PGN_WHITE" ) )
        self.rbNegras = Controles.RB( self, tr( "PGN_BLACK" ) )
        self.rbRandom = Controles.RB( self, tr( "ALEATORIO" ) )

        # Ayudas
        self.edAyudas = QTUtil2.spinBoxLB( 0, 0, 99, maxTam=50 )

        # Posicion
        self.btPosicion = Controles.PB( self, " "*5+tr( "CAMBIAR" )+" "*5, self.editarPosicion ).ponPlano( False )
        self.fen = ""

        # Tiempo
        self.edMinutos, lbMinutos = QTUtil2.spinBoxLB( 15, 0, 99, maxTam=50, etiqueta=tr( "TIEMPO_MINUTOS_TOTAL" ) )
        self.edSegundos, lbSegundos = QTUtil2.spinBoxLB( 6, 0, 99, maxTam=50, etiqueta=tr( "TIEMPO_SEGUNDOS_JUGADA" ) )

        # Layout
        ## Color
        hbox = Colocacion.H().relleno(1).control(self.rbBlancas).espacio(30).control(self.rbNegras).espacio(30).control(self.rbRandom).relleno(1)
        gbColor = Controles.GB( self, tr( "JUGAMOS_CON" ), hbox )

        ## Ayudas
        hbox = Colocacion.H().control( self.edAyudas )
        gbAyudas = Controles.GB( self, tr( "AYUDAS" ), hbox )

        ## Ayudas + Color
        hAC = Colocacion.H().control( gbColor ).control( gbAyudas )

        ## Posicion
        hbox = Colocacion.H().relleno(1).control( self.btPosicion ).relleno(1)
        self.gbPosicion = gbPosicion = Controles.GB( self, tr( "POSICION_INICIAL" ), hbox )

        ## Tiempo
        ly = Colocacion.G()
        ly.controld( lbMinutos, 0, 0 ).control( self.edMinutos, 0, 1 )
        ly.controld( lbSegundos, 1, 0 ).control( self.edSegundos, 1, 1 )
        gbT = Controles.GB( self, tr( "ETI_TIEMPO" ), ly )

        lyResto = Colocacion.V()
        lyResto.otro( hAC).espacio( 15 )
        lyResto.control( gbT ).espacio( 15 )
        lyResto.control( gbPosicion ).espacio( 15 )
        lyResto.margen( 15 )

        layout = Colocacion.V().control( tb ).otro( lyResto ).margen( 3 )

        self.setLayout( layout )

        self.ficheroDIC = configuracion.ficheroRemNueva
        self.recuperaDic()

        if colorInicial is None :
            colorInicial = "R"
        self.rbBlancas.activa(colorInicial == "W")
        self.rbNegras.activa(colorInicial == "B")
        self.rbRandom.activa(colorInicial == "R")

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def editarPosicion( self ) :
        w = EntMaquina.WPosicion( self, self.configuracion, self.fen )
        if w.exec_() :
            self.fen = w.fen
            self.muestraPosicion()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def muestraPosicion( self ) :
        if self.fen :
            rotulo = self.fen
        else :
            rotulo = tr( "CAMBIAR" )
        rotulo = " "*5+rotulo + " "*5
        self.btPosicion.ponTexto( rotulo )

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def procesarTB( self ) :
        accion = self.sender().clave
        if accion == "aceptar" :
            dic = {}
            dic["COLOR"] = "W" if self.rbBlancas.isChecked() else ( "B" if self.rbNegras.isChecked() else "R" )
            dic["FEN"] = self.fen
            dic["AYUDAS"] = self.edAyudas.value()
            dic["MINUTOS"] = self.edMinutos.value()
            dic["SEGUNDOS"] = self.edSegundos.value()

            self.dic = dic
            self.guardaDic( dic )
            self.accept()

        elif accion == "cancelar" :
            self.reject()

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def guardaDic( self, dic ) :
        Util.guardaDIC( dic, self.ficheroDIC )

    #--------------------------------------------------------------------------------------------------------------------------------------------
    def recuperaDic( self ) :
        dic = Util.recuperaDIC( self.ficheroDIC )
        if dic :

            self.fen = dic["FEN"]
            self.muestraPosicion()

            self.edAyudas.setValue(dic["AYUDAS"])

            self.edMinutos.setValue(dic["MINUTOS"])
            self.edSegundos.setValue(dic["SEGUNDOS"])

# ----------------------------------------------------------------------------------------------
def nuevaPartida( parent, configuracion, color = "R" ):

    w = WNuevaPartida( parent, configuracion, color )
    if w.exec_() :
        return w.dic
    else :
        return None
