{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Language.Haskell.LSP.Capture
  ( Event(..)
  , CaptureContext
  , noCapture
  , captureToFile
  , captureFromClient
  , captureFromServer
  ) where

import Data.Aeson
import Data.ByteString.Lazy.Char8 as BSL
import Data.Time.Clock
import GHC.Generics
import Language.Haskell.LSP.Messages
import System.IO
import Language.Haskell.LSP.Utility
import Control.Concurrent
import Control.Monad
import Control.Concurrent.STM

data Event = FromClient !UTCTime !FromClientMessage
           | FromServer !UTCTime !FromServerMessage
  deriving (Show, Eq, Generic, ToJSON, FromJSON)

data CaptureContext = NoCapture | Capture (TChan Event)

noCapture :: CaptureContext
noCapture = NoCapture

captureToFile :: FilePath -> IO CaptureContext
captureToFile fname = do
    logs $ "haskell-lsp:Logging to " ++ fname
    chan <- newTChanIO
    _tid <- forkIO $ withFile fname WriteMode $ writeToHandle chan
    return $ Capture chan

captureFromServer :: FromServerMessage -> CaptureContext -> IO ()
captureFromServer _ NoCapture = return ()
captureFromServer msg (Capture chan) = do
  time <- getCurrentTime
  atomically $ writeTChan chan $ FromServer time msg

captureFromClient :: FromClientMessage -> CaptureContext -> IO ()
captureFromClient _ NoCapture = return ()
captureFromClient msg (Capture chan) = do
  time <- getCurrentTime
  atomically $ writeTChan chan $ FromClient time msg

writeToHandle :: TChan Event -> Handle -> IO ()
writeToHandle chan hdl = forever $ do
    ev <- atomically $ readTChan chan
    BSL.hPutStrLn hdl $ encode ev