module Test.Data.List where

import qualified Data.List.HT.Private as ListHT
import qualified Data.List as List
import Control.Monad (liftM2, )

import Test.Utility (equalLists, equalInfLists, )
import Test.QuickCheck (Testable, Property, quickCheck, (==>), )

import Prelude hiding (iterate, )



takeWhileRev :: (Ord a) => (a -> Bool) -> [a] -> Bool
takeWhileRev p xs =
   ListHT.takeWhileRev p xs == reverse (takeWhile p (reverse xs))

dropWhileRev :: (Ord a) => (a -> Bool) -> [a] -> Bool
dropWhileRev p xs =
   ListHT.dropWhileRev p xs == reverse (dropWhile p (reverse xs))


takeRev :: (Eq a) => Int -> [a] -> Bool
takeRev n xs =
   ListHT.takeRev n xs == reverse (take n (reverse xs))

dropRev :: (Eq a) => Int -> [a] -> Bool
dropRev n xs =
   ListHT.dropRev n xs == reverse (drop n (reverse xs))


sieve :: Eq a => Int -> [a] -> Property
sieve n x =
   n>0 ==>
      equalLists [ListHT.sieve    n x,
                  ListHT.sieve'   n x,
                  ListHT.sieve''  n x,
                  ListHT.sieve''' n x]


sliceHorizontal :: Eq a => Int -> [a] -> Bool
sliceHorizontal n0 x =
   let n = 1 + mod n0 1000
   in  ListHT.sliceHorizontal n x == ListHT.sliceHorizontal' n x


sliceVertical :: Eq a => Int -> [a] -> Property
sliceVertical n x =
   n>0 ==>
      ListHT.sliceVertical n x == ListHT.sliceVertical' n x

slice :: Eq a => Int -> [a] -> a -> Bool
slice n0 as a =
   let x = a:as
       n = 1 + mod n0 (length x)
   in  -- problems: ListHT.sliceHorizontal 4 [] == [[],[],[],[]]
       ListHT.sliceHorizontal n x == List.transpose (ListHT.sliceVertical  n x)  &&
       ListHT.sliceVertical  n x == List.transpose (ListHT.sliceHorizontal n x)




shear :: Eq a => [[a]] -> Bool
shear xs =
   ListHT.shearTranspose xs  ==  map reverse (ListHT.shear xs)



outerProduct :: (Eq a, Eq b) => [a] -> [b] -> Bool
outerProduct xs ys =
   concat (ListHT.outerProduct (,) xs ys)  ==  liftM2 (,) xs ys



iterate :: Eq a => (a -> a -> a) -> a -> Bool
iterate op a =
   let xs = List.iterate (op a) a
       ys = ListHT.iterateAssociative op a
       zs = ListHT.iterateLeaky op a
   in  equalInfLists 1000 [xs, ys, zs]


mapAdjacent :: (Num a, Eq a) => a -> [a] -> Bool
mapAdjacent x xs =
   ListHT.mapAdjacent subtract (scanl (+) x xs) == xs


simple ::
   (Testable test) =>
   (Int -> [Integer] -> test) -> IO ()
simple = quickCheck


tests :: [(String, IO ())]
tests =
   ("takeWhileRev",     quickCheck (\a -> takeWhileRev ((a::Integer)>=))) :
   ("dropWhileRev",     quickCheck (\a -> dropWhileRev ((a::Integer)>=))) :
   ("takeRev",          simple takeRev) :
   ("dropRev",          simple dropRev) :
   ("sieve",            simple sieve) :
   ("sliceHorizontal",  simple sliceHorizontal) :
   ("sliceVertical",    simple sliceVertical) :
   ("slice",            simple slice) :
   ("shear",            quickCheck (shear           :: [[Integer]] -> Bool)) :
   ("outerProduct",     quickCheck (outerProduct    :: [Integer] -> [Int] -> Bool)) :
   ("iterate",          quickCheck (iterate (+)     :: Integer -> Bool)) :
   ("mapAdjacent",      quickCheck (mapAdjacent     :: Integer -> [Integer] -> Bool)) :
   []
