from urllib import urlencode
from urlparse import urlunparse

from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.internet.task import LoopingCall
from twisted.python import log
from twisted.web.client import getPage

from bravo import version as bravo_version
from bravo.config import configuration
from bravo.entity import Pickup, Player
from bravo.protocols.infini import InfiniClientProtocol, InfiniNodeProtocol

(STATE_UNAUTHENTICATED, STATE_CHALLENGED, STATE_AUTHENTICATED,
    STATE_LOCATED) = range(4)

entities_by_name = {
    "Player": Player,
    "Pickup": Pickup,
}

class InfiniClientFactory(Factory):
    """
    A ``Factory`` that serves as an InfiniCraft client.
    """

    protocol = InfiniClientProtocol

    def __init__(self, name):
        self.protocols = set()

        log.msg("InfiniClient started")

    def buildProtocol(self, addr):
        log.msg("Starting connection to %s" % addr)

        return Factory.buildProtocol(self, addr)

class InfiniNodeFactory(Factory):
    """
    A ``Factory`` that serves as an InfiniCraft node.
    """

    protocol = InfiniNodeProtocol

    ready = False

    broadcast_loop = None

    private_key = None

    def __init__(self, name):
        self.name = name
        self.port = configuration.getint("infininode %s" % name, "port")
        self.gateway = configuration.get("infininode %s" % name, "gateway")

        if configuration.has_option("infininode %s" % name, "private_key"):
            self.private_key = configuration.get("infininode %s" % name,
                "private_key")

        self.broadcast_loop = LoopingCall(self.broadcast)
        self.broadcast_loop.start(220)

    def broadcast(self):
        args = urlencode({
            "max_clients": 10,
            "max_chunks": 256,
            "client_count": 0,
            "chunk_count": 0,
            "node_agent": "Bravo %s" % bravo_version,
            "port": self.port,
            "name": self.name,
        })

        if self.private_key:
            url = urlunparse(("http", self.gateway,
                "/broadcast/%s/" % self.private_key, None, args, None))
        else:
            url = urlunparse(("http", self.gateway, "/broadcast/", None, args,
                None))
        d = getPage(url)
        d.addCallback(self.online)
        d.addErrback(self.error)

    def broadcasted(self):
        self.ready = True

    def online(self, response):
        log.msg("Successfully said hi")
        log.msg("Response: %s" % response)

        if response == "Ok":
            # We're in business!
            reactor.callLater(0, self.broadcasted)
        elif response.startswith("Ok"):
            # New keypair?
            try:
                okay, public, private = response.split(":")
                self.public_key = public
                self.private_key = private
                self.save_keys()
            except ValueError:
                pass

            reactor.callLater(0, self.broadcasted)

    def save_keys(self):
        pass

    def error(self, reason):
        log.err("Couldn't talk to gateway %s" % self.gateway)
        log.err(reason)
