module Main (main) where

import TestUtils
import EvalIntExpr (testEvalIntExpr)
import EvalIdExpr (testEvalIdExpr)
import EvalMaybeExpr (testEvalMaybeExpr)
import PostfixExpr (testPostfixExpr)

import Test.QuickCheck


toSingletonLists :: [e] -> [[e]]
toSingletonLists xs = map (\x -> [x]) xs

testToSingletonLists = do
  print "******* toSingletonLists"
  quickCheck $ counterexample "ints" $
    toSingletonLists [ 5, 7, 2 ] == [ [5], [7], [2] ]
  quickCheck $ counterexample "chars" $
    toSingletonLists [ 'a', 'x', 'd' ] == [ "a", "x", "d" ]
  quickCheck $ counterexample "empty" $
    toSingletonLists [] == ([] :: [[Int]])


listMap :: (a -> b -> c) -> a -> [b] -> [c]
listMap f a xs = map (\x -> f a x) xs

testListMap = do
  print "******* listMap"
  quickCheck $ counterexample "add" $ listMap (+) 5 [1, 2, 3] == [6, 7, 8]
  quickCheck $ counterexample "sub" $ listMap (-) 5 [1, 2, 3] == [4, 3, 2]
  quickCheck $ counterexample "mul" $ listMap (*) 5 [1, 2, 3] == [5, 10, 15]
  quickCheck $ counterexample "empty" $ listMap (-) 5 [] == []


member :: Eq e => e -> [e] -> Bool
member e ls = foldl (\acc x -> acc || x == e) False ls

testMember = do
  print "******* member"
  quickCheck $ counterexample "ints first" $  member 5 [ 5, 7, 2 ] == True
  quickCheck $ counterexample "ints last" $  member 2 [ 5, 7, 2 ] == True
  quickCheck $ counterexample "ints mid" $  member 7 [ 5, 7, 2 ] == True
  quickCheck $ counterexample "ints fail" $  member 4 [ 5, 7, 2 ] == False
  quickCheck $ counterexample "empty" $  member 4 [] == False


selectNApart :: Int -> [e] -> [e]
selectNApart _ [] = []
selectNApart n (x:xs)
  | n > 0     = x : selectNApart n (drop (n-1) xs)
  | otherwise = x : selectNApart (n+1) xs

testSelectNApart = do
  print "******* selectNApart"
  quickCheck $ counterexample "2-apart" $
    selectNApart 2 [0..10] == [0, 2, 4, 6, 8, 10]
  quickCheck $ counterexample "2-apart chars" $
    selectNApart 2 ['a'..'z'] == "acegikmoqsuwy"
  quickCheck $ counterexample "3-apart" $
    selectNApart 3 [0..20] == [0, 3, 6, 9, 12, 15, 18]
  quickCheck $ counterexample "5-apart" $
    selectNApart 5 [0..21] == [0, 5, 10, 15, 20]
  quickCheck $ counterexample "empty" $ selectNApart 5 ([]::[Int]) == []


------------------------ Functions in Separate Files --------------------

-- #5: 15-points
-- implement the specified function in EvalIntExpr.hs

-- #6: 15-points
-- implement the specified function in EvalIdExpr.hs

-- #7: 20-points
-- implement the specified function in EvalMaybeExpr.hs

-- #8: 20-points
-- implement the specified function in PostfixExpr.hs

--------------------------------- Tests ---------------------------------

-- Can mark test suites with following test statuses:
--   Only:  run only these tests and other tests marked Only.
--   Run:   run these tests when no tests are marked Only.
--   Skip:  skip these tests.
allTests = [
    (Run testToSingletonLists),
    (Run testListMap),
    (Run testMember),
    (Run testSelectNApart),
    (Run testEvalIntExpr),
    (Run testEvalIdExpr),
    (Run testEvalMaybeExpr),
    (Run testPostfixExpr)
  ]


main = do
  mapM_ id tests
  where
    only = onlyTests allTests
    tests = if (length only > 0) then only else runTests allTests