import socket, sys
from time import sleep, time
from Queue import Queue

from Channel import Channel

# ew...
def getIP():
	s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	s.connect(('91.121.94.180', 80)) # doesn't matter if it fails
	addr = s.getsockname()[0] 
	s.close()
	return addr

class PdLANPoller(Channel):
	"""
		Broadcasts our IP address every two seconds.
		It's the poor GNU programmer's Bonjour! :)
		Also has the ability to broadcast arrays of Pd data, queued up with Post()
	"""
	def __init__(self, exitEvent, queue_type=Queue):
		self.queue = queue_type()
		Channel.__init__(self)
		self.exitEvent = exitEvent
		self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
		self.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
		self.set_reuse_addr()
		self.dest = ('255.255.255.255', 10314)
		self.connect(self.dest)
		
		# what IP address the server is listening on
		if len(sys.argv) == 2:
			self.addr = sys.argv[1]
		else:
			self.addr = getIP()
		print "Listening on", self.addr
		print "(You can specify this with an argument)"
	
	def Launch(self):
		# elapsed time
		last = 0
		
		try:
			while not self.exitEvent.is_set():
				# broadcast the server IP address every two seconds
				if last < time() - 2:
					#print 'broadcasting ip...'
					self.Send(["ip", self.addr])
					last = time()
				# if we have UDP messages queued, then send them too
				while not self.queue.empty():
					self.Send(self.queue.get())
				self.Pump()
				sleep(0.001)
		except KeyboardInterrupt:
			sys.exit(0)
	
	def handle_error(self):
		""" Bail on errors. """
		print "Exiting PdLANPoller loop because we can't send anything due to the following error:"
		self.exitEvent.set()
		Channel.handle_error(self)
	
	def Post(self, data):
		""" Broadcast this array to all clients on the LAN. """
		self.queue.put(data)

if __name__ == "__main__":
	print PdLANPoller.__doc__
	import threading
	if float(sys.version[:3]) < 2.5:
		from asyncore import poll2 as poll
	else:
		from asyncore import poll
	try:
		poller = PdLANPoller()
		poller.Post(["my", "first", "test"])
		threadSrv = threading.Thread(target=poller.Launch)
		threadSrv.start()
		start = time()
		while 1:
			poll()
			if start < time() - 2.5:
				poller.Post(["this", "is", "just", "a", "test"])
				start = time()
			sleep(0.01)
	except KeyboardInterrupt:
		sys.exit(0)


