from twisted.internet.protocol import Protocol, Factory, ClientFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor, error

import json
import base64

from database import *
from packettypes import *
from datahandler import *
from utils.utils import *
from gui.dialogs import alertMessageDialog
from constants import *
import global_vars as g
from objects import *

dataHandler = None

def startConnection():
    global dataHandler
    factory = gameClientFactory()
    g.connector = reactor.connectTCP(GAME_IP, GAME_PORT, factory)
    dataHandler = DataHandler()

    return factory.protocol

class gameClientProtocol(LineReceiver):
    MAX_LENGTH = 999999 #todo: find a suitable size (see client: sendMap (in clienttcp.py))

    def __init__(self, factory):
        self.factory = factory

    def connectionMade(self):
        ''' called when connection has been made '''
        ''' used for logging in and new account '''

        if g.gameState == MENU_LOGIN:
            # logging in, so send login after connection has been established
            username = g.gameEngine.menuLogin.username
            password = g.gameEngine.menuLogin.password

            g.tcpConn.sendLogin(username, password)

        log("Connection established to server")

    def lineReceived(self, data):
        global dataHandler

        # handle base64 data
        decodedData = base64.b64decode(data)

        log("Received data from server")
        log(" -> " + decodedData)

        dataHandler.handleData(decodedData)

    def sendData(self, data):
        # encode data using base64
        encodedData = base64.b64encode(data)
        self.sendLine(encodedData)


class gameClientFactory(ClientFactory):
    def __init__(self):
        self.protocol = p = gameClientProtocol(self)

    def startedConnecting(self, connector):
        log("Connecting to server...")

    def buildProtocol(self, addr):
        return self.protocol

    def clientConnectionFailed(self, connector, reason):
        errorMsg = reason.getErrorMessage().split(':')
        alertMessageDialog('Unable to connect to server: ' + errorMsg[1] + errorMsg[2], 'An error occured')
        print reason.getErrorMessage()

    def clientConnectionLost(self, connector, reason):
        print reason.getErrorMessage()
        try:
            #reactor.stop()
            log("Disconnection from server")
        except error.ReactorNotRunning:
            pass


class TCPConnection():
    def __init__(self, protocol):
        self.protocol = protocol

    def sendData(self, data):
        self.protocol.sendData(data)

    def sendNewAccount(self, username, password):
        packet = json.dumps([{"packet": ClientPackets.CNewAccount, "name": username, "password": password}])
        self.sendData(packet)

    def sendDelAccount(self, username, password):
        packet = json.dumps([{"packet": ClientPackets.CDelAccount, "name": username, "password": password}])
        self.sendData(packet)

    def sendLogin(self, username, password):
        packet = json.dumps([{"packet": ClientPackets.CLogin, "name": username, "password": password}], ensure_ascii=False)
        self.sendData(packet)

    def sendAddChar(self, name, sex, classNum, slot):
        packet = json.dumps([{"packet": ClientPackets.CAddChar, "name": name, "sex": sex, "class": classNum, "slot": slot}])
        self.sendData(packet)

    def sendDelChar(self, slot):
        packet = json.dumps([{"packet": ClientPackets.CDelChar}])
        self.sendData(packet)

    def sendGetClasses(self):
        packet = json.dumps([{"packet": ClientPackets.CGetClasses}])
        self.sendData(packet)

    def sendUseChar(self, charslot):
        packet = json.dumps([{"packet": ClientPackets.CUseChar, "charslot": charslot}])
        self.sendData(packet)

    def sayMsg(self, msg):
        packet = json.dumps([{"packet": ClientPackets.CSayMsg, "msg": msg}])
        self.sendData(packet)

    def globalMsg(self, msg):
        packet = json.dumps([{"packet": ClientPackets.CGlobalMsg, "msg": msg}])
        self.sendData(packet)

    def broadcastMsg(self, msg):
        packet = json.dumps([{"packet": ClientPackets.CBroadcastMsg, "msg": msg}])
        self.sendData(packet)

    def emoteMsg(self, msg):
        packet = json.dumps([{"packet": ClientPackets.CEmoteMsg, "msg": msg}])
        self.sendData(packet)

    def playerMsg(self, msg, msgTo):
        packet = json.dumps([{"packet": ClientPackets.CPlayerMsg, "msg": msg, "msgto": msgTo}])
        self.sendData(packet)

    def adminMsg(self, msg):
        packet = json.dumps([{"packet": ClientPackets.CAdminMsg, "msg": msg}])
        self.sendData(packet)

    def sendPlayerMove(self):
        packet = json.dumps([{"packet": ClientPackets.CPlayerMove, "direction": getPlayerDir(g.myIndex), "moving": Player[g.myIndex].moving}])
        self.sendData(packet)

    def sendPlayerAttack(self):
        packet = json.dumps([{"packet": ClientPackets.CAttack}])
        self.sendData(packet)

    def sendPlayerDir(self):
        packet = json.dumps([{"packet": ClientPackets.CPlayerDir, "direction": getPlayerDir(g.myIndex)}])
        self.sendData(packet)

    def sendPlayerRequestNewMap(self):
        packet = json.dumps([{"packet": ClientPackets.CRequestNewMap, "direction": getPlayerDir(g.myIndex)}])
        self.sendData(packet)

    def sendMapGetItem(self):
        packet = json.dumps([{"packet": ClientPackets.CMapGetItem}])
        self.sendData(packet)

    def sendMap(self):
        #todo: npc

        #canMoveNow = false

        packet = []
        packet.append({"packet": ClientPackets.CMapData, \
                       "mapname": Map.name, \
                       "moral": Map.moral, \
                       "tileset": Map.tileSet, \
                       "up": Map.up, \
                       "down": Map.down, \
                       "left": Map.left, \
                       "right": Map.right, \
                       "bootmap": Map.bootMap, \
                       "bootx": Map.bootX, \
                       "booty": Map.bootY})

        for x in range(MAX_MAPX):
            for y in range(MAX_MAPY):
                tempTile = Map.tile[x][y]
                packet.append([{"layer1":    tempTile.layer1, \
                                "layer2":    tempTile.layer2, \
                                "layer3":    tempTile.layer3, \
                                "mask":      tempTile.mask, \
                                "animation": tempTile.anim, \
                                "fringe":    tempTile.fringe, \
                                "type":      tempTile.type, \
                                "data1":     tempTile.data1, \
                                "data2":     tempTile.data2, \
                                "data3":     tempTile.data3}])


        for i in range(MAX_MAP_NPCS):
            packet.append([{'npcnum': Map.npc[i]}])


        packet = json.dumps(packet)
        self.sendData(packet)

    def sendNeedMap(self, answer=0):
        packet = json.dumps([{"packet": ClientPackets.CNeedMap, "answer": answer}])