{-# LANGUAGE FlexibleContexts #-}

module HaskellWorks.Data.FingerTree.Gen where

import Control.Monad
import HaskellWorks.Data.FingerTree.Strict
import Hedgehog

import qualified Hedgehog.Gen             as G
import qualified Hedgehog.Internal.Gen    as G
import qualified Hedgehog.Internal.Shrink as S
import qualified Hedgehog.Range           as R

genList :: MonadGen m => Range Int -> m a -> m [a]
genList range gen =
  G.sized $ \size ->
    (traverse snd =<<) .
    G.ensure (G.atLeast $ R.lowerBound size range) .
    G.shrink S.list $ do
      k <- G.integral_ range
      replicateM k (G.freeze gen)

shrinkFingerTree :: Measured v a => FingerTree v a -> [FingerTree v a]
shrinkFingerTree (Deep _ (One a) Empty (One b)) = [Single a, Single b]
shrinkFingerTree (Deep _ pr m sf) =
    [deep pr' m  sf  | pr' <- shrinkDigit      pr] ++
    [deep pr  m' sf  | m'  <- shrinkFingerTree m ] ++
    [deep pr  m  sf' | sf' <- shrinkDigit      sf]
shrinkFingerTree (Single x) = []
shrinkFingerTree Empty = []

fingerTree :: (MonadGen m, Measured v a) => m a -> m (FingerTree v a)
fingerTree gen = G.sized $ \size -> genSizedFingerTree size gen

genSizedFingerTree :: (MonadGen m, Measured v a) => Size -> m a -> m (FingerTree v a)
genSizedFingerTree n gen = G.shrink shrinkFingerTree $ case n of
    0 -> return Empty
    1 -> Single <$> gen
    n -> deep <$> (One <$> gen) <*> genSizedFingerTree (n `div` 2) (genSizedNode (n `div` 2) gen) <*> (One <$> gen)

shrinkNode :: Measured v a => Node v a -> [Node v a]
shrinkNode (Node2 _ a b)   = []
shrinkNode (Node3 _ a b c) = [node2 a  b, node2 a c, node2 b c]

genSizedNode :: (MonadGen m, Measured v a) => Size -> m a -> m (Node v a)
genSizedNode n gen = G.shrink shrinkNode $ G.choice
    [ node2 <$> gen <*> gen
    , node3 <$> gen <*> gen <*> gen
    ]

shrinkDigit :: Digit a -> [Digit a]
shrinkDigit (One a)        = []
shrinkDigit (Two a b)      = [One a, One b]
shrinkDigit (Three a b c)  = [Two a b, Two a c, Two b c]
shrinkDigit (Four a b c d) = [Three a b c, Three a b d, Three a c d, Three b c d]