{-# LANGUAGE NoImplicitPrelude #-}

module Codec.QRCode.Code.Intermediate
  ( toIntermediate
  , fromIntermediate
  ) where

import           Codec.QRCode.Base

import           Codec.QRCode.Code.Data
import           Codec.QRCode.Code.Image
import           Codec.QRCode.Code.Mask
import qualified Codec.QRCode.Data.ByteStreamBuilder       as BSB
import           Codec.QRCode.Data.Mask
import qualified Codec.QRCode.Data.MQRImage                as MI
import           Codec.QRCode.Data.QRCodeOptions
import           Codec.QRCode.Data.QRImage
import           Codec.QRCode.Data.QRIntermediate.Internal
import           Codec.QRCode.Data.QRSegment.Internal
import           Codec.QRCode.Data.Result

-- | Convert segments into an intermediate state.
--   This is the first point where it can be guaranteed that there will
--   be an result. The Version and ErrorLevel is already determined at
--   this point.
toIntermediate :: QRCodeOptions -> QRSegment -> Result QRIntermediate
{-# INLINE toIntermediate #-}
toIntermediate = calcVersionAndErrorLevel

-- | Convert the intermediate state into an image.
fromIntermediate :: QRIntermediate -> QRImage
{-# INLINE fromIntermediate #-}
fromIntermediate = generateQRImage . appendErrorCorrection . appendEndAndPadding

-- | "Draw" the image
generateQRImage :: QRInternal [Word8] -> QRImage
generateQRImage (v, e, bs, mmask) = runST $ do
  -- create a new image
  img1 <- MI.new v e
  -- draw all function modules
  drawFunctionPatterns img1
  -- convert the image, now the information wether an module is for data or function can't be changed anymore
  img2 <- MI.unsafeConvert img1
  -- draw the image
  drawCodeWords img2 (BSB.toBitStream bs)
  case mmask of
    Just m -> do
      -- a specific mask was given
      -- clone the current image
      img3 <- MI.clone img2
      -- apply the mask
      applyMask img3 m
      -- return the image
      MI.unsafeFreeze img3
    Nothing -> do
      rs <- forM [Mask0 .. Mask7] $ \m -> do
        -- create a new clone of the image
        img3 <- MI.clone img2
        -- apply the mask
        applyMask img3 m
        -- freeze the image (can't be altered anymore)
        qrimg <- MI.unsafeFreeze img3
        -- return the image along with the penalty score
        return (getPenaltyScore qrimg, qrimg)
      -- pick the image with the lowest penalty score
      return $ snd $ head $ sortOn fst rs