File: src/internal/stream_collection.coffee
    
{Deferred} = require('./promise')
EventEmitter = require('events').EventEmitter
###*
# @module rtc.internal
###
###*
# Helper handling the mapping of streams for RemotePeer
# @class rtc.internal.StreamCollection
#
# @constructor
###
class exports.StreamCollection extends EventEmitter
  ###*
  # A new stream was added to the collection
  # @event steam_added
  # @param {String} name The user defined name of the stream
  # @param {Promise -> rtc.Stream} stream Promise to the stream
  ###
  constructor: () ->
    ###*
    # Contains the promises which will resolve to the streams
    # @property {Object} streams
    ###
    @streams = {}
    @_defers = {}
    @_waiting = {}
    @_pending = {}
    @wait_d = new Deferred()
    @wait_p = @wait_d.promise
  ###*
  # Set stream description and generate promises
  # @method update
  # @param data {Object} An object mapping the stream ids to stream names
  ###
  update: (data) ->
    members = []
    @_waiting = {}
    # remove old streams
    for name, stream_p in @streams
      if not data[name]?
        # remove
        delete @streams[name]
        @emit('stream_removed', name)
        # close/fail
        # TODO: this does not work anymore ...
        if stream_p.isFullfilled()
          stream_p.then (stream) ->
            stream.close()
        else if stream_p.isPending()
          stream_p.reject(new Error("Stream removed before being established"))
    # update mappings
    for name, id of data
      # does stream exist?
      if not @streams[name]?
        # create stream promise
        defer = new Deferred()
        @streams[name] = defer.promise
        @_defers[name] = defer
        @emit('stream_added', name, defer.promise)
      # do we adjust stream initialization?
      if @_defers[name]?
        if @_pending[id]?
          # got it!
          stream = @_pending[id]
          delete @_pending[id]
          @_defers[name].resolve(stream)
          delete @_defers[name]
        else
          # add waiting mapping
          @_waiting[id] = name
    @wait_d.resolve()
  ###*
  # Add stream to the collection and resolve promises waiting for it
  # @method resolve
  # @param {rtc.Stream} stream
  ###
  resolve: (stream) ->
    id = stream.id()
    # streams from Chrome to Firefox are coming in with id set to 'default' ...
    if id == 'default'
      if Object.keys(@streams).length == 1 and Object.keys(@_waiting).length == 1
        console.log("Working around incompatibility between Firefox and Chrome concerning stream identification")
        id = Object.keys(@_waiting)[0]
      else
        console.log("Unable to work around incompatibility between Firefox and Chrome concerning stream identification")
    if @_waiting[id]?
      # stream is expected
      name = @_waiting[id]
      delete @_waiting[id]
      @_defers[name].resolve(stream)
      delete @_defers[name]
    else
      # lets hope someone wants this later ...
      @_pending[id] = stream
  ###*
  # Gets a promise for a stream with the given name. Might be rejected after `update()`
  #
  # @method get
  # @param {String} name
  # @return {Promise} The promise for the `rtc.Stream`
  ###
  get: (name) ->
    @wait_p.then () =>
      if @streams[name]?
        return @streams[name]
      else
        throw new Error("Stream not offered")