from time import sleep
from sys import exit

# import something to manage multiple threads
try:
    from multiprocessing import Process as Thread, Queue, Event
except ImportError:
        try:
           from processing import Process as Thread, Queue, Event
        except ImportError:
            from threading import Thread, Event
            from Queue import Queue

# ridiculous hacking to get around different versions of threading/processing
# having slightly different interfaces.
e = Event().__class__
if not hasattr(e, "is_set"):
	e.is_set = e.isSet

from PdServer import PdServer
from PdChannel import PdChannel
from PdLANPoller import PdLANPoller
from PdUDPListener import PdUDPListener

class PdLANParty(PdServer):
	def __init__(self):
		"""
		Creates the lanparty server. Call the Launch() method to start it.
		Use GetMessages() and PostMessage(data) to send stuff to and from connected clients. 
		Use Exit() to shut down all server threads.
		"""
		# two way Pd style connection working
		# run server first
		# emulate ip address broadcast catcher = nc -lu 10314
		# emulate Pd listener = nc -l 192.168.2.113 10315
		# emulate Pd sender = nc localhost 10314 -s 192.168.2.113
		
		# Event to signal all threads to exit
		self.exitEvent = Event()
		# hack for different versions of processing/multiprocessing
		# launch a thread which broadcasts to all devices on the network every two seconds
		self.poller = PdLANPoller(self.exitEvent, Queue)
		self.threadSrv = Thread(target=self.poller.Launch)
		self.threadSrv.start()
		
		# start the UDP listener
		self.udplistener = PdUDPListener(self.exitEvent, Queue)
		self.threadUDP = Thread(target=self.udplistener.Launch)
		self.threadUDP.start()
		
		self.inQueue = Queue()
		self.outQueue = Queue()
	
	def Launch(self):
		threadSrv = Thread(target=self.ServerLoop)
		threadSrv.start()
	
	def ServerLoop(self):
		# set this up as the actual two way server
		PdServer.__init__(self, queue_type=Queue, channelClass=PdChannel, localaddr=("0.0.0.0", 10314), listeners=50)
		try:
			while not self.exitEvent.is_set():
				self.Pump()
				sleep(0.001)
		except KeyboardInterrupt:
			exit(0)
	
	def Exit(self):
		""" Make PdLANParty threads exit. This will block until they are done. """
		self.exitEvent.set()
		self.threadSrv.join()
		self.threadUDP.join()
	
	def PostUDPMessage(self, data):
		""" Send a broadcast UDP message to all connected clients. 'data' should be an array. """
		self.poller.Post(data)
	
	def GetUDPMessages(self):
		""" Get all of the UDP messages from all connected clients. """
		return self.udplistener.GetMessages()


