content: module Device.Nintendo.Switch.Utils where
  
  -- attoparsec
  import Data.Attoparsec.ByteString (Parser, anyWord8)
  
  -- base
  import Data.Bits ((.|.), (.&.), Bits, shiftL)
  import Data.Word (Word8)
  
  checkMask :: (Bits a, Eq a) => a -> a -> Bool
  checkMask mask value =
    mask .&. value == mask
  
  clamp :: Ord a => a -> a -> a -> a
  clamp low high value
    | value <= low  = low
    | value >= high = high
    | otherwise     = value
  
  combine :: Word8 -> Word8 -> Word8
  combine high low =
    shiftL high 4 .|. low
  
  pairs :: [a] -> [(a,a)]
  pairs (x:y:rest) = (x,y) : pairs rest
  pairs _ = []
  
  discretize :: (Real a, Integral b) => a -> a -> b -> b -> a -> b
  discretize srcMin srcMax tgtMin tgtMax value
    | value <= srcMin = tgtMin
    | value >= srcMax = tgtMax
    | otherwise = round $ fromIntegral tgtMin + frac * fromIntegral (tgtMax - tgtMin)
    where
      frac = (realToFrac (value - srcMin) / realToFrac (srcMax - srcMin)) :: Float
  
  tripleZipWith :: (a -> b -> c) -> (a, a, a) -> (b, b, b) -> (c, c, c)
  tripleZipWith f (a1, a2, a3) (b1, b2, b3) = (f a1 b1, f a2 b2, f a3 b3)
  
  tripleMap :: (a -> b) -> (a, a, a) -> (b, b, b)
  tripleMap f (a1, a2, a3) = (f a1, f a2, f a3)
  
  littleEndianWord16Parser :: (Bits a, Num a) => Parser a
  littleEndianWord16Parser = do
    byte0 <- fromIntegral <$> anyWord8
    byte1 <- fromIntegral <$> anyWord8
    pure $ shiftL byte1 8 .|. byte0
  
  tripleParser :: (Bits a, Num a) => Parser (a, a, a)
  tripleParser = do
    x <- littleEndianWord16Parser
    y <- littleEndianWord16Parser
    z <- littleEndianWord16Parser
    pure (x, y, z)