from mcvals import *
import uuid
import mcserver
import world
import random

prelogin_hooks = []
postlogin_hooks = []

INVULNERABLE = 1
FLYING = 2
ALLOWFLYING = 4
CREATIVE = 8


def handshake(sock, tinfo):
    t = {}
    # http://wiki.vg/Protocol#Handshake
    pack = MinecraftPacket(0, [VarInt(0), String(""), Short(0), VarInt(0)])
    pack.receivePartial(sock)
    t["state"] = pack.values[3].val
    print "{} changed state to {}".format(sock.getpeername()[0], t["state"])
    return t


def loginstart(sock, tinfo):
    t = {}
    # http://wiki.vg/Protocol#Login_Start
    pack = MinecraftPacket(0, [String("")])
    pack.receivePartial(sock)
    t["username"] = pack.values[0].val
    print "{} changed username to {}".format(sock.getpeername()[0], t["username"])

    # http://wiki.vg/Protocol#Login_Success
    t["uuid"] = str(uuid.uuid4())
    pack2 = MinecraftPacket(2, [String(t["uuid"]), String(t["username"])])
    pack2.transmit(sock)
    t["state"] = 3
    print "{} started game as {}, state set to 3".format(t["username"], t["uuid"])
    tinfo.update(t)
    for p in prelogin_hooks:
        err, msg = p(sock, tinfo)
        if err == 1:
            print "Prelogin hook message: {}".format(msg)
        if err == 2:
            print "Prelogin hook error: {}".format(msg)
            t["kick"] = msg
            return t

    # http://wiki.vg/Protocol#Join_Game
    print "Sending join game to {}".format(t["username"])
    t["entityid"] = 5
    pack3 = MinecraftPacket(0x23, [Int(t["entityid"]),
                                   Byte(world.gamemode),
                                   Int(0),
                                   Byte(world.difficulty),
                                   Byte(10),
                                   String("flat"),
                                   Byte(0)])
    pack3.transmit(sock)

    # http://wiki.vg/Protocol#Spawn_Position
    # print "Sending position to {}".format(t["username"])
    #pack4 = MinecraftPacket(0x45, [Position((69,69,69))])
    # pack4.transmit(sock)

    # http://wiki.vg/Protocol#Player_Abilities_.28clientbound.29
    print "Sending player abilities to {}".format(t["username"])
    pack5 = MinecraftPacket(VarInt(0x2b), [Byte(FLYING | ALLOWFLYING),
                                           Float(0.4000000059604645),
                                           Float(0.699999988079071)])

    return t


def clientsettings(sock, tinfo):
    t = {}
    # http://wiki.vg/Protocol#Client_Settings
    pack = MinecraftPacket(4, [String(""),  # locale
                               Byte(0),    # distance
                               VarInt(0),  # chat mode
                               Byte(0),    # colors
                               Byte(0),    # skin parts
                               VarInt(0)])  # dexterity
    pack.receivePartial(sock)
    t["locale"] = pack.values[0].val
    t["distance"] = pack.values[1].val
    t["chatmode"] = pack.values[2].val
    t["colours"] = pack.values[3].val
    t["skinparts"] = pack.values[4].val
    t["dexterity"] = pack.values[5].val
    print "{} has locale {}, view distance {}, chat {}, colours {}, skin flag {} and is {}-handed.".format(tinfo["username"],
                                                                                                           t["locale"],
                                                                                                           t["distance"],
                                                                                                           ["on", "limited", "hidden"][t["chatmode"]],
                                                                                                           ["off", "on"][t["colours"]],
                                                                                                           hex(
                                                                                                               t["skinparts"]),
                                                                                                           ["left", "right"][t["dexterity"]])

    # http://wiki.vg/Protocol#Player_Position_And_Look_.28clientbound.29
    print "Sending {} new position.".format(tinfo["username"])
    t["teleportid"] = random.randint(0, 65535)
    t["pos"] = [float(x.strip()) for x in tinfo["conf"].get(
        "login", "spawnpos", "203,203,203").split(",")]
    pack2 = MinecraftPacket(0x2e, [Double(t["pos"][0]), Double(t["pos"][1]), Double(t["pos"][2]),  # pos
                                   Float(0), Float(0),  # yaw/pitch
                                   Byte(0), VarInt(t["teleportid"])])  # flags, teleport confirm ID
    pack2.transmit(sock)
    for p in postlogin_hooks:
        err, msg = p(sock, tinfo)
        if err == 1:
            print "post login log: {}".format(msg)
        if err == 2:
            print "error: {}".format(msg)
            t["kick"] = "post login hook error"
            return t
    return t


provides = {
    "0,0": handshake,
    "2,0": loginstart,
    "3,5": clientsettings
}

mcserver.functable.update(provides)
