{-# OPTIONS_HADDOCK hide #-}
module Codec.Binary.QRCode.Matrix where

import Data.Array.IArray
import Codec.Binary.QRCode.Utils

-- | Represents a QR Code symbol.
newtype Matrix = QRM { getModules :: Array (Int,Int) Module }

instance Show Matrix where
    show = showMatrix

getWidth :: Array (Int, Int) Module -> Int
getWidth = fst . snd . bounds

-- | Convert a 'Matrix' to an array of 'Bounded'
-- 'Light' modules will have the value 'maxBound';
-- 'Dark' modules will have the value 'minBound'
toArray :: Bounded a => Matrix -> Array (Int, Int) a
toArray (QRM m) = amap conv . ixmap bs inv $ m
    where
        conv Dark = minBound
        conv Light = maxBound

        bs = bounds m
        width = getWidth m
        inv (r,c) = (width - r, width - c)

qrmCol :: Int -> Matrix -> Modules
qrmCol n (QRM mat) = [mat ! (r,n) | r <- [0..(getWidth mat)]]

qrmRow :: Int -> Matrix -> Modules
qrmRow n (QRM mat) = [mat ! (n,c) | c <- [0..(getWidth mat)]]

qrmWidth :: Matrix -> Int
qrmWidth = getWidth . getModules

qrmOverlay :: Matrix -> [((Int, Int), Module)] -> Matrix
qrmOverlay (QRM mat) associations = QRM $ mat // associations

show2DArray :: (Enum i, Num i, Ix i, Show e) => Array (i,i) e -> String
show2DArray mods = rows
    where
        bound = fst . snd . bounds $ mods
        showFs = amap shows mods
        row r = foldr (.) ("\n"++) [showFs ! (r,col) | col <- reverse [0..bound]]
        rows = foldr (.) id [row r | r <- reverse [0..bound]] $ ""

-- Show Matrix "top-down"
-- i.e. (0,0) is displayed in bottom right
showMatrix :: Matrix -> String
showMatrix = show2DArray . getModules