from twisted.internet import reactor
from twisted.internet.protocol import ReconnectingClientFactory
from twisted.application.internet import TCPClient
from twisted.application.service import Application, MultiService
from twisted.words.xish.domish import Element
from twisted.words.protocols.jabber import jid
from twisted.words.protocols.jabber.client import basicClientFactory
from twisted.words.protocols.irc import IRCClient


class JabberRelay(object):
    def __init__(self, bridge):
        self.bridge = bridge
        self.xmlstream = None

        self.myJid = jid.JID('triumph@slipgate.za.net/triumph')
        factory = basicClientFactory(self.myJid, 'CENSORED')
        factory.addBootstrap('//event/stream/authd', self.authed)
        self.service = TCPClient('chthon.slipgate.za.net', 5222, factory)

    def authed(self, xmlstream):
        self.xmlstream = xmlstream

        presence = Element(('jabber:client', 'presence'))
        xmlstream.send(presence)

        xmlstream.addObserver('/message',  self.handleJabberMessage)
        #xmlstream.addObserver('/presence', self.debug)
        xmlstream.addObserver('/iq',       self.debug)

    def sendMessage(self, message):
        if self.xmlstream is None:
            return

        elem = Element((None, 'message'))
        elem['type'] = u'chat'
        elem['from'] = unicode(self.myJid)
        elem['to'] = u'triumvirate.conf@gmail.com'
        elem.addElement('body', content=message)
        self.xmlstream.send(elem)

    def handleJabberMessage(self, elem):
        user, host, resource = jid.parse(elem['from'])
        if (user, host) != (u'triumvirate.conf', u'gmail.com'):
            return

        message = elem.body.children[0]
        self.bridge.irc.sendMessage(message)

    def debug(self, elem):
        print elem.toXml().encode('utf-8')
        print "="*20


class IRCRelayProtocol(IRCClient):
    nickname = 'triumph'

    def connectionMade(self):
        IRCClient.connectionMade(self)
        self.factory.relay.proto = self

    def connectionLost(self, reason):
        IRCClient.connectionLost(self, reason)
        self.factory.relay.proto = None

    def signedOn(self):
        self.join(self.factory.channel)

    def privmsg(self, user, channel, msg):
        if channel != self.factory.channel:
            return
        nick = unicode(user.split('!', 1)[0], 'ascii')
        msg = unicode(msg, 'utf-8')
        self.factory.relay.receivedMessage(u'<%s> %s' % (nick, msg))

    def action(self, user, channel, msg):
        if channel != self.factory.channel:
            return
        nick = unicode(user.split('!', 1)[0], 'ascii')
        msg = unicode(msg, 'utf-8')
        self.factory.relay.receivedMessage(u'* %s %s' % (nick, msg))

    def sendMessage(self, message):
        self.msg(self.factory.channel, message)


class IRCFactory(ReconnectingClientFactory):
    protocol = IRCRelayProtocol
    channel = '#triumvirate'

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


class IRCRelay(object):
    def __init__(self, bridge):
        self.bridge = bridge
        factory = IRCFactory(self)
        self.service = TCPClient('shikari.shadowfire.org', 6667, factory)
        self.proto = None

    def sendMessage(self, message):
        if self.proto is not None:
            for line in message.splitlines():
                self.proto.sendMessage(line.encode('utf-8', 'replace'))

    def receivedMessage(self, message):
        self.bridge.jabber.sendMessage(message)


class Bridge(object):
    def __init__(self):
        self.jabber = JabberRelay(self)
        self.irc = IRCRelay(self)

        self.service = MultiService()
        self.jabber.service.setServiceParent(self.service)
        self.irc.service.setServiceParent(self.service)


application = Application('triumph')
b = Bridge()
b.service.setServiceParent(application)
