# twisted imports
from twisted.words.protocols import irc
from twisted.internet import reactor, protocol
from twisted.python import log


# system imports
import time, sys

#other
import json

class MessageLogger:
	"""
	An independent logger class (because separation of application
	and protocol logic is a good thing).
	"""
	def __init__(self, file):
		self.file = file

	def log(self, message):
		"""Write a message to the file."""
		timestamp = time.strftime("[%H:%M:%S]", time.localtime(time.time()))
		self.file.write('%s %s\n' % (timestamp, message))
		self.file.flush()

	def close(self):
		self.file.close()




class Bot(irc.IRCClient):
	"""A logging IRC bot."""
	
	nickname = "virus"
	infectedChannels = list()
	chanInfo = dict()

	def connectionMade(self):
		irc.IRCClient.connectionMade(self)
		self.logger = MessageLogger(open(self.factory.filename, "a"))
		self.logger.log("[connected at %s]" % 
						time.asctime(time.localtime(time.time())))
						
	def connectionLost(self, reason):
		irc.IRCClient.connectionLost(self, reason)
		self.logger.log("[disconnected at %s]" % 
						time.asctime(time.localtime(time.time())))
		self.logger.close()


	# callbacks for events

	def signedOn(self):
		"""Called when bot has succesfully signed on to server."""
		self.join(self.factory.rootChannel)

	def joined(self, channel):
		"""This will get called when the bot joins the channel."""
		self.logger.log("[I have joined %s]" % channel)
		print("joined %s" % channel)

	def privmsg(self, user, channel, msg):
		"""This will get called when the bot receives a message."""
		user = user.split('!', 1)[0]
		self.logger.log("<%s> %s" % (user, msg))
		args = msg.split( )
		
		for substring in args:
			if substring.startswith('#') and substring.find(',') == -1:
				print("Hitting WHO send")
				self.sendLine("WHO %s" % substring)



		# Check to see if they're sending me a private message
		if channel == self.nickname:
			msg = "It isn't nice to whisper!  Play nice with the group."
			self.msg(user, msg)
			return

		# Otherwise check to see if it is a message directed at me
		if msg.startswith(self.nickname + ":"):
			msg = "%s: Infected channels; %s" % (user, '\n'.join(self.infectedChannels))
			self.msg(channel, msg)
			self.logger.log("<%s> %s" % (self.nickname, msg))

	def action(self, user, channel, msg):
		"""This will get called when the bot sees someone do an action."""
		user = user.split('!', 1)[0]
		self.logger.log("* %s %s" % (user, msg))

	# irc callbacks

	def irc_RPL_WHOREPLY(self, prefix, params):
		print("Got who reply: %s" % ', '.join(params))
		if params[0].lower() not in self.infectedChannels:
			self.join(params[0])
			self.infectedChannels.append(params[0].lower())
			print("Added %s to infected" % params[0].lower())


	def irc_NICK(self, prefix, params):
		"""Called when an IRC user changes their nickname."""
		old_nick = prefix.split('!')[0]
		new_nick = params[0]
		self.logger.log("%s is now known as %s" % (old_nick, new_nick))


	# For fun, override the method that determines how a nickname is changed on
	# collisions. The default method appends an underscore.
	def alterCollidedNick(self, nickname):
		"""
		Generate an altered version of a nickname that caused a collision in an
		effort to create an unused related name for subsequent registration.
		"""
		return nickname + '^'



class BotFactory(protocol.ClientFactory):
	"""A factory for Bots.

	A new protocol instance will be created each time we connect to the server.
	"""

	def __init__(self):
		self.rootChannel = "#jacoders" #The channel to always join.
		self.filename = "session.txt"
	def buildProtocol(self, addr):
		p = Bot()
		p.factory = self
		return p

	def clientConnectionLost(self, connector, reason):
		"""If we get disconnected, reconnect to server."""
		connector.connect()

	def clientConnectionFailed(self, connector, reason):
		print "connection failed:", reason
		reactor.stop()


if __name__ == '__main__':
	# initialize logging
	log.startLogging(sys.stdout)
	
	# create factory protocol and application
	f = BotFactory()

	# connect factory to this host and port
	reactor.connectTCP("irc.arloria.net", 6667, f)

	# run bot
	reactor.run()