--------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
-- | Functionality related to index storage and the DefaultList type.
module Text.Digestive.Form.List
    ( indicesRef
    , parseIndices
    , unparseIndices
    , DefaultList (..)
    , defaultListIndex
    ) where


--------------------------------------------------------------------------------
import           Control.Applicative ((<$>), (<*>))
import           Data.Foldable       (Foldable (..))
import           Data.Maybe          (mapMaybe)
import           Data.Text           (Text)
import qualified Data.Text           as T
import           Data.Traversable    (Traversable (..))
import           Prelude             hiding (foldr)


--------------------------------------------------------------------------------
import           Text.Digestive.Util


--------------------------------------------------------------------------------
-- | Key used to store list indices
indicesRef :: Text
indicesRef = "indices"


--------------------------------------------------------------------------------
-- | Parse a string of comma-delimited integers to a list.
-- Unparseable substrings are left out of the result.
parseIndices :: Text -> [Int]
parseIndices = mapMaybe (readMaybe . T.unpack) . T.split (== ',')


--------------------------------------------------------------------------------
-- | Serialize a list of integers as a comma-delimited Text
unparseIndices :: [Int] -> Text
unparseIndices = T.intercalate "," . map (T.pack . show)


--------------------------------------------------------------------------------
-- | A list which, when indexed on non-existant positions, returns a default
-- value.
data DefaultList a = DefaultList a [a]


--------------------------------------------------------------------------------
instance Functor DefaultList where
    fmap f (DefaultList x xs) = DefaultList (f x) (map f xs)


--------------------------------------------------------------------------------
instance Foldable DefaultList where
    foldr f z (DefaultList x xs) = f x (foldr f z xs)


--------------------------------------------------------------------------------
instance Traversable DefaultList where
    traverse f (DefaultList x xs) = DefaultList <$> f x <*> traverse f xs


--------------------------------------------------------------------------------
-- | Safe indexing of a DefaultList - returns the default value if
-- the given index is out of bounds.
defaultListIndex :: DefaultList a -> Int -> a
defaultListIndex (DefaultList x xs) i
    | i < 0     = x
    | otherwise = case drop i xs of
        (y : _) -> y
        []      -> x