content: {-# LANGUAGE RecordWildCards #-}
  {-# OPTIONS_GHC -Wno-incomplete-record-updates #-}
  
  module Network.QUIC.Connection.Role (
      setToken,
      getToken,
      getResumptionInfo,
      setRetried,
      getRetried,
      setIncompatibleVN,
      getIncompatibleVN,
      setResumptionSession,
      setNewToken,
      setResumptionParameters,
      setRegister,
      getRegister,
      getUnregister,
      setTokenManager,
      getTokenManager,
      setStopServer,
      getStopServer,
      setCertificateChain,
      getCertificateChain,
      setSockConnected,
      getSockConnected,
  ) where
  
  import qualified Crypto.Token as CT
  import Data.X509 (CertificateChain)
  
  import Network.QUIC.Connection.Misc
  import Network.QUIC.Connection.Types
  import Network.QUIC.Connector
  import Network.QUIC.Imports
  import Network.QUIC.Parameters
  import Network.QUIC.Types
  
  ----------------------------------------------------------------
  
  setToken :: Connection -> Token -> IO ()
  setToken Connection{..} token = atomicModifyIORef'' roleInfo $
      \ci -> ci{clientInitialToken = token}
  
  getToken :: Connection -> IO Token
  getToken conn@Connection{..}
      | isClient conn = clientInitialToken <$> readIORef roleInfo
      | otherwise = return emptyToken
  
  ----------------------------------------------------------------
  
  -- | Getting information about resumption.
  getResumptionInfo :: Connection -> IO ResumptionInfo
  getResumptionInfo Connection{..} = resumptionInfo <$> readIORef roleInfo
  
  ----------------------------------------------------------------
  
  setRetried :: Connection -> Bool -> IO ()
  setRetried conn@Connection{..} r
      | isClient conn = atomicModifyIORef'' roleInfo $ \ci ->
          ci
              { resumptionInfo = (resumptionInfo ci){resumptionRetry = r}
              }
      | otherwise = atomicModifyIORef'' roleInfo $ \si -> si{askRetry = r}
  
  getRetried :: Connection -> IO Bool
  getRetried conn@Connection{..}
      | isClient conn = resumptionRetry . resumptionInfo <$> readIORef roleInfo
      | otherwise = askRetry <$> readIORef roleInfo
  
  ----------------------------------------------------------------
  
  setIncompatibleVN :: Connection -> Bool -> IO ()
  setIncompatibleVN conn@Connection{..} icvn
      | isClient conn = atomicModifyIORef'' roleInfo $ \ci ->
          ci
              { incompatibleVN = icvn
              }
      | otherwise = return ()
  
  getIncompatibleVN :: Connection -> IO Bool
  getIncompatibleVN conn@Connection{..}
      | isClient conn = incompatibleVN <$> readIORef roleInfo
      | otherwise = return False
  
  ----------------------------------------------------------------
  
  setResumptionSession :: Connection -> SessionEstablish
  setResumptionSession conn@Connection{..} si sd = do
      ver <- getVersion conn
      atomicModifyIORef'' roleInfo $ \ci ->
          let resumInfo = resumptionInfo ci
           in ci
                  { resumptionInfo =
                      resumInfo
                          { resumptionVersion = ver
                          , resumptionSession = (si, sd) : resumptionSession resumInfo
                          }
                  }
      return Nothing
  
  setNewToken :: Connection -> Token -> IO ()
  setNewToken conn@Connection{..} token = do
      ver <- getVersion conn
      atomicModifyIORef'' roleInfo $ \ci ->
          ci
              { resumptionInfo =
                  (resumptionInfo ci)
                      { resumptionVersion = ver
                      , resumptionToken = token
                      }
              }
  
  setResumptionParameters :: Connection -> Parameters -> IO ()
  setResumptionParameters Connection{..} params = do
      atomicModifyIORef'' roleInfo $ \ci ->
          ci
              { resumptionInfo = parametersToResumption (resumptionInfo ci) params
              }
  
  parametersToResumption :: ResumptionInfo -> Parameters -> ResumptionInfo
  parametersToResumption ri Parameters{..} =
      ri
          { resumptionActiveConnectionIdLimit = activeConnectionIdLimit
          , resumptionInitialMaxData = initialMaxData
          , resumptionInitialMaxStreamDataBidiLocal = initialMaxStreamDataBidiLocal
          , resumptionInitialMaxStreamDataBidiRemote = initialMaxStreamDataBidiRemote
          , resumptionInitialMaxStreamDataUni = initialMaxStreamDataUni
          , resumptionInitialMaxStreamsBidi = initialMaxStreamsBidi
          , resumptionInitialMaxStreamsUni = initialMaxStreamsUni
          }
  
  ----------------------------------------------------------------
  
  setRegister
      :: Connection -> (CID -> Connection -> IO ()) -> (CID -> IO ()) -> IO ()
  setRegister Connection{..} regisrer unregister = atomicModifyIORef'' roleInfo $ \si ->
      si
          { registerCID = regisrer
          , unregisterCID = unregister
          }
  
  getRegister :: Connection -> IO (CID -> Connection -> IO ())
  getRegister Connection{..} = registerCID <$> readIORef roleInfo
  
  getUnregister :: Connection -> IO (CID -> IO ())
  getUnregister Connection{..} = unregisterCID <$> readIORef roleInfo
  
  ----------------------------------------------------------------
  
  setTokenManager :: Connection -> CT.TokenManager -> IO ()
  setTokenManager Connection{..} mgr = atomicModifyIORef'' roleInfo $
      \si -> si{tokenManager = mgr}
  
  getTokenManager :: Connection -> IO CT.TokenManager
  getTokenManager Connection{..} = tokenManager <$> readIORef roleInfo
  
  ----------------------------------------------------------------
  
  setStopServer :: Connection -> IO () -> IO ()
  setStopServer Connection{..} action = atomicModifyIORef'' roleInfo $
      \si -> si{stopServer = action}
  
  getStopServer :: Connection -> IO (IO ())
  getStopServer Connection{..} = stopServer <$> readIORef roleInfo
  
  ----------------------------------------------------------------
  
  setCertificateChain :: Connection -> Maybe CertificateChain -> IO ()
  setCertificateChain Connection{..} mcc = atomicModifyIORef'' roleInfo $
      \si -> si{certChain = mcc}
  
  getCertificateChain :: Connection -> IO (Maybe CertificateChain)
  getCertificateChain Connection{..} = certChain <$> readIORef roleInfo
  
  ----------------------------------------------------------------
  
  setSockConnected :: Connection -> Bool -> IO ()
  setSockConnected Connection{..} b = atomicModifyIORef'' roleInfo $
      \ci -> ci{sockConnected = b}
  
  getSockConnected :: Connection -> IO Bool
  getSockConnected Connection{..} = do
      ri <- readIORef roleInfo
      case ri of
          ClientInfo{..} -> return sockConnected
          _ -> return False
  