         params: @params
 
 class Lobby
-    constructor: (player) ->
-        @players = [player]
+    constructor: (p1, p2, match) ->
+        @players = [p1, p2]
+        p1.socket.emit('playerJoined', p2)
+        p2.socket.emit('playerJoined', p1)
+        match.random_map = match.maps[Math.floor(
+            Math.random()*match.maps.length)]
+        p.socket.emit('lobbyFinished', match) for p in @players
 
     removePlayer: (id) =>
-        @players = _.reject(@players, (p) -> p.id is id)
-        for player in @players
-            player.socket.emit('playerLeft', id)
-
-    matches: (other_lobby) =>
-        return false if this.finished() or other_lobby.finished()
-        return @players[0].matches(other_lobby.players[0])
-
-    match: (other_lobby) =>
-        match = this.matches(other_lobby)
-        return unless match
-        @players.push(other_lobby.players[0])
-        @players[0].socket.emit('playerJoined', @players[1])
-        @players[1].socket.emit('playerJoined', @players[0])
-        if this.finished()
-            match.random_map = match.maps[Math.floor(
-                Math.random()*match.maps.length)]
-            p.socket.emit('lobbyFinished', match) for p in @players
-
-    finished: =>
-        return @players.length is 2
-    
+        to_return = _.find(@players, (p) -> p.id isnt id)
+        to_return.socket.emit('playerLeft', id)
+        return to_return
+
     sendChat: (id, text) =>
-        to_players = _.reject(@players, (p) -> p.id is id)
-        for p in to_players
-            p.socket.emit('chatReceived', {id: id, text: text})
+        to_player = _.reject(@players, (p) -> p.id is id)[0]
+        to_player.socket.emit('chatReceived', {id: id, text: text})
+
+class LobbyManagerGlobal
+    constructor: ->
+        @pending_players = []
+        @lobbies_by_id = {}
+
+    isPresent: (id) =>
+        return id of @lobbies_by_id or id in (p.id for p in @pending_players)
+
+    addPlayer: (player) =>
+        return if this.isPresent(player.id)
+        @pending_players.push(player)
+        players = {}
+        players[player.id] = player
+        return players
+
+    removePlayer: (id) =>
+        if id of @lobbies_by_id
+            lobby = @lobbies_by_id[id]
+            other_player = lobby.removePlayer(id)
+            @pending_players.push(other_player)
+            delete @lobbies_by_id[id]
+            delete @lobbies_by_id[other_player.id]
+        else
+            @pending_players = _.reject(@pending_players, (p) -> p.id is id)
+
+    matchmake: =>
+        new_pending = []
+        while @pending_players.length > 0
+            player = @pending_players.shift()
+            continue if player.id of @lobbies_by_id
+            matched = false
+            for other_player in @pending_players
+                match = player.matches(other_player)
+                if match
+                    lobby = new Lobby(player, other_player, match)
+                    @lobbies_by_id[player.id] = lobby
+                    @lobbies_by_id[other_player.id] = lobby
+                    matched = true
+                    break
+            new_pending.push(player) if not matched
+        @pending_players = new_pending
+
+    sendChat: (id, text) =>
+        return unless id of @lobbies_by_id
+        @lobbies_by_id[id].sendChat(id, text)
+LobbyManager = new LobbyManagerGlobal()
+setInterval(->
+    try
+        LobbyManager.matchmake()
+    catch err
+        console.log('Exception: ' + err)
+, 5000)
 
 class GlobalLobbyGlobal
     constructor: ->

                cb(GlobalLobby.addPlayer(player))
            ))
    ))
    socket.on('getUserProfile', (profile_url, cb) ->
        UserProfiles.get(profile_url, cb)
    )
    socket.on('createLobby', (req, cb) ->
        UserProfiles.get(req.profile_url, handleErrors((err, profile) ->
            return if err
            req.league = profile.league
            player = new Player(socket, req)
            players = LobbyManager.addPlayer(player)
            GlobalLobby.removeByID(player.id)
            cb(players)
        ))
    )
    socket.on('listLobbies', (req, cb) ->
        UserProfiles.get(req.profile_url, handleErrors((err, profile) ->
            return if err
            req.league = profile.league
            player = new Player(socket, req)
            lobbies = LobbyManager.getMatchingLobbies(player)
            cb(lobbies)
        ))
    )
    socket.on('joinLobby', (req, cb) ->
        UserProfiles.get(req.profile_url, handleErrors((err, profile) ->
            return if err
            req.league = profile.league
            player = new Player(socket, req)
            LobbyManager.joinLobby(player, cb)
        ))
    )
    socket.on('sendChat', handleErrors((text) ->
        if GlobalLobby.isPresent(socket.id)
            GlobalLobby.sendChat(socket.id, text)

util = require('util')
_ = require('underscore')

class Player
    constructor: (socket, request) ->
        _.extend(this, request)
        @socket = socket
        @id = socket.id

    matches: (other) =>
        if not this.regionMatches(other)
            return false
        if not this.raceMatches(other) or not other.raceMatches(this)
            return false
        if not this.leagueMatches(other) or not other.leagueMatches(this)
            return false
        if not this.blocklistOk(other) or not other.blocklistOk(this)
            return false
        series = this.seriesMatches(other)
        return false if series.length is 0
        maps = this.mapMatches(other)
        return false if maps.length is 0
        return {series: series, maps: maps}

    regionMatches: (other) ->
        return @region is other.region

    raceMatches: (other) ->
        return other.race in @params.opp_races

    leagueMatches: (other) ->
        return other.league in @params.opp_leagues

    seriesMatches: (other) ->
        return _.intersection(@params.series, other.params.series)

    mapMatches: (other) ->
        return _.intersection(@params.maps, other.params.maps)

    blocklistOk: (other) ->
        user = other.name + '.' + other.char_code
        return not @params.blocked_users[user]

    toJSON: =>
        id: @id
