#!/usr/bin/env python
"""
santa.py
"""
import random

import time
import sys

from twisted.internet                                 import reactor
from twisted.internet                                 import defer
from twisted.internet                                 import task
from twisted.python.failure                           import Failure

import stackless

RTIME = (6,12)
ETIME = (1,12)

class TwistedException(Exception):
    def __init__(self, failure):
        super(TwistedException, self).__init__()
        self.failure = failure
        return


def tick(seconds):
    tickCh = stackless.channel()
    reactor.callLater(seconds, tickCh.send, None)
    tickCh.receive()


def startTwisted():
    reactor.run()


def stopTwisted():
    reactor.callLater(1, reactor.stop)
    print "that's all folks"


def worker(ch, name, theRange):
    myChannel = stackless.channel()
    while True:
       waitTime = random.randint(theRange[0], theRange[1])
       print name,"starting", waitTime
       tick(waitTime)
       print name," done"
       ch.send((name, myChannel))
       answer = myChannel.receive()
       print name, answer


def santa(reindeer, elves):
    print "I GOT HERE"
    reindeerReady = elvesReady = False
    reindeerChannels = [ch for name, ch, waitTime in reindeer]
    elvesChannels = [ch for name, ch, waitTime in elves]
    reindeerCases = [ch.receives() for ch in reindeerChannels]
    elvesCases = [ch.receives() for ch in elvesChannels]
    reindeerQueue = []
    elvesQueue = []

    cases = reindeerCases + elvesCases

    print cases
    print "I AM READY TO ROLL"
    start = time.time()
    while not reindeerReady:
        ch, operation, value = stackless.select(cases)
        if ch in reindeerChannels: 
           reindeerQueue.append(value)
           if len(reindeerQueue) == 9:
              reindeerReady = True
              print "ALL REINDEER ACCOUNTED FOR"
              continue 
        elif ch in elvesChannels:
           elvesQueue.append(value)
           if len(elvesQueue) == 3:
              elvesReady = True
              print "ALL ELVES ACCOUNTED FOR"
              continue 

    print "ALL REINDEER ACCOUNTED FOR"
    finish = time.time() - start
    print "time: ", finish
    stopTwisted()
    print "Twisted is dead"


def makeWorkers(workers):
    for name, ch, waitTime in workers:
        stackless.tasklet(worker)(ch, name, waitTime)
    return 


if __name__ == "__main__":
   random.seed()
   reindeers = [(reindeer, stackless.channel(), RTIME) for reindeer in \
               ["DANCER", "PRANCER", "VIXEN", "COMET", "CUPID", "DONER", \
                "DASHER", "BLITZEN", "RUDOLPH"]]

   elves = [(elf, stackless.channel(), ETIME) for elf in \
            ['A','B','C','D','E','F','G','H','I','J']]

    
   makeWorkers(reindeers)
   makeWorkers(elves)

   print "STARTING MAIN"

   l = task.LoopingCall(stackless.schedule)
   l.start(.001)
   print "twisted: ", stackless.tasklet(startTwisted)()
   stackless.tasklet(santa)(reindeers, elves)
   stackless.run()
