<commit_before>class CollaborativeWorkspace extends Workspace

  init: ->
    {createUserList, enableChat} = @getOptions()
    @nickname    = KD.nick()
    @sessionData = []
    @users       = {}
    @activeUsers = {}
    @createRemoteInstance()
    @createLoader()
    @fetchUsers()
    @createUserListContainer()  if createUserList
    @createChat()               if enableChat
    @bindRemoteEvents()

  createChat: ->
    chatPaneClass = @getOptions().chatPaneClass or ChatPane
    @container.addSubView @chatView = new chatPaneClass
      delegate  : this
      itemClass : TeamworkChatItem

    @chatView.hide()

  createRemoteInstance: ->
    instanceName  = @getOptions().firebaseInstance

    unless instanceName
      return warn "CollaborativeWorkspace requires a Firebase instance."

    @firebaseRef    = new Firebase "https://#{instanceName}.firebaseio.com/"
    @sessionKey     = @getOptions().sessionKey or @createSessionKey()
    @workspaceRef   = @firebaseRef.child @sessionKey
    @broadcastRef   = @workspaceRef.child "broadcast"
    @historyRef     = @workspaceRef.child "history"
    @chatRef        = @workspaceRef.child "chat"
    @usersRef       = @workspaceRef.child "users"
    @userRef        = @usersRef.child KD.nick()
    @requestPingRef = @workspaceRef.child "requestPing"
    @sessionKeysRef = @firebaseRef.child  "session_keys"

  syncWorkspace: ->
    @workspaceRef.once "value", (snapshot) =>
      if @getOptions().sessionKey
        unless snapshot.val()?.keys
          @showNotActiveView()
          return false

      isOldSession = keys = snapshot.val()?.keys
      if isOldSession
        @isOldSession = yes
        @sessionData  = keys
        @createPanel()
      else
        @createPanel()
        @workspaceRef.set "keys": @sessionData

      if not isOldSession
        @addToHistory { message: "$0 started the session", by: KD.nick() }

      @sessionKeysRef.child(@nickname).set @sessionKey
      @userRef.child("status").set "online"

      @loader.destroy()
      @chatView?.show()

      @emit "WorkspaceSyncedWithRemote"

  bindRemoteEvents: ->
    if @amIHost() then @syncWorkspace() else @requestPingFromHost()

    @usersRef.on "child_added", (snapshot) =>
      @fetchUsers()

      username = snapshot.name()
      return if username is @nickname

      @usersRef.child(username).child("status").on "value", (snapshot) =>
        status = snapshot.val()
        if status is "online"
          @once "WorkspaceUsersFetched", =>
            @activeUsers[username] = @users[username]

          @emit "SomeoneJoinedToTheSession", username
          @setPresenceHandler()  unless @presenceInterval
          if @amIHost()
            message = "#{username} joined the session"
            @addToHistory { message, by: KD.nick() }
        else if status is "offline"
          delete @activeUsers[username]
          if Object.keys(@activeUsers).length is 0 and @amIHost()
            @killPresenceTimer()
          @emit "SomeoneHasLeftTheSession", username
          if @amIHost()
            message = "#{username} has left the session"
            @addToHistory { message, by: KD.nick() }

    @broadcastRef.on "value", (snapshot) =>
      message = snapshot.val()
      return if not message or not message.data or message.data.sender is @nickname
      @displayBroadcastMessage message.data

    @on "AllPanesAddedToPanel", (panel, panes) ->
      paneSessionKeys = []
      paneSessionKeys.push pane.sessionKey for pane in panes
      @sessionData.push paneSessionKeys

    @on "KDObjectWillBeDestroyed", =>
      @forceDisconnect()
      events = [ "value", "child_added", "child_removed", "child_changed" ]
      @workspaceRef.off eventName for eventName in events

    @userRef.child("status").onDisconnect().set "offline"

    @requestPingRef.on "value", (snapshot) =>
      return unless @amIHost()
      @userRef.child("timestamp").set Date.now()

    @usersRef.child(@getHost()).child("timestamp").on "value", (snapshot) =>
      return if @amIHost() or @connected or snapshot.val() is null

      if Date.now() - snapshot.val() > 20000
        return @pingHostTimer = KD.utils.wait 10000, =>
          @showNotActiveView()

      @syncWorkspace()
      @connected = yes
      KD.utils.killWait @pingHostTimer

  requestPingFromHost: ->
    @requestPingRef.set Date.now()

  fetchUsers: ->
    @workspaceRef.once "value", (snapshot) =>
      val = snapshot.val()
      return  unless val

      usernames = []
      usernames.push username for own username, status of val.users unless @users[username]

      # TODO: Each time we are fetching user data that we already have. Needs to be fixed.
      KD.remote.api.JAccount.some { "profile.nickname": { "$in": usernames } }, {}, (err, jAccounts) =>
        for user in jAccounts
          {nickname} = user.profile
          @users[nickname] = user
        @emit "WorkspaceUsersFetched"

  createPanel: (callback = noop) ->
    panelOptions             = @getOptions().panels[@lastCreatedPanelIndex]
    panelOptions.delegate    = @
    panelOptions.sessionKeys = @sessionData[@lastCreatedPanelIndex]  if @sessionData<commit_msg>CollaborativeWorkspace: Introduced onlineCountRef.<commit_after>class CollaborativeWorkspace extends Workspace

  init: ->
    {createUserList, enableChat} = @getOptions()
    @nickname    = KD.nick()
    @sessionData = []
    @users       = {}
    @activeUsers = {}
    @createRemoteInstance()
    @createLoader()
    @fetchUsers()
    @createUserListContainer()  if createUserList
    @createChat()               if enableChat
    @bindRemoteEvents()

  createChat: ->
    chatPaneClass = @getOptions().chatPaneClass or ChatPane
    @container.addSubView @chatView = new chatPaneClass
      delegate  : this
      itemClass : TeamworkChatItem

    @chatView.hide()

  createRemoteInstance: ->
    instanceName  = @getOptions().firebaseInstance

    unless instanceName
      return warn "CollaborativeWorkspace requires a Firebase instance."

    @firebaseRef    = new Firebase "https://#{instanceName}.firebaseio.com/"
    @sessionKey     = @getOptions().sessionKey or @createSessionKey()
    @workspaceRef   = @firebaseRef.child @sessionKey
    @broadcastRef   = @workspaceRef.child "broadcast"
    @historyRef     = @workspaceRef.child "history"
    @chatRef        = @workspaceRef.child "chat"
    @usersRef       = @workspaceRef.child "users"
    @userRef        = @usersRef.child KD.nick()
    @requestPingRef = @workspaceRef.child "requestPing"
    @onlineCountRef = @workspaceRef.child "onlineUserCount"
    @sessionKeysRef = @firebaseRef.child  "session_keys"

  syncWorkspace: ->
    @workspaceRef.once "value", (snapshot) =>
      if @getOptions().sessionKey
        unless snapshot.val()?.keys
          @showNotActiveView()
          return false

      isOldSession = keys = snapshot.val()?.keys
      if isOldSession
        @isOldSession = yes
        @sessionData  = keys
        @createPanel()
      else
        @createPanel()
        @workspaceRef.set "keys": @sessionData

      if not isOldSession
        @addToHistory { message: "$0 started the session", by: KD.nick() }

      @sessionKeysRef.child(@nickname).set @sessionKey
      @userRef.child("status").set "online"

      @loader.destroy()
      @chatView?.show()

      @emit "WorkspaceSyncedWithRemote"

  bindRemoteEvents: ->
    if @amIHost() then @syncWorkspace() else @requestPingFromHost()

    @usersRef.on "child_added", (snapshot) =>
      @fetchUsers()

      username = snapshot.name()
      return if username is @nickname

      @usersRef.child(username).child("status").on "value", (snapshot) =>
        status = snapshot.val()
        if status is "online"
          @once "WorkspaceUsersFetched", =>
            @activeUsers[username] = @users[username]

          @emit "SomeoneJoinedToTheSession", username
          @setPresenceHandler()  unless @presenceInterval
          if @amIHost()
            message = "#{username} joined the session"
            @addToHistory { message, by: KD.nick() }
        else if status is "offline"
          delete @activeUsers[username]
          if Object.keys(@activeUsers).length is 0 and @amIHost()
            @killPresenceTimer()
          @emit "SomeoneHasLeftTheSession", username
          if @amIHost()
            message = "#{username} has left the session"
            @addToHistory { message, by: KD.nick() }

    @broadcastRef.on "value", (snapshot) =>
      message = snapshot.val()
      return if not message or not message.data or message.data.sender is @nickname
      @displayBroadcastMessage message.data

    @on "AllPanesAddedToPanel", (panel, panes) ->
      paneSessionKeys = []
      paneSessionKeys.push pane.sessionKey for pane in panes
      @sessionData.push paneSessionKeys

    @on "KDObjectWillBeDestroyed", =>
      @forceDisconnect()
      events = [ "value", "child_added", "child_removed", "child_changed" ]
      @workspaceRef.off eventName for eventName in events

    @userRef.child("status").onDisconnect().set "offline"

    @requestPingRef.on "value", (snapshot) =>
      return unless @amIHost()
      @userRef.child("timestamp").set Date.now()

    @usersRef.child(@getHost()).child("timestamp").on "value", (snapshot) =>
      return if @amIHost() or @connected or snapshot.val() is null

      if Date.now() - snapshot.val() > 20000
        return @pingHostTimer = KD.utils.wait 10000, =>
          @showNotActiveView()

      @syncWorkspace()
      @connected = yes
      KD.utils.killWait @pingHostTimer

    @usersRef.on "value", (snapshot) =>
      data   = snapshot.val()
      return unless data
      count  = 0
      count++ for username, state of data when state.status is "online"
      @onlineCountRef.set count

  requestPingFromHost: ->
    @requestPingRef.set Date.now()

  fetchUsers: ->
    @workspaceRef.once "value", (snapshot) =>
      val = snapshot.val()
      return  unless val

      usernames = []
      usernames.push username for own username, status of val.users unless @users[username]

      # TODO: Each time we are fetching user data that we already have. Needs to be fixed.
      KD.remote.api.JAccount.some { "profile.nickname": { "$in": usernames } }, {}, (err, jAccounts) =>
        for user in jAccounts
          {nickname} = user.profile
          @users[nickname] = user
        @emit "WorkspaceUsersFetched"

  createPanel: (callback = noop) ->
    panelOptions             = @getOptions().panels[@lastCreatedPanelIndex]
    panelOptions.delegate    = @
    panelOptions.sessionKeys = @sessionData[@lastCreatedPanelIndex]  if @sessionData
{'fraction_non_alphanumeric': 0.11682683248539665, 'fraction_numerical': 0.0023553796872055775, 'mean_word_length': 2.7964949928469243, 'pattern_counts': {'":': 6, '<': 3, '<?xml version=': 0, '>': 46, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '414898', 'n_tokens_mistral': 3130, 'n_tokens_neox': 3056, 'n_words': 724}