{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable, StandaloneDeriving #-}
module Yi.GHC where

import Control.Concurrent
import Control.Concurrent.MVar
import Control.Monad.Error ()
import Control.Monad.Reader (asks)
import Control.Monad.State
import Control.Monad.Writer
import Data.Maybe
import ErrUtils
import GHC
import Outputable
import Prelude ()
import Shim.Hsinfo
import Shim.SHM hiding (io)
import Yi.Dynamic
import Yi.Editor
import Yi.Keymap
import Yi.Prelude hiding ((<>))
import qualified Data.List.PointedList.Circular as PL
import qualified Data.Map as M
import qualified Yi.Editor as Editor

newShim :: YiM (MVar ShimState)
newShim = do
    session <- io $ ghcInit

    r <- asks yiVar
    cfg <- asks yiConfig
    let logMsg msgSeverity msgSrcSpan style msg = 
           unsafeWithEditor cfg r $ do                             
             let note = CompileNote msgSeverity msgSrcSpan style msg
             modA notesA (Just . maybe (PL.singleton note) (PL.insertRight note))
             printMsg ('\n':show ((mkLocMessage msgSrcSpan msg) style))


    io $ newMVar ShimState
               { tempSession = session,
                 sessionMap = M.empty,
                 compBuffer = M.empty,
                 compLogAction = logMsg }


getShim :: YiM (MVar ShimState)
getShim = do
  r <- withEditor $ getA maybeShimA
  case r of
    Just x -> return x
    Nothing -> do x <- newShim
                  withEditor $ putA maybeShimA (Just x)
                  return x

withShim :: SHM a -> YiM a
withShim f = do
  r <- getShim
  liftIO $ do e <- takeMVar r
              (a,e') <- runStateT f e
              putMVar r e'
              return a

runShimThread :: SHM () -> YiM ThreadId
runShimThread f = do
  r <- getShim
  (liftIO . forkOS) $
           do e <- takeMVar r
              (a,e') <- runStateT f e
              putMVar r e'
              return a

maybeShimA  :: Accessor Editor (Maybe (MVar ShimState))
maybeShimA = dynamicValueA . dynamicA

-- ---------------------------------------------------------------------
-- CompileNote

-- TODO: Perhaps this CompileNote should be replaced with something
-- more general not necessary GHC specific.
--
-- It is moved here from Yi.Mode.Shim because it has to be accessible
-- from Yi.Core. The CompileNote type itself comes from SHIM

data CompileNote = CompileNote {severity :: Severity,
                                srcSpan :: SrcSpan,
                                pprStyle :: PprStyle,
                                message :: Message}


instance Show CompileNote where
    show n = show $
               (hang (ppr (srcSpan n) <> colon) 4  (message n)) (pprStyle n)


type T = (Maybe (PL.PointedList CompileNote))
newtype ShimNotes = ShimNotes { fromShimNotes :: T }
    deriving Typeable

instance Initializable ShimNotes where
    initial = ShimNotes Nothing



notesA :: Accessor Editor T
notesA =  (accessor fromShimNotes (\x (ShimNotes _) -> ShimNotes x)) 
          . dynamicValueA . dynamicA 


