import errno
import select
import socket
import time

reading = {}
writing = {}
excepting = {}
timer_queue = []
signal_queue = []
trailing = []
quit = 0

def log(s):
    f = open('event.log', 'a')
    f.write(s)
    f.close()

def run():
    while not quit:
	try:
	    while signal_queue:
		signal_queue[0]()
		del signal_queue[0]
	    if timer_queue:
		rs, ws, exs = select.select(
		    reading.keys(), writing.keys(), excepting.keys(),
		    max(0.0, timer_queue[0][0] - time.time()))
	    else:
		rs, ws, exs = select.select(
		    reading.keys(), writing.keys(), excepting.keys())
	    for r in rs:
		reading[r](r)
	    if not rs:
		for w in ws:
		    if writing.has_key(w):
			writing[w](w)
		if not ws:
		    for ex in exs:
			if excepting.has_key(ex):
			    excepting[ex](ex)
		    if not exs:
			t = time.time()
			while timer_queue and timer_queue[0][0] <= t:
			    timer_queue[0][1]()
			    del timer_queue[0]
            for fn in trailing:
                fn()
	except select.error, (err, err_string):
	    if err == errno.EINTR:
		pass
	    else:
		raise

def timer_set(at, fn):
    i = 0
    while i < len(timer_queue):
	if timer_queue[i][0] > at:
	    timer_queue.insert(i, (at, fn))
	    return
	i = i + 1
    timer_queue.append((at, fn))

class SingleTimer:
    def __init__(self, delay):
	timer_set(time.time() + delay, self.run)

    def run(self):
	## override this when subclassing
	pass

class RepeatingTimer:
    def __init__(self, interval, first_interval = None):
	if first_interval == None:
	    first_interval = interval
	self.next = time.time() + first_interval
	self.interval = interval
	timer_set(self.next, self.run_and_set)

    def run_and_set(self):
	self.next = self.next + self.interval
	self.run()
	timer_set(self.next, self.run_and_set)

    def run(self):
	## override this when subclassing
	pass

class ServerSocket:
    def __init__(self, host = '', port = 0):
	self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	self.sock.bind(host, port)
	self.sock.listen(5)
	reading[self.sock] = self.read_ready

    def read_ready(self, sock):
	data_sock = self.sock.accept()
	make_data_sock(data_sock)

    def make_data_sock(self, data_sock):
	## override this when subclassing
	data_sock.close()

class DataSocket:
    def __init__(self, sock = None):
	if sock:
	    self.sock = sock
	else:
	    self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	self.sock.setblocking(0)
	self.write_queue = []
        self.in_size = 4096

    def connect(self, address):
	err = self.sock.connect_ex(address)
	if err == errno.EINPROGRESS:
	    writing[self.sock] = self.connected
	elif not err:
	    self.connected(self.sock)
	else:
	    pass # problems?

    def connected(self, sock):
	## override this when subclassing
	del writing[self.sock]

    def read(self):
	reading[self.sock] = self.read_ready

    def read_ready(self, sock):
	try:
	    data = self.sock.recv(self.in_size)
	    if not data:
		self.disconnected()
	    else:
		self.received(data)
	except socket.error, (err, err_string):
	    if err == errno.EINTR:
		pass
	    elif err == errno.EAGAIN:
		pass
	    elif err == errno.EPIPE:
		self.broken_pipe_read()
	    elif err == errno.ECONNREFUSED:
		self.connection_refused()
	    elif err == errno.ECONNRESET:
		self.connection_reset()
	    else:
		raise

    def broken_pipe_read(self):
	## may be overridden when subclassing
	self.broken_pipe()

    def received(self, data):
	## override this when subclassing
	pass

    def connection_refused(self):
	## may be overridden when subclassing
	self.disconnected()

    def connection_reset(self):
	## may be overridden when subclassing
	self.disconnected()

    def disconnected(self):
	## override this when subclassing
	self.sock.close()

    def write(self, data):
	self.write_queue.append(data)
	writing[self.sock] = self.write_ready

    def write_ready(self, sock):
	try:
	    data = self.write_queue[0]
	    length = self.sock.send(data)
	    if length == len(data):
		del self.write_queue[0]
	    else:
		self.write_queue[0] = data[length:]
	    if not self.write_queue:
		del writing[self.sock]
	except socket.error, (err, err_string):
	    if err == errno.EINTR:
		pass
	    elif err == errno.EPIPE:
		self.broken_pipe_write()
	    else:
		raise

    def broken_pipe_write(self):
	## may be overridden when subclassing
	self.broken_pipe()

    def broken_pipe(self):
	## override this when subclassing
	if reading.has_key(self.sock):
	    del reading[self.sock]
	if writing.has_key(self.sock):
	    del writing[self.sock]
	self.sock.close()

class UDPSocket:
    def __init__(self):
	self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	self.sock.setblocking(0)
	self.write_queue = []

    def recvfrom(self, size, flags = 0):
	self.size = size
	self.flags = flags
	reading[self.sock] = self.read_ready

    def read_ready(self, sock):
	data, address = self.sock.recvfrom(self.size, self.flags)
	self.received(data, address)

    def received(self, data, address):
	## override this when subclassing
	pass

    def sendto(self, data, flags, address):
	self.write_queue.append((data, flags, address))
	writing[self.sock] = self.write_ready

    def write_ready(self, sock):
	data, flags, address = self.write_queue[0]
	self.sock.sendto(data, flags, address)
	del self.write_queue[0]
	if not self.write_queue:
	    del writing[self.sock]

## End. ##
