# -*- coding: utf-8 -*-

"""
Copyright (C) 2009-2016 Wolfgang Rohdewald <wolfgang@rohdewald.de>

SPDX-License-Identifier: GPL-2.0


The DBPasswordChecker is based on an example from the book
Twisted Network Programming Essentials by Abe Fettig, 2006
O'Reilly Media, Inc., ISBN 0-596-10032-9
"""

import datetime

from twisted.internet.defer import fail
from twisted.spread import pb

from common import Internal, Debug, Options, StrMixin
from servercommon import srvError
from log import logDebug
from mi18n import i18nE
from query import Query

class User(pb.Avatar, StrMixin):

    """the twisted avatar"""

    def __init__(self, userid):
        self.name = Query(
            'select name from player where id=?',
            (userid,
            )).records[0][0]
        self.mind = None
        self.server = None
        self.dbIdent = None
        self.voiceId = None
        self.maxGameId = None
        self.lastPing = None
        self.pinged()

    def pinged(self):
        """time of last ping or message from user"""
        self.lastPing = datetime.datetime.now()
        if self.server:
            self.server.lastPing = self.lastPing

    def source(self):
        """how did he connect?"""
        result = str(self.mind.broker.transport.getPeer())
        if 'UNIXAddress' in result:
            # socket: we want to get the socket name
            result = Options.socket
        return result

    def attached(self, mind):
        """override pb.Avatar.attached"""
        self.mind = mind
        self.server.login(self)

    def detached(self, unusedMind):
        """override pb.Avatar.detached"""
        if Debug.connections:
            logDebug(
                '%s: connection detached from %s' %
                (self, self.source()))
        self.server.logout(self)
        self.mind = None

    def perspective_setClientProperties(
            self, dbIdent, voiceId, maxGameId, clientVersion=None):
        """perspective_* methods are to be called remotely"""
        self.pinged()
        self.dbIdent = dbIdent
        self.voiceId = voiceId
        self.maxGameId = maxGameId
        serverVersion = Internal.defaultPort
        if clientVersion != serverVersion:
            # we assume that versions x.y.* are compatible
            if clientVersion is None:
                # client passed no version info
                return fail(srvError(pb.Error,
                                     i18nE(
                                         'Your client has a version older than 4.9.0 but you need %1 for this server'),
                                     serverVersion))
            commonDigits = len([x for x in zip(
                clientVersion.split(b'.'),
                serverVersion.split(b'.'))
                                if x[0] == x[1]])
            if commonDigits < 2:
                return fail(srvError(pb.Error,
                                     i18nE(
                                         'Your client has version %1 but you need %2 for this server'),
                                     clientVersion or '<4.9.0',
                                     '.'.join(serverVersion.split('.')[:2]) + '.*'))
        if Debug.table:
            logDebug('client has dbIdent={} voiceId={} maxGameId={} clientVersion {}'.format(
                self.dbIdent, self.voiceId, self.maxGameId, clientVersion))
        self.server.sendTables(self)
        return None

    def perspective_ping(self):
        """perspective_* methods are to be called remotely"""
        return self.pinged()

    def perspective_needRulesets(self, rulesetHashes):
        """perspective_* methods are to be called remotely"""
        return self.server.needRulesets(rulesetHashes)

    def perspective_joinTable(self, tableid):
        """perspective_* methods are to be called remotely"""
        return self.server.joinTable(self, tableid)

    def perspective_leaveTable(self, tableid):
        """perspective_* methods are to be called remotely"""
        return self.server.leaveTable(self, tableid, None)

    def perspective_newTable(
            self, ruleset, playOpen, autoPlay, wantedGame: str, tableId=None):
        """perspective_* methods are to be called remotely"""
        return self.server.newTable(self, ruleset, playOpen, autoPlay, wantedGame, tableId)

    def perspective_startGame(self, tableid):
        """perspective_* methods are to be called remotely"""
        return self.server.startGame(self, tableid)

    def perspective_logout(self):
        """perspective_* methods are to be called remotely"""
        self.detached(None)

    def perspective_chat(self, chatString):
        """perspective_* methods are to be called remotely"""
        self.pinged()
        return self.server.chat(chatString)

    def __str__(self):
        return self.name
