# This software was originally developed as a part of a project paid for by
# UNINETT, Norway.

import select, time

class message:
   pass

RemoveStream = message()

class ircmultiplexer:
   def __init__(self):
      self.streams = {}
      self.w_streams = {}
      self.pending_actions = []
   def register(self, stream, handler):
      self.streams[stream] = handler
   def w_register(self, stream, handler):
      self.w_streams[stream] = handler
   def p_register(self, action):
      self.pending_actions.append(action)
   def remove(self, stream):
      del self.streams[stream]
   def w_remove(self, stream):
      del self.w_streams[stream]
   def mainloop(self):
      while 1:
         w_items = self.w_streams.items()
         w_streams = []
         for stream, handler in w_items:
            if handler.queuelen():
               w_streams.append(stream)
         if self.pending_actions:
            readystreams = select.select(self.streams.keys(),
               w_streams, [], .5)
         else:
            readystreams = select.select(self.streams.keys(),
               w_streams, [])

         for stream in readystreams[0]:
            result = self.streams[stream]()
            if result == RemoveStream:
               self.remove(stream)
               if stream in self.w_streams.keys():
                  self.w_remove(stream)
         for stream in readystreams[1]:
            try:
               result = self.w_streams[stream]()
            except KeyError:
               # The stream may have been deregistered in the previous
               # step
               continue
            if result == RemoveStream:
               self.w_remove(stream)
               if stream in self.streams.keys():
                  self.remove(stream)

         now = time.time()
         removeactions = [] # Has to make activating new
                            # actions while looping vaguely sane
         for action in self.pending_actions[:]:
            if now >= action.time:
               newtimeout = action()
               if newtimeout:
                  action.time = newtimeout
                  self.p_register(action)
               removeactions.append(action)
         for action in removeactions:
            # Note: This allows for actions to reinsert themselves
            # when being called above.
            self.pending_actions.remove(action)
