module Text.Search.Sphinx.Get where

import Data.Binary.Get
import Data.Int (Int64)
import Prelude hiding (readList)
import Data.ByteString.Lazy hiding (pack, length, map, groupBy)
import Control.Monad
import Text.Search.Sphinx.Types

-- Utility functions
getNum :: Get Int
getNum = getWord32be >>= return . fromEnum

getNum64 :: Get Int64
getNum64 = getWord64be >>= return . fromIntegral

getNums = readList getNum
readList f = do num <- getNum
                num `times` f
times = replicateM
readField = readStr
readStr = do len <- getNum
             getLazyByteString (fromIntegral len)


getResult :: Get SearchResult
getResult = do
    status     <- getNum
    -- todo: we suppose the status is OK
    fields     <- readList readField
    attrs      <- readList readAttr
    matchCount <- getNum
    id64       <- getNum
    matches    <- matchCount `times` readMatch (id64 > 0) (map snd attrs)
    [total, totalFound, time, numWords] <- 4 `times` getNum
    wrds       <- numWords `times` readWord
    return (SearchResult matches total totalFound wrds)


readWord = do s <- readStr
              [doc, hits] <- 2 `times` getNum
              return (s, doc, hits)

readMatch isId64 attrs = do
    doc <- if isId64 then getNum64 else (getNum >>= return . fromIntegral)
    weight <- getNum
    matchAttrs <- mapM readMatchAttr attrs
    return $ Match doc weight matchAttrs

readMatchAttr AttrTFloat  = error "readMatchAttr for AttrFloat not implemented yet."
readMatchAttr AttrTMulti  = getNums >>= return . AttrMulti
readMatchAttr _           = getNum  >>= return . AttrNum

readAttr = do
    s <- readStr
    t <- getNum
    return (s, toEnum t)

readHeader = runGet $ do status  <- getWord16be
                         version <- getWord16be
                         length  <- getWord32be
                         return (status, version, length)