module Vaultaire.Types.ContentsResponse
(
    ContentsResponse(..),
) where
import Control.Applicative ((<$>), (<*>))
import Control.Exception (SomeException (..))
import qualified Data.ByteString as S
import Data.Packer (getBytes, getWord64LE, putBytes, putWord64LE, putWord8,
                    runPacking, runUnpacking)
import Test.QuickCheck
import Vaultaire.Classes.WireFormat
import Vaultaire.Types.Address
import Vaultaire.Types.SourceDict
data ContentsResponse = RandomAddress Address
                      | InvalidContentsOrigin
                      | ContentsListEntry Address SourceDict
                      | EndOfContentsList
                      | UpdateSuccess
                      | RemoveSuccess
  deriving (Show, Eq)
instance WireFormat ContentsResponse where
    fromWire bs
        | bs == "\x00" = Right InvalidContentsOrigin
        | bs == "\x03" = Right EndOfContentsList
        | bs == "\x04" = Right UpdateSuccess
        | bs == "\x05" = Right RemoveSuccess
        | S.take 1 bs == "\x01" = RandomAddress <$> fromWire (S.drop 1 bs)
        
        | S.take 1 bs == "\x02" = do
            let body = S.drop 1 bs
            let unpacker = (,) <$> getBytes 8 <*> (getWord64LE >>= getBytes . fromIntegral)
            let (addr_bytes, dict_bytes ) = runUnpacking unpacker body
            ContentsListEntry <$> fromWire addr_bytes <*> fromWire dict_bytes
        | otherwise = Left $ SomeException $
                        userError "Invalid ContentsResponse packet"
    toWire InvalidContentsOrigin = "\x00"
    toWire (RandomAddress addr)  = "\x01" `S.append` toWire addr
    toWire (ContentsListEntry addr dict) =
        let addr_bytes = toWire addr
            dict_bytes = toWire dict
            dict_len = S.length dict_bytes
        in runPacking (dict_len + 17) $ do
            putWord8 0x2
            putBytes addr_bytes
            putWord64LE $ fromIntegral dict_len
            putBytes dict_bytes
    toWire EndOfContentsList = "\x03"
    toWire UpdateSuccess     = "\x04"
    toWire RemoveSuccess     = "\x05"
instance Arbitrary ContentsResponse where
    arbitrary = oneof [ RandomAddress  <$> arbitrary
                      , ContentsListEntry <$> arbitrary <*> arbitrary
                      , return EndOfContentsList
                      , return UpdateSuccess
                      , return RemoveSuccess ]