 Fiber = Npm.require 'fibers'
 
-SyncToken = new Mongo.Collection 'meteor.SyncToken'
+SYNC_TOKEN_ID = 'syncToken'
+LAST_UPDATED_ID = 'lastUpdated'
+
+SyncState = new Mongo.Collection 'meteor.SyncState'
+
 Packages = new Mongo.Collection 'meteor.Packages'
 Versions = new Mongo.Collection 'meteor.Versions'
 Builds = new Mongo.Collection 'meteor.Builds'

    console.log "ReleaseTracks - all: #{ReleaseTracks.find().count()}, new: #{newReleaseTracks}, updated: #{updatedReleaseTracks}" if newReleaseTracks or updatedReleaseTracks
    console.log "ReleaseVersions - all: #{ReleaseVersions.find().count()}, new: #{newReleaseVersions}, updated: #{updatedReleaseVersions}" if newReleaseVersions or updatedReleaseVersions

    SyncToken.update
      _id: 'syncToken'
    ,
      $set:
        syncToken: result.syncToken

  # TODO: Slight race condition here. There might be another document inserted between removal and this insertion.
  LatestPackages.insert document

latestPackagesObserve = ->
  console.log "Starting latest packages observe"

  try
    # We try to create the initial document.
    SyncState.insert
      _id: LAST_UPDATED_ID
      lastUpdated: null
  catch error
    throw error unless /E11000 duplicate key error index:.*SyncState\.\$_id/.test error.err

  timeoutHandle = null
  newestLastUpdated = null

  # Update sync state after 30 seconds of no updates. This assures that if there was a series of observe
  # callbacks called, we really processed them all. Otherwise we might set state but program might
  # terminate before we had a chance to process all observe callbacks. Which will mean that those
  # packages from pending observe callbacks will not be processed the next time the program runs.
  updateSyncState = (newLastUpdated) ->
    # We allow that in a series of observe callbacks the order of last updated timestamps is
    # not monotonic. In the case that last updated timestamps are not monotonic between
    # series of observe callbacks, we will have to (and do) restart the observe.
    if not newestLastUpdated or newestLastUpdated < newLastUpdated
      newestLastUpdated = newLastUpdated

    Meteor.clearTimeout timeoutHandle
    timeoutHandle = Meteor.setTimeout ->
      lastUpdated = newestLastUpdated
      newestLastUpdated = null

      SyncState.update
        _id: LAST_UPDATED_ID
      ,
        $set:
          lastUpdated: lastUpdated
    ,
      30 * 1000 # ms

  observeHandle = null
  currentLastUpdated = null

  startObserve = ->
    observeHandle?.stop()
    observeHandle = null


    if currentLastUpdated
      query =
        lastUpdated:
          $gte: currentLastUpdated
    else
      query = {}

    observeHandle = Versions.find(query).observeChanges
      added: (id, fields) ->
        insertLatestPackage _.extend {_id: id}, fields

        updateSyncState fields.lastUpdated.valueOf()

      changed: (id, fields) ->
        # Will possibly not update anything, if the change is for an older package.
        LatestPackages.update id, fieldsToModifier fields

        updateSyncState fields.lastUpdated.valueOf() if 'lastUpdated' of fields

      removed: (id) ->
        oldPackage = LatestPackages.findOne id

