{-# LANGUAGE BinaryLiterals #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Codec.QRCode.Mode.Numeric
  ( numeric
  , numericB
  ) where

import           Codec.QRCode.Base

import qualified Codec.QRCode.Data.ByteStreamBuilder  as BSB
import           Codec.QRCode.Data.QRSegment.Internal
import           Codec.QRCode.Data.Result
import           Codec.QRCode.Data.ToInput

-- | Generate a segment representing the specified string of decimal digits encoded in numeric mode.
numeric :: ToNumeric a => a -> Result QRSegment
numeric s =
  case toNumeric s of
    [] -> pure (constStream mempty)
    s' -> ((encodeBits 4 0b0001 <> lengthSegment (10, 12, 14) (length s')) <>) . constStream <$> numericB s'

numericB :: ToNumeric a => a -> Result BSB.ByteStreamBuilder
numericB s
  | all (\c -> c >= 0 && c <= 9) s' = pure (go s')
  | otherwise = empty
  where
    s' :: [Int]
    s' = toNumeric s
    go :: [Int] -> BSB.ByteStreamBuilder
    go (a:b:c:cs) = BSB.encodeBits 10 (a * 100 + b * 10 + c) <> go cs
    go [a,b]      = BSB.encodeBits 7 (a * 10 + b)
    go [a]        = BSB.encodeBits 4 a
    go []         = mempty