{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE KindSignatures      #-}
{-# LANGUAGE NamedFieldPuns      #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Ouroboros.Network.Diffusion
  ( -- * Common API
    P2P (..)
  , InitializationTracer (..)
  , Tracers (..)
  , nullTracers
  , ExtraTracers (..)
  , Failure
  , Arguments (..)
  , ExtraArguments (..)
  , Applications (..)
  , ExtraApplications (..)
    -- * Run data diffusion
  , run
    -- * Re-exports
  , P2P.AbstractTransitionTrace
  ) where

import           Control.Exception (IOException)
import           Data.Functor (void)

import           Network.Socket (Socket)

import           Ouroboros.Network.NodeToClient (LocalAddress, LocalSocket,
                     NodeToClientVersion, NodeToClientVersionData)
import           Ouroboros.Network.NodeToNode (NodeToNodeVersion,
                     NodeToNodeVersionData, RemoteAddress)

import           Ouroboros.Network.Diffusion.Common as Common
import qualified Ouroboros.Network.Diffusion.NonP2P as NonP2P
import qualified Ouroboros.Network.Diffusion.P2P as P2P

-- | Promoted data types.
--
data P2P = P2P | NonP2P


-- | Tracers which depend on p2p mode.
--
data ExtraTracers (p2p :: P2P) where
  P2PTracers
    :: P2P.TracersExtra
           RemoteAddress  NodeToNodeVersion   NodeToNodeVersionData
           LocalAddress   NodeToClientVersion NodeToClientVersionData
           IOException IO
    -> ExtraTracers 'P2P

  NonP2PTracers
    :: NonP2P.TracersExtra
    -> ExtraTracers 'NonP2P


-- | Diffusion arguments which depend on p2p mode.
--
data ExtraArguments (p2p :: P2P) m where
  P2PArguments
    :: P2P.ArgumentsExtra m
    -> ExtraArguments 'P2P m

  NonP2PArguments
    :: NonP2P.ArgumentsExtra
    -> ExtraArguments 'NonP2P m


-- | Application data which depend on p2p mode.
--
data ExtraApplications (p2p :: P2P) ntnAddr m where
  P2PApplications
    :: P2P.ApplicationsExtra ntnAddr m
    -> ExtraApplications 'P2P ntnAddr m

  NonP2PApplications
    :: NonP2P.ApplicationsExtra
    -> ExtraApplications 'NonP2P ntnAddr m


-- | Run data diffusion in either 'P2P' or 'NonP2P' mode.
--
run :: forall (p2p :: P2P).
       Tracers
         RemoteAddress NodeToNodeVersion
         LocalAddress  NodeToClientVersion
         IO
    -> ExtraTracers p2p
    -> Arguments
         Socket      RemoteAddress
         LocalSocket LocalAddress
    -> ExtraArguments p2p IO
    -> Applications
         RemoteAddress  NodeToNodeVersion   NodeToNodeVersionData
         LocalAddress   NodeToClientVersion NodeToClientVersionData
         IO
    -> ExtraApplications p2p RemoteAddress IO
    -> IO ()
run :: Tracers
  RemoteAddress NodeToNodeVersion LocalAddress NodeToClientVersion IO
-> ExtraTracers p2p
-> Arguments Socket RemoteAddress LocalSocket LocalAddress
-> ExtraArguments p2p IO
-> Applications
     RemoteAddress
     NodeToNodeVersion
     NodeToNodeVersionData
     LocalAddress
     NodeToClientVersion
     NodeToClientVersionData
     IO
-> ExtraApplications p2p RemoteAddress IO
-> IO ()
run Tracers
  RemoteAddress NodeToNodeVersion LocalAddress NodeToClientVersion IO
tracers (P2PTracers TracersExtra
  RemoteAddress
  NodeToNodeVersion
  NodeToNodeVersionData
  LocalAddress
  NodeToClientVersion
  NodeToClientVersionData
  IOException
  IO
tracersExtra)
            Arguments Socket RemoteAddress LocalSocket LocalAddress
args (P2PArguments ArgumentsExtra IO
argsExtra)
            Applications
  RemoteAddress
  NodeToNodeVersion
  NodeToNodeVersionData
  LocalAddress
  NodeToClientVersion
  NodeToClientVersionData
  IO
apps (P2PApplications ApplicationsExtra RemoteAddress IO
appsExtra) =
    IO Void -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Void -> IO ()) -> IO Void -> IO ()
forall a b. (a -> b) -> a -> b
$
    Tracers
  RemoteAddress NodeToNodeVersion LocalAddress NodeToClientVersion IO
-> TracersExtra
     RemoteAddress
     NodeToNodeVersion
     NodeToNodeVersionData
     LocalAddress
     NodeToClientVersion
     NodeToClientVersionData
     IOException
     IO
-> Arguments Socket RemoteAddress LocalSocket LocalAddress
-> ArgumentsExtra IO
-> Applications
     RemoteAddress
     NodeToNodeVersion
     NodeToNodeVersionData
     LocalAddress
     NodeToClientVersion
     NodeToClientVersionData
     IO
-> ApplicationsExtra RemoteAddress IO
-> IO Void
P2P.run Tracers
  RemoteAddress NodeToNodeVersion LocalAddress NodeToClientVersion IO
tracers TracersExtra
  RemoteAddress
  NodeToNodeVersion
  NodeToNodeVersionData
  LocalAddress
  NodeToClientVersion
  NodeToClientVersionData
  IOException
  IO
tracersExtra
            Arguments Socket RemoteAddress LocalSocket LocalAddress
args ArgumentsExtra IO
argsExtra
            Applications
  RemoteAddress
  NodeToNodeVersion
  NodeToNodeVersionData
  LocalAddress
  NodeToClientVersion
  NodeToClientVersionData
  IO
apps ApplicationsExtra RemoteAddress IO
appsExtra
run Tracers
  RemoteAddress NodeToNodeVersion LocalAddress NodeToClientVersion IO
tracers (NonP2PTracers TracersExtra
tracersExtra)
            Arguments Socket RemoteAddress LocalSocket LocalAddress
args (NonP2PArguments ArgumentsExtra
argsExtra)
            Applications
  RemoteAddress
  NodeToNodeVersion
  NodeToNodeVersionData
  LocalAddress
  NodeToClientVersion
  NodeToClientVersionData
  IO
apps (NonP2PApplications ApplicationsExtra
appsExtra) =
    Tracers
  RemoteAddress NodeToNodeVersion LocalAddress NodeToClientVersion IO
-> TracersExtra
-> Arguments Socket RemoteAddress LocalSocket LocalAddress
-> ArgumentsExtra
-> Applications
     RemoteAddress
     NodeToNodeVersion
     NodeToNodeVersionData
     LocalAddress
     NodeToClientVersion
     NodeToClientVersionData
     IO
-> ApplicationsExtra
-> IO ()
NonP2P.run Tracers
  RemoteAddress NodeToNodeVersion LocalAddress NodeToClientVersion IO
tracers TracersExtra
tracersExtra
               Arguments Socket RemoteAddress LocalSocket LocalAddress
args ArgumentsExtra
argsExtra
               Applications
  RemoteAddress
  NodeToNodeVersion
  NodeToNodeVersionData
  LocalAddress
  NodeToClientVersion
  NodeToClientVersionData
  IO
apps ApplicationsExtra
appsExtra