module IdeSession.GHC.Requests (
    GhcInitRequest(..)
  , GhcRequest(..)
  , GhcRunRequest(..)
  , RunCmd(..)
  ) where
import Data.Binary
import Data.ByteString (ByteString)
import Data.Typeable (Typeable)
import Control.Applicative ((<$>), (<*>))
import Text.Show.Pretty (PrettyVal(..))
import GHC.Generics
import IdeSession.Types.Public
data GhcInitRequest = GhcInitRequest {
    ghcInitClientApiVersion   :: Int
  , ghcInitGenerateModInfo    :: Bool
  , ghcInitOpts               :: [String]
  , ghcInitUserPackageDB      :: Bool
  , ghcInitSpecificPackageDBs :: [String]
  , ghcInitSessionDir         :: FilePath
  , ghcInitSourceDir          :: FilePath
  , ghcInitDistDir            :: !FilePath
  }
  deriving (Typeable, Generic)
data GhcRequest
  = ReqCompile {
        reqCompileGenCode   :: Bool
      , reqCompileTargets   :: Targets
      }
  | ReqRun {
        reqRunCmd :: RunCmd
      }
  | ReqSetEnv {
        reqSetEnv :: [(String, Maybe String)]
      }
  | ReqSetArgs {
        reqSetArgs :: [String]
      }
  | ReqBreakpoint {
        reqBreakpointModule :: ModuleName
      , reqBreakpointSpan   :: SourceSpan
      , reqBreakpointValue  :: Bool
      }
  | ReqPrint {
        reqPrintVars  :: Name
      , reqPrintBind  :: Bool
      , reqPrintForce :: Bool
      }
  | ReqLoad {
        reqLoad :: [FilePath]
      }
  | ReqUnload {
        reqUnload :: [FilePath]
      }
  | ReqSetGhcOpts {
        reqSetGhcOpts :: [String]
      }
    
  | ReqCrash {
        reqCrashDelay :: Maybe Int
      }
  deriving (Typeable, Generic, Show)
data RunCmd =
    RunStmt {
        runCmdModule   :: String
      , runCmdFunction :: String
      , runCmdStdout   :: RunBufferMode
      , runCmdStderr   :: RunBufferMode
      , runCmdPty      :: Bool
      }
  | Resume
  deriving (Typeable, Generic, Show)
instance PrettyVal GhcInitRequest
instance PrettyVal GhcRequest
instance PrettyVal RunCmd
data GhcRunRequest =
    GhcRunInput ByteString
  | GhcRunInterrupt
  deriving Typeable
instance Binary GhcInitRequest where
  put (GhcInitRequest{..}) = do
    
    
    
    put ghcInitClientApiVersion
    put ghcInitGenerateModInfo
    put ghcInitOpts
    put ghcInitUserPackageDB
    put ghcInitSpecificPackageDBs
    put ghcInitSessionDir
    put ghcInitSourceDir
    put ghcInitDistDir
  get = GhcInitRequest <$> get
                       <*> get
                       <*> get
                       <*> get
                       <*> get
                       <*> get
                       <*> get
                       <*> get
instance Binary GhcRequest where
  put ReqCompile{..} = do
    putWord8 0
    put reqCompileGenCode
    put reqCompileTargets
  put ReqRun{..} = do
    putWord8 1
    put reqRunCmd
  put ReqSetEnv{..} = do
    putWord8 2
    put reqSetEnv
  put ReqSetArgs{..} = do
    putWord8 3
    put reqSetArgs
  put ReqBreakpoint{..} = do
    putWord8 4
    put reqBreakpointModule
    put reqBreakpointSpan
    put reqBreakpointValue
  put ReqPrint{..} = do
    putWord8 5
    put reqPrintVars
    put reqPrintBind
    put reqPrintForce
  put ReqLoad{..} = do
    putWord8 6
    put reqLoad
  put ReqUnload{..} = do
    putWord8 7
    put reqUnload
  put ReqSetGhcOpts{..} = do
    putWord8 8
    put reqSetGhcOpts
  put ReqCrash{..} = do
    putWord8 255
    put reqCrashDelay
  get = do
    header <- getWord8
    case header of
      0   -> ReqCompile     <$> get <*> get
      1   -> ReqRun         <$> get
      2   -> ReqSetEnv      <$> get
      3   -> ReqSetArgs     <$> get
      4   -> ReqBreakpoint  <$> get <*> get <*> get
      5   -> ReqPrint       <$> get <*> get <*> get
      6   -> ReqLoad        <$> get
      7   -> ReqUnload      <$> get
      8   -> ReqSetGhcOpts  <$> get
      255 -> ReqCrash       <$> get
      _   -> fail "GhcRequest.get: invalid header"
instance Binary RunCmd where
  put (RunStmt {..}) = do
    putWord8 2
    put runCmdModule
    put runCmdFunction
    put runCmdStdout
    put runCmdStderr
    put runCmdPty
  put Resume = do
    putWord8 1
  get = do
    header <- getWord8
    case header of
      
      0 -> RunStmt <$> get <*> get <*> get <*> get <*> return False
      1 -> return Resume
      2 -> RunStmt <$> get <*> get <*> get <*> get <*> get
      _ -> fail "RunCmd.get: invalid header"
instance Binary GhcRunRequest where
  put (GhcRunInput bs) = putWord8 0 >> put bs
  put GhcRunInterrupt  = putWord8 1
  get = do
    header <- getWord8
    case header of
      0 -> GhcRunInput <$> get
      1 -> return GhcRunInterrupt
      _ -> fail "GhcRunRequest.get: invalid header"