module Cardano.RTView
    ( runCardanoRTView
    ) where

import           Control.Concurrent.Async (async, waitAnyCancel)
import           Control.Concurrent.STM.TVar (TVar, newTVarIO)
import           Control.Monad (void)
import           Data.Text (Text)
import qualified Data.Text.IO as TIO

import           Cardano.BM.Backend.Switchboard (addUserDefinedBackend)
import           Cardano.BM.Data.Backend (Backend (..))
import qualified Cardano.BM.Setup as Setup
import           Cardano.BM.Trace (Trace, logNotice)
import           Cardano.BM.Tracing (appendName)

import           Cardano.RTView.Acceptor (launchMetricsAcceptor)
import           Cardano.RTView.CLI (RTViewParams (..))
import           Cardano.RTView.Config (prepareConfigAndParams)
import           Cardano.RTView.GUI.Elements (TmpElements, initialTmpElements)
import           Cardano.RTView.EKG (EKGStores, mkEKGStores)
import           Cardano.RTView.ErrorBuffer (ErrorBuffer, effectuate, realize, unrealize)
import           Cardano.RTView.NodeState.Types (NodesState, initialNodesState)
import           Cardano.RTView.NodeState.Updater (launchNodeStateUpdater)
import           Cardano.RTView.Notifications.CheckEvents (launchNotifications)
import           Cardano.RTView.Notifications.Types (NotificationSettings)
import           Cardano.RTView.WebServer (launchWebServer)

-- | Run the service.
runCardanoRTView :: RTViewParams -> IO ()
runCardanoRTView params' = do
  TIO.putStrLn "RTView: real-time watching for Cardano nodes"

  (config, notifySettings, params, acceptors) <- prepareConfigAndParams params'

  (tr :: Trace IO Text, switchBoard) <- Setup.setupTrace_ config "cardano-rt-view"
  let accTr = appendName "acceptor" tr

  Initialise own backend ( error buffer ) .
  be :: ErrorBuffer Text <- realize config
  let ebBe = MkBackend { bEffectuate = effectuate be
                       , bUnrealize  = unrealize be
                       }
  addUserDefinedBackend switchBoard ebBe "ErrorBufferBK"

  logNotice tr "Starting service; hit CTRL-C to terminate..."

  This TVar contains state ( info , metrics ) for all nodes we receive metrics from .
  nsTVar :: TVar NodesState <- newTVarIO =<< initialNodesState config
  This TVar contains temporary Elements which should be deleted explicitly .
  tmpElsTVar :: TVar TmpElements <- newTVarIO $ initialTmpElements acceptors
  This TVar contains complete notification settings .
  notifyTVar :: TVar NotificationSettings <- newTVarIO notifySettings
  This TVar contains EKG - stores for all acceptors .
  ekgStoresTVar :: TVar EKGStores <- newTVarIO =<< mkEKGStores acceptors

  let nsTr = appendName "nodeState" tr
      wsTr = appendName "webServer" tr
      ntTr = appendName "notifications" tr
  Launch 4 threads :
    1 . acceptor plugin ( it launches |TraceAcceptor| plugin ) ,
    2 . node state updater ( it gets metrics from  and updates NodeState ) ,
    3 . web server ( it serves requests from user 's browser and shows nodes ' metrics in the real time ) .
    4 . notifications : check events and notify the user about them .
  acceptorThr <- async $ launchMetricsAcceptor config accTr switchBoard
  updaterThr  <- async $ launchNodeStateUpdater nsTr switchBoard be nsTVar ekgStoresTVar
  serverThr   <- async $ launchWebServer wsTr config nsTVar tmpElsTVar notifyTVar params acceptors
  notifyThr   <- async $ launchNotifications ntTr nsTVar notifyTVar

  void $ waitAnyCancel [acceptorThr, updaterThr, serverThr, notifyThr]

 | Run the service.
module Cardano.RTView
    ( runCardanoRTView
    ) where

import           Control.Concurrent.Async (async, waitAnyCancel)
import           Control.Concurrent.STM.TVar (TVar, newTVarIO)
import           Control.Monad (void)
import           Data.Text (Text)
import qualified Data.Text.IO as TIO

import           Cardano.BM.Backend.Switchboard (addUserDefinedBackend)
import           Cardano.BM.Data.Backend (Backend (..))
import qualified Cardano.BM.Setup as Setup
import           Cardano.BM.Trace (Trace, logNotice)
import           Cardano.BM.Tracing (appendName)

import           Cardano.RTView.Acceptor (launchMetricsAcceptor)
import           Cardano.RTView.CLI (RTViewParams (..))
import           Cardano.RTView.Config (prepareConfigAndParams)
import           Cardano.RTView.GUI.Elements (TmpElements, initialTmpElements)
import           Cardano.RTView.EKG (EKGStores, mkEKGStores)
import           Cardano.RTView.ErrorBuffer (ErrorBuffer, effectuate, realize, unrealize)
import           Cardano.RTView.NodeState.Types (NodesState, initialNodesState)
import           Cardano.RTView.NodeState.Updater (launchNodeStateUpdater)
import           Cardano.RTView.Notifications.CheckEvents (launchNotifications)
import           Cardano.RTView.Notifications.Types (NotificationSettings)
import           Cardano.RTView.WebServer (launchWebServer)

runCardanoRTView :: RTViewParams -> IO ()
runCardanoRTView params' = do
  TIO.putStrLn "RTView: real-time watching for Cardano nodes"

  (config, notifySettings, params, acceptors) <- prepareConfigAndParams params'

  (tr :: Trace IO Text, switchBoard) <- Setup.setupTrace_ config "cardano-rt-view"
  let accTr = appendName "acceptor" tr

  Initialise own backend ( error buffer ) .
  be :: ErrorBuffer Text <- realize config
  let ebBe = MkBackend { bEffectuate = effectuate be
                       , bUnrealize  = unrealize be
                       }
  addUserDefinedBackend switchBoard ebBe "ErrorBufferBK"

  logNotice tr "Starting service; hit CTRL-C to terminate..."

  This TVar contains state ( info , metrics ) for all nodes we receive metrics from .
  nsTVar :: TVar NodesState <- newTVarIO =<< initialNodesState config
  This TVar contains temporary Elements which should be deleted explicitly .
  tmpElsTVar :: TVar TmpElements <- newTVarIO $ initialTmpElements acceptors
  This TVar contains complete notification settings .
  notifyTVar :: TVar NotificationSettings <- newTVarIO notifySettings
  This TVar contains EKG - stores for all acceptors .
  ekgStoresTVar :: TVar EKGStores <- newTVarIO =<< mkEKGStores acceptors

  let nsTr = appendName "nodeState" tr
      wsTr = appendName "webServer" tr
      ntTr = appendName "notifications" tr
  Launch 4 threads :
    1 . acceptor plugin ( it launches |TraceAcceptor| plugin ) ,
    2 . node state updater ( it gets metrics from  and updates NodeState ) ,
    3 . web server ( it serves requests from user 's browser and shows nodes ' metrics in the real time ) .
    4 . notifications : check events and notify the user about them .
  acceptorThr <- async $ launchMetricsAcceptor config accTr switchBoard
  updaterThr  <- async $ launchNodeStateUpdater nsTr switchBoard be nsTVar ekgStoresTVar
  serverThr   <- async $ launchWebServer wsTr config nsTVar tmpElsTVar notifyTVar params acceptors
  notifyThr   <- async $ launchNotifications ntTr nsTVar notifyTVar

  void $ waitAnyCancel [acceptorThr, updaterThr, serverThr, notifyThr]
