-- isForNetwork _ _ = False


--------------------------------------------------------------------------------
-- Clients
--------------------------------------------------------------------------------

behRemoteClients :: ChatUserName
                 -> Event RemoteClient
                 -> Behavior (I.IxSet ChatNetwork)
                 -> Event CoreEvent
                 -> Reactive (Behavior (M.Map Int RemoteClientInfo), IO ())
behRemoteClients uName eNewConn bNetworks eCoreEvent = do
    rec
      -- Fires when a client disconnects.
      let eClientDisconnect :: Event (Int, RemoteClientInfo)
          eClientDisconnect = switchMergeWith mkDCEvent (M.toList <$> bClientMap)

      -- Fires the ID of a client when it disconnects.
      let eClientDisconnectId :: Event Int
          eClientDisconnectId = fst <$> eClientDisconnect

      -- Event streams of functions to add and remove clients.
      let eDoAddClient = uncurry M.insert <$> eNewClient
          eDoRemoveClient = M.delete <$> eClientDisconnectId

      -- Starts new clients and fires events for each client started.
      eNewClient <- tagIds $ executeAsyncIO (($ clientCtx) <$> eNewConn)

      -- The client list is a map that is modified by functions coming out of the
      -- `eDo(Add|Remove)Client` events.
      bClientMap <- accum M.empty (eDoAddClient <> eDoRemoveClient)

    -- Cleanup clients when they disconnect.
    clean <- listen eClientDisconnect cleanClient

    return (bClientMap, clean)
  where
    clientCtx = RemoteClientCtx uName eCoreEvent bNetworks
    -- | Fires an event when the given client disconnects.
    mkDCEvent :: (Int, RemoteClientInfo) -> Event (Int, RemoteClientInfo)
    mkDCEvent (cid, client) = const (cid, client) <$> rcDisconnect client
    -- | Runs cleanup actions for the given client.
    cleanClient :: (Int, RemoteClientInfo) -> IO ()
    cleanClient (cid, client) = do
        putStrLn ("Client " <> show cid <> " disconnected.")
        -- FIXME: If the client's cleanup action calls sync, this will lock up.
        cleanupRemoteClient client


--------------------------------------------------------------------------------
-- Main
--------------------------------------------------------------------------------

-- | Set up behaviors and events for the given user.
behRemoteClients :: ChatUserName
                 -> Event RemoteClient
                 -> Behavior (I.IxSet ChatNetwork)
                 -> Event CoreEvent
                 -> Reactive (Behavior (M.Map Int RemoteClientInfo), IO ())
behRemoteClients uName eNewConn bNetworks eCoreEvent = do
    rec
      -- Fires when a client disconnects.
      let eClientDisconnect :: Event (Int, RemoteClientInfo)
          eClientDisconnect = switchMergeWith mkDCEvent (M.toList <$> bClientMap)

      -- Fires the ID of a client when it disconnects.
      let eClientDisconnectId :: Event Int
          eClientDisconnectId = fst <$> eClientDisconnect

      -- Event streams of functions to add and remove clients.
      let eDoAddClient = uncurry M.insert <$> eNewClient
          eDoRemoveClient = M.delete <$> eClientDisconnectId

      -- Starts new clients and fires events for each client started.
      eNewClient <- tagIds $ executeAsyncIO (($ clientCtx) <$> eNewConn)

      -- The client list is a map that is modified by functions coming out of the
      -- `eDo(Add|Remove)Client` events.
      bClientMap <- accum M.empty (eDoAddClient <> eDoRemoveClient)

    -- Cleanup clients when they disconnect.
    clean <- listen eClientDisconnect cleanClient

    return (bClientMap, clean)
  where
    clientCtx = RemoteClientCtx uName eCoreEvent bNetworks
    -- | Fires an event when the given client disconnects.
    mkDCEvent :: (Int, RemoteClientInfo) -> Event (Int, RemoteClientInfo)
    mkDCEvent (cid, client) = const (cid, client) <$> rcDisconnect client
    -- | Runs cleanup actions for the given client.
    cleanClient :: (Int, RemoteClientInfo) -> IO ()
    cleanClient (cid, client) = do
        putStrLn ("Client " <> show cid <> " disconnected.")
        -- FIXME: If the client's cleanup action calls sync, this will lock up.
        cleanupRemoteClient client


--------------------------------------------------------------------------------
-- Main
--------------------------------------------------------------------------------

-- | Set up behaviors and events for the given user.
behRemoteClients uName eNewConn bNetworks eCoreEvent = do
    rec
      -- Fires when a client disconnects.
      let eClientDisconnect :: Event (Int, RemoteClientInfo)
          eClientDisconnect = switchMergeWith mkDCEvent (M.toList <$> bClientMap)

      -- Fires the ID of a client when it disconnects.
      let eClientDisconnectId :: Event Int
          eClientDisconnectId = fst <$> eClientDisconnect

      -- Event streams of functions to add and remove clients.
      let eDoAddClient = uncurry M.insert <$> eNewClient
          eDoRemoveClient = M.delete <$> eClientDisconnectId

      -- Starts new clients and fires events for each client started.
      eNewClient <- tagIds $ executeAsyncIO (($ clientCtx) <$> eNewConn)

      -- The client list is a map that is modified by functions coming out of the
      -- `eDo(Add|Remove)Client` events.
      bClientMap <- accum M.empty (eDoAddClient <> eDoRemoveClient)

    -- Cleanup clients when they disconnect.
    clean <- listen eClientDisconnect cleanClient

    return (bClientMap, clean)
  where
    clientCtx = RemoteClientCtx uName eCoreEvent bNetworks
    -- | Fires an event when the given client disconnects.
    mkDCEvent :: (Int, RemoteClientInfo) -> Event (Int, RemoteClientInfo)
    mkDCEvent (cid, client) = const (cid, client) <$> rcDisconnect client
    -- | Runs cleanup actions for the given client.
    cleanClient :: (Int, RemoteClientInfo) -> IO ()
    cleanClient (cid, client) = do
        putStrLn ("Client " <> show cid <> " disconnected.")
        -- FIXME: If the client's cleanup action calls sync, this will lock up.
        cleanupRemoteClient client


--------------------------------------------------------------------------------
-- Main
--------------------------------------------------------------------------------

-- | Set up behaviors and events for the given user.