-----------------------------------------------------------------------------
-- |
-- Module      : System.Taffybar.Widget.NetworkGraph
-- Copyright   : (c) Ivan A. Malison
-- License     : BSD3-style (see LICENSE)
--
-- Maintainer  : Ivan A. Malison
-- Stability   : unstable
-- Portability : unportable
--
-- This module provides a channel based network graph widget.
-----------------------------------------------------------------------------

module System.Taffybar.Widget.NetworkGraph where

import Data.Default (Default(..))
import Data.Foldable (for_)
import qualified GI.Gtk
import GI.Gtk.Objects.Widget (widgetSetTooltipMarkup)
import System.Taffybar.Context
import System.Taffybar.Hooks
import System.Taffybar.Information.Network
import System.Taffybar.Util (postGUIASync)
import System.Taffybar.Widget.Generic.ChannelGraph
import System.Taffybar.Widget.Generic.ChannelWidget
import System.Taffybar.Widget.Generic.Graph
import System.Taffybar.Widget.Text.NetworkMonitor

-- | 'NetworkGraphConfig' configures the network graph widget.
data NetworkGraphConfig = NetworkGraphConfig
  { networkGraphGraphConfig :: GraphConfig -- ^ The configuration of the graph itself.
  -- | A tooltip format string, together with the precision that should be used
  -- for numbers in the string.
  , networkGraphTooltipFormat :: Maybe (String, Int)
  -- | A function to scale the y axis of the network config. The default is
  -- `logBase $ 2 ** 32`.
  , networkGraphScale :: Double -> Double
  -- | A filter function that determines whether a given interface will be
  -- included in the network stats.
  , interfacesFilter :: String -> Bool
  }

-- | Default configuration paramters for the network graph.
defaultNetworkGraphConfig :: NetworkGraphConfig
defaultNetworkGraphConfig = NetworkGraphConfig
  { networkGraphGraphConfig = def
  , networkGraphTooltipFormat = Just (defaultNetFormat, 3)
  , networkGraphScale = logBase $ 2 ** 32
  , interfacesFilter = const True
  }

instance Default NetworkGraphConfig where
  def = defaultNetworkGraphConfig

-- | 'networkGraphNew' instantiates a network graph widget from a 'GraphConfig'
-- and a list of interfaces.
networkGraphNew :: GraphConfig -> Maybe [String] -> TaffyIO GI.Gtk.Widget
networkGraphNew config interfaces =
  networkGraphNewWith def
                        { networkGraphGraphConfig = config
                        , interfacesFilter = maybe (const True) (flip elem) interfaces
                        }

-- | 'networkGraphNewWith' instantiates a network graph widget from a
-- 'NetworkGraphConfig'.
networkGraphNewWith :: NetworkGraphConfig -> TaffyIO GI.Gtk.Widget
networkGraphNewWith config = do
  NetworkInfoChan chan <- getNetworkChan
  let getUpDown = sumSpeeds . map snd . filter (interfacesFilter config . fst)
      toSample (up, down) = map (networkGraphScale config . fromRational) [up, down]
      sampleBuilder = return . toSample . getUpDown
  widget <- channelGraphNew (networkGraphGraphConfig config) chan sampleBuilder
  for_ (networkGraphTooltipFormat config) $ \(format, precision) ->
    channelWidgetNew widget chan $ \speedInfo ->
      let (up, down) = sumSpeeds $ map snd speedInfo
          tooltip = showInfo format precision (fromRational down, fromRational up)
      in postGUIASync $ widgetSetTooltipMarkup widget $ Just tooltip
  return widget
