import collections

from eventlet import api, greenlib

import greenlet

__all__ = ['channel']

class channel(object):
    balance = 0

    def _tasklet_loop(self):
        deque = self.deque = collections.deque()
        hub = api.get_hub()
        switch = greenlib.switch
        direction, caller, args = switch()
        try:
            while True:
                if direction == -1:
                    # waiting to receive
                    if self.balance > 0:
                        sender, args = deque.popleft()
                        hub.schedule_call(0, switch, sender)
                        hub.schedule_call(0, switch, caller, *args)
                    else:
                        deque.append(caller)
                else:
                    # waiting to send
                    if self.balance < 0:
                        receiver = deque.popleft()
                        hub.schedule_call(0, switch, receiver, *args)
                        hub.schedule_call(0, switch, caller)
                    else:
                        deque.append((caller, args))
                self.balance += direction
                direction, caller, args = hub.switch()
        finally:
            deque.clear()
            del self.deque
            self.balance = 0

    def _send_tasklet(self, *args):
        try:
            t = self._tasklet
        except AttributeError:
            t = self._tasklet = greenlib.tracked_greenlet()
            greenlib.switch(t, (self._tasklet_loop,))
        if args:
            return greenlib.switch(t, (1, greenlet.getcurrent(), args))
        else:
            return greenlib.switch(t, (-1, greenlet.getcurrent(), args))
        
    def receive(self):
        return self._send_tasklet()

    def send(self, value):
        return self._send_tasklet(value)

    def send_exception(self, exc):
        return self._send_tasklet(None, exc)
