module Robotics.NXT.Data (
fromUByte,
fromUWord,
fromULong,
fromSByte,
fromSWord,
fromSLong,
dataToString,
dataToString0,
toUByte,
toUWord,
toULong,
toSByte,
toSWord,
toSLong,
stringToData,
stringToData0,
nameToData,
messageToData
) where
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as C
import Data.List
import Data.Word
import Control.Exception
dataToInt :: Integral a => [Word8] -> a
dataToInt = foldr addByte 0x00
where addByte x y = y' * 0x100 + x'
where x' = fromIntegral x
y' = fromIntegral y
fromUByte :: Integral a => [Word8] -> a
fromUByte ws@[_] = dataToInt ws
fromUByte _ = throw $ PatternMatchFail "fromUByte"
fromUWord :: Integral a => [Word8] -> a
fromUWord ws@[_, _] = dataToInt ws
fromUWord _ = throw $ PatternMatchFail "fromUWord"
fromULong :: Integral a => [Word8] -> a
fromULong ws@[_, _, _, _] = dataToInt ws
fromULong _ = throw $ PatternMatchFail "fromULong"
fromSByte :: Integral a => [Word8] -> a
fromSByte ws@[b] | b <= 0x7F = dataToInt ws
| otherwise = negate . () 0x100 . dataToInt $ ws
fromSByte _ = throw $ PatternMatchFail "fromSByte"
fromSWord :: Integral a => [Word8] -> a
fromSWord ws@[_, b] | b <= 0x7F = dataToInt ws
| otherwise = negate . () 0x10000 . dataToInt $ ws
fromSWord _ = throw $ PatternMatchFail "fromSWord"
fromSLong :: Integral a => [Word8] -> a
fromSLong ws@[_, _, _, b] | b <= 0x7F = dataToInt ws
| otherwise = negate . () 0x100000000 . dataToInt $ ws
fromSLong _ = throw $ PatternMatchFail "fromSLong"
dataToString0 :: [Word8] -> String
dataToString0 = dataToString . takeWhile (/= 0x00)
dataToString :: [Word8] -> String
dataToString = C.unpack . B.pack
intToData :: Integral a => a -> [Word8]
intToData 0x00 = [0x00]
intToData x = unfoldr getByte x
where getByte 0x00 = Nothing
getByte y = Just (fromIntegral $ y `mod` 0x100, y `div` 0x100)
toUByte :: (Show a, Integral a) => a -> [Word8]
toUByte x | x >= 0x00 && x <= 0xFF = intToData x
| otherwise = throw . PatternMatchFail $ "toUByte: " ++ show x
toUWord :: (Show a, Integral a) => a -> [Word8]
toUWord x | x >= 0x00 && x <= 0xFFFF = take 2 . flip (++) (repeat 0x00) . intToData $ x
| otherwise = throw . PatternMatchFail $ "toUWord: " ++ show x
toULong :: (Show a, Integral a) => a -> [Word8]
toULong x | x' >= 0x00 && x' <= 0xFFFFFFFF = take 4 . flip (++) (repeat 0x00) . intToData $ x'
| otherwise = throw . PatternMatchFail $ "toULong: " ++ show x
where x' = fromIntegral x :: Integer
toSByte :: (Show a, Integral a) => a -> [Word8]
toSByte x | x >= (0x80) && x < 0x00 = intToData $ 0x100 + x
| x >= 0x00 && x <= 0x7F = intToData x
| otherwise = throw . PatternMatchFail $ "toSByte: " ++ show x
toSWord :: (Show a, Integral a) => a -> [Word8]
toSWord x | x >= (0x8000) && x < 0x00 = take 2 . flip (++) (repeat 0x00) . intToData $ 0x10000 + x
| x >= 0x00 && x <= 0x7FFF = take 2 . flip (++) (repeat 0x00) . intToData $ x
| otherwise = throw . PatternMatchFail $ "toSWord: " ++ show x
toSLong :: (Show a, Integral a) => a -> [Word8]
toSLong x | x' >= (0x80000000) && x' < 0x00 = take 4 . flip (++) (repeat 0x00) . intToData $ 0x100000000 + x'
| x' >= 0x00 && x' <= 0x7FFFFFFF = take 4 . flip (++) (repeat 0x00) . intToData $ x'
| otherwise = throw . PatternMatchFail $ "toSLong: " ++ show x
where x' = fromIntegral x :: Integer
stringToData0 :: String -> [Word8]
stringToData0 = stringToData . flip (++) "\0"
stringToData :: String -> [Word8]
stringToData = B.unpack . C.pack
nameToData :: String -> [Word8]
nameToData = stringToData0 . take 19 . flip (++) (repeat '\0')
messageToData :: String -> [Word8]
messageToData = stringToData0 . take 58