module Text.Search.Sphinx.Get where
import Data.Binary.Get
import Data.Binary.IEEE754
import Data.Int (Int64)
import Prelude hiding (readList)
import Data.ByteString.Lazy hiding (pack, length, map, groupBy)
import Control.Monad
import qualified Text.Search.Sphinx.Types as T
import Data.Maybe (isJust, fromJust)
import qualified Data.Text.ICU.Convert as ICU
getNum :: Get Int
getNum = getWord32be >>= return . fromEnum
getFloat :: Get Float
getFloat = getFloat32be
getNum64 :: Get Int64
getNum64 = getWord64be >>= return . fromIntegral
readList f = do num <- getNum
num `times` f
times = replicateM
getTxt conv = liftM (ICU.toUnicode conv) getStrStr
getStr = do len <- getNum
getLazyByteString (fromIntegral len)
getStrStr = do len <- getNum
getByteString (fromIntegral len)
getResult :: ICU.Converter -> Get (T.SingleResult)
getResult conv = do
statusNum <- getNum
case T.toQueryStatus statusNum of
T.QueryERROR n -> do e <- getTxt conv
return $ T.QueryError statusNum e
T.QueryOK -> getResultOk >>= return . T.QueryOk
T.QueryWARNING -> do w <- getTxt conv
getResultOk >>= return . (T.QueryWarning w)
where
getResultOk = do
fields <- readList getStr
attrs <- readList readAttrPair
matchCount <- getNum
id64 <- getNum
matches <- matchCount `times` readMatch (id64 > 0) (map snd attrs) conv
[total, totalFound, time, numWords] <- 4 `times` getNum
wrds <- numWords `times` readWord conv
return $ T.QueryResult matches total totalFound wrds (map fst attrs)
readWord conv = do
s <- getStrStr
[doc, hits] <- 2 `times` getNum
return (ICU.toUnicode conv s, doc, hits)
readMatch isId64 attrs conv = do
doc <- if isId64 then getNum64 else (getNum >>= return . fromIntegral)
weight <- getNum
matchAttrs <- mapM readAttr attrs
return $ T.Match doc weight matchAttrs
where
readAttr (T.AttrTMulti attr) = (readList (readAttr attr)) >>= return . T.AttrMulti
readAttr T.AttrTBigInt = getNum64 >>= return . T.AttrBigInt
readAttr T.AttrTString = getStrStr >>= return . T.AttrString . ICU.toUnicode conv
readAttr T.AttrTUInt = getNum >>= return . T.AttrUInt
readAttr T.AttrTFloat = getFloat >>= return . T.AttrFloat
readAttr _ = getNum >>= return . T.AttrUInt
readAttrPair = do
s <- getStr
t <- getNum
return (s, toEnum t)
readHeader = runGet $ do status <- getWord16be
version <- getWord16be
length <- getWord32be
return (T.toStatus $ fromIntegral status, version, length)