 ###
 class TinyRaveScheduler
   @createBlock: (duration, methods) ->
+    if arguments.length != 2
+      throw new Error "Must specify a duration and block methods for createBlock()"
     { duration: duration, methods: methods }
 
   constructor: ->

TinyRave.setBPM = (bpm) ->
  TinyRave.BPM = bpm

TinyRave.setInterval = (callback, delay) ->
  TinyRave.scheduler.registerCallback(callback, delay, TinyRave.scheduler.getTime(), true)

TinyRave.setTimeout = (callback, delay) ->
  TinyRave.scheduler.registerCallback(callback, delay, TinyRave.scheduler.getTime(), false)

TinyRave.clearInterval = (id) ->
  # This can work for setTimeout calls, too, unlike native setTimeout.
  TinyRave.scheduler.unregisterCallback(id)
  undefined


  push: (blocks...) ->
    for block in blocks
      console.warn "Push all blocks before the first call to buildSample. (Feel free to email me if you need this fixed. - Eddie)" if @time > 0
      delay = @getBlockQueueLength()
      @blocks.push(block)
      setTimeout((=> @shiftBlock()), delay)

  shiftBlock: ->
    block = @blocks.shift()
    console.error "In shiftBlock(). No block left to shift." unless block?
    blockScope = new TopLevelScope block.duration
    block.methods.run.apply(blockScope)


# All timer DSL functions (every, until, after) are called with an instance of
# TopLevelScope or ShadowScope as `this.` Initially, we create a TopLevelScope
# with an expiration set to now() + delay. Any calls to setInterval / setTimeout
# from inside the functions will be cleared at the expiration time. The special
# case is `until`, which executes its callback in a new instance of
# ShadowScope, which is chained to the parent scope (an instance of
# TopLevelScope or ShadowScope [since `until` calls can be nested]).
#
# Doing this gets us two things:
#
# 1) An `expiration` shadow variable. When the timer methods run in an instance
#    of ShadowScope, they will reference the most-local, shadow copy of
#    @expiration. This allows us to adjust the block expiration deeper in nested
#    calls.
#
# 2) A version of `this` that will still resolve instance variables. If you
#    define any variables in blockWillRun they are accessible in timer callbacks
#    This is really handy, since you can establish your state at the start of
#    the run, modify it in the timer methods, and reference it when actually
#    pushing new instruments on to the GlobalMixer.

class TopLevelScope
  constructor: (delay) ->
    @expiration = TinyRave.scheduler.getTime() + delay

  every: (delay, callback) ->
    @until(delay, callback)
    @withExpiration(
      setInterval((=> @until(delay, callback)), delay)
    )

  after: (delay, callback) ->
    @withExpiration(
      setTimeout((=> callback.apply(@)), delay)
    )

  until: (delay, callback) ->
    newScope = @createUntilScope(delay)
    callback.apply(newScope)

  withExpiration: (id) ->
    setTimeout((=> clearInterval(id)), @expiration - TinyRave.scheduler.getTime())

  createUntilScope: (delay) ->
    # Delay cannot exceed parent (existing) scope expiration
    expiration = Math.min(TinyRave.scheduler.getTime() + delay, @expiration)
    # The new scope creates a shadow var expiration, so timer functions will
    # see the local scope's value and behave apporopriately in nested calls
    ShadowScope.prototype = @
    new ShadowScope(expiration)

# For expiration shadow variable
class ShadowScope
  constructor: (@expiration) ->


#
# TinyRave Object
