module Hint where

import HSE.All
import Data.Char
import Data.List
import Data.Maybe
import Data.Ord
import Settings
import Type
import Util


type DeclHint = NameMatch -> Module_ -> Decl_ -> [Idea]
type ModuHint = NameMatch -> Module_          -> [Idea]

data Hint = DeclHint {declHint :: DeclHint} | ModuHint {moduHint :: ModuHint}


applyHint :: ParseFlags -> [Hint] -> [Setting] -> FilePath -> IO [Idea]
applyHint flags h s file = do
    src <- readFileEncoding (encoding flags) file
    return $ applyHintStr flags h s file src


applyHintStr :: ParseFlags -> [Hint] -> [Setting] -> FilePath -> String -> [Idea]
applyHintStr flags h s file src =
    case parseString flags file src of
        ParseFailed sl msg ->
            let ticks = ["  ","  ","> ","  ","  "]
                bad = zipWith (++) ticks $ take 5 $ drop (srcLine sl - 3) $ lines src ++ [""]
                bad2 = reverse $ dropWhile (all isSpace) $ reverse $ dropWhile (all isSpace) bad
            in [classify s $ ParseError Warning "Parse error" sl msg (unlines bad2)]
        ParseOk m ->
            let name = moduleName m
                nm = nameMatch $ moduleImports m
                order n = map (\i -> i{func = (name,n)}) . sortBy (comparing loc)
                settings = concatMap(fromMaybe [] . readPragma) $ moduleDecls m
            in map (classify $ s ++ settings) $
               order "" [i | ModuHint h <- h, i <- h nm m] ++
               concat [order (fromNamed d) [i | DeclHint h <- h, i <- h nm m d] | d <- moduleDecls m]