module Network.HPACK.HeaderBlock.Integer (
    encode
  , encodeOne
  , decode
  , decodeOne
  , parseInteger
  ) where

import Data.Array (Array, listArray, (!))
import Data.Word (Word8)

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

powerArray :: Array Int Int
powerArray = listArray (1,8) [1,3,7,15,31,63,127,255]

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

-- | Integer encoding. The first argument is N of prefix.
--
-- >>> encode 5 10
-- [10]
-- >>> encode 5 1337
-- [31,154,10]
-- >>> encode 8 42
-- [42]
encode :: Int -> Int -> [Word8]
encode n i
  | i < p     = fromIntegral i : []
  | otherwise = fromIntegral p : encode' (i - p)
  where
    p = powerArray ! n

encode' :: Int -> [Word8]
encode' i
  | i < 128   = fromIntegral i : []
  | otherwise = fromIntegral (r + 128) : encode' q
  where
    (q,r) = i `divMod` 128

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

-- | Integer encoding.
encodeOne :: Int -> Word8
encodeOne = fromIntegral

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

-- | Integer decoding. The first argument is N of prefix.
--
-- >>> decode 5 [10]
-- 10
-- >>> decode 5 [31,154,10]
-- 1337
-- >>> decode 8 [42]
-- 42
decode :: Int -> [Word8] -> Int
decode _ []     = error "decode"
decode n ws
  | i < p     = i
  | otherwise = foldr1 (\x y -> x - 128 + y * 128) is + i
  where
    p = powerArray ! n
    (i:is) = map fromIntegral ws

-- | Integer decoding.
decodeOne :: Word8 -> Int
decodeOne = fromIntegral

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

parseInteger :: Int -> Word8 -> [Word8] -> (Int, [Word8])
parseInteger n w ws
  | i < p     = (i, ws)
  | otherwise = (len, rest)
  where
    p = powerArray ! n
    i = fromIntegral w
    (ws', rest) = split ws
    len = decode n (w:ws')

split :: [Word8] -> ([Word8],[Word8])
split []     = error "split"
split (w:ws)
  | w >= 128  = let (xs,ys) = split ws in (w:xs, ys)
  | otherwise = ([w], ws)