module Hoogle(
    
    TagStr(..), showTagText, showTagANSI, showTagHTML, showTagHTMLWith,
    H.ParseError(..),
    URL,
    H.Language(..),
    
    Database, loadDatabase, saveDatabase, createDatabase, showDatabase,
    
    Query, parseQuery, H.renderQuery,
    H.queryDatabases, H.queryPackages, H.querySetPackage,
    
    Score, H.scoring,
    
    Result(..), search, suggestions, completions, queryExact, H.ItemKind(..)
    ) where
import Hoogle.Store.All
import General.Base
import General.System
import Hoogle.Type.TagStr
import qualified Hoogle.DataBase.All as H
import qualified Hoogle.Query.All as H
import qualified Hoogle.Score.All as H
import qualified Hoogle.Search.All as H
import qualified Hoogle.Type.All as H
import qualified Hoogle.Language.Haskell as H
import Hoogle.Query.All(Query, exactSearch)
import Hoogle.Score.All(Score)
newtype Database = Database [H.DataBase]
toDataBase (Database x) = H.combineDataBase x
fromDataBase x = Database [x]
instance NFData Database where
    rnf (Database a) = rnf a
instance Monoid Database where
    mempty = Database []
    mappend (Database xs) (Database ys) = Database $ xs ++ ys
instance Show Database where
    show = show . toDataBase
saveDatabase :: FilePath -> Database -> IO ()
saveDatabase file x = do
    performGC
    H.saveDataBase file $ toDataBase x
loadDatabase :: FilePath -> IO Database
loadDatabase = fmap fromDataBase . H.loadDataBase
createDatabase
    :: H.Language 
    -> [Database] 
    -> String 
    -> ([H.ParseError], Database) 
createDatabase _ dbs src = (err, fromDataBase $ H.createDataBase xs res)
    where
        (err,res) = H.parseInputHaskell src
        xs = concat [x | Database x <- dbs]
showDatabase :: Database -> Maybe [String] -> String
showDatabase x sects = concatMap (`H.showDataBase` toDataBase x) $ fromMaybe [""] sects
parseQuery :: H.Language -> String -> Either H.ParseError Query
parseQuery _ = H.parseQuery
data Result = Result
    {locations :: [(URL, [(URL, String)])] 
    ,self :: TagStr 
    ,docs :: TagStr 
    }
    deriving (Eq, Show)
toResult :: H.Result -> (Score,Result)
toResult r@(H.Result ent view score) = (score, Result parents self docs)
    where
        self = H.renderResult r
        parents = map (second $ map f) $  H.entryLocations ent
        f = (H.entryURL &&& H.entryName) . fromOnce
        docs = H.renderDocs $ H.entryDocs ent
search :: Database -> Query -> [(Score,Result)]
search (Database xs) q = map toResult $ H.search xs q
suggestions :: Database -> Query -> Maybe TagStr
suggestions (Database dbs) q = H.suggestQuery dbs q
completions :: Database -> String -> [String]
completions x = H.completions (toDataBase x)
queryExact :: Maybe H.ItemKind -> Query -> Query
queryExact kind q = q { exactSearch = kind }