{-# OPTIONS -fth #-}
module Shim.Messages where

import Shim.MessagesTH
import qualified Shim.Hsinfo as Hsinfo
import Shim.SHM
import Shim.Sexp
import Shim.Utils

import SrcLoc
import ErrUtils ( Severity(..) )
import FastString
import Directory

import Control.Monad.State
import System.FilePath ( (</>) )

simpleCompleteModule :: FilePath -> String -> SHM (Response ([String], String))
simpleCompleteModule filename name = do
  l <- Hsinfo.findModulesPrefix filename name
  retVal (l, commonPrefix l)


fuzzyCompleteModule :: FilePath -> String -> SHM (Response [[String]])
fuzzyCompleteModule filename name = do
  l <- Hsinfo.findModulesPrefix filename name
  retVal (map (\x -> [x,"","",""]) l)                              

getModuleExports :: FilePath -> String -> String -> SHM (Response [[String]])
getModuleExports filename name prefix = do
  l <-  Hsinfo.getModuleExports filename name prefix
  retVal (map (\(x,y) -> [x,y,"",""]) l)

quit :: SHM (Response ())
quit = do 
  logInfo "received the quit command, exiting"
  error "quit"
  return$ Error "quit"

fuzzyCompleteIdentifier :: FilePath -> String -> SHM (Response [[String]])
fuzzyCompleteIdentifier filename name = do
  l <- Hsinfo.findIdPrefix filename name
  retVal (map (\(s,ty) -> [s,ty,"",""]) l)

simpleCompleteIdentifier :: FilePath -> String -> SHM (Response ([String], String))
simpleCompleteIdentifier filename name = do
  l <- map fst `liftM` Hsinfo.findIdPrefix filename name
  retVal $ (l, commonPrefix l)

bufferNeedsPreprocessing :: FilePath -> String -> SHM (Response [Bool])
bufferNeedsPreprocessing filename source = do
  res <- Hsinfo.bufferNeedsPreprocessing filename source
  retVal [res]

-- loadFile :: FilePath -> Maybe String -> SHM (Response Se)
loadFile filename source = do
                     (res,_) <- Hsinfo.load filename True source
                     case res of
                       FileCompiled notes ->
                           retVal $ Se (S "file-compiled", encodeNotes notes)
                       ImportsOnly notes ->
                           retVal $ Se (S "compilation-failed", encodeNotes notes)
                       PreludeOnly notes ->
                           retVal $ Se (S "compilation-failed", encodeNotes notes)
                       NothingCompiled exc notes ->
                           retVal $ Se (S "compilation-exception", exc, encodeNotes notes)

lookupType :: FilePath -> Int -> Int -> Maybe String -> SHM (Response String)
lookupType filename line col source = do
  s <- Hsinfo.findTypeOfPos filename line col source
  retVal s

findDefinition :: FilePath -> Int -> Int -> Maybe String -> SHM (Response Se)
findDefinition filename line col source = do
  srcLoc <- Hsinfo.findDefinition filename line col source
  loc <- encodeSrcLoc srcLoc
  retVal loc

testUnexpectedExc :: SHM (Response a)
testUnexpectedExc = error "test-unexpected-exc"


-----------------------------------------

retVal :: a -> SHM (Response a)
retVal = return . Response

encodeSrcLoc :: SrcLoc -> SHM Se
encodeSrcLoc srcLoc
  | isGoodSrcLoc srcLoc = do projectDir <- io $ Directory.getCurrentDirectory
                             let filename0 = unpackFS $ srcLocFile srcLoc
                                 filename = case filename0 of
                                              ('/':_) -> filename0
                                              _ -> projectDir </> filename0
                             return $ Se (S ":loc", filename,
                                          srcLocLine srcLoc, srcLocCol srcLoc)
  | otherwise = return $ Se nil


encodeNotes :: [CompileNote] -> Se
encodeNotes l =
  Se . map (\c -> (encodeSeverity (severity c),
                   encodeSrcSpan c (projectdir c),
                   show (message c (pprStyle c)))) $ l
 where encodeSeverity SevInfo    = S ":sev-info" 
       encodeSeverity SevWarning = S ":sev-warning"
       encodeSeverity SevError   = S ":sev-error"
       encodeSeverity SevFatal   = S ":sev-fatal"
       encodeSrcSpan s dir =
         maybe (Se nil)
               (\(f,l1,c1,l2,c2) -> if l1==l2 && c1==c2  -- hack to deal with empty 
                                                         -- spans(emacs gets confused), 
                                                         -- due to parsing errors 
                                    then Se (S ":span",f,l1,c1,l2,c2+1)
                                    else Se (S ":span",f,l1,c1,l2,c2))
               $ excToMaybe $
         let loc1 = srcSpanStart $ srcSpan s
             loc2 = srcSpanEnd $ srcSpan s
             filename0 = unpackFS $ srcLocFile loc1
         in (dir </> filename0, srcLocLine loc1,
             srcLocCol loc1, srcLocLine loc2, srcLocCol loc2 )
             -- TODO: srcLoc{File,Line,Col} can panic, use isGoodSrcLoc

$(mkMsg 'simpleCompleteModule)
$(mkMsg 'fuzzyCompleteModule)
$(mkMsg 'simpleCompleteIdentifier)
$(mkMsg 'fuzzyCompleteIdentifier)
$(mkMsg 'lookupType)
$(mkMsg 'findDefinition)
$(mkMsg 'getModuleExports)
$(mkMsg 'bufferNeedsPreprocessing)
$(mkMsg 'loadFile)
$(mkMsg 'quit)

$(mkMessageList)
