{-# LANGUAGE UnicodeSyntax, Rank2Types #-}
-- | Collection of functions of more general purpose.
module SoccerFun.Prelude 	where

import Data.Maybe
import Control.Monad.Identity


fst3 (x,y,z) = x
snd3 (x,y,z) = y
thd3 (x,y,z) = z

avg  Fractional a  [a]  a
avg xs = sum xs / fromIntegral (length xs)

zero  Num a  a
zero = fromIntegral 0

one  Num a  a
one = fromIntegral 1

iterateStn  Int  (s  (a,s))  s  ([a],s)
iterateStn 0 _ s	= ([],s)
iterateStn n f s = runIdentity $ do
	(a, s)		 return $ f s
	(as,s)		 return $ iterateStn (n-1) f s
	return $ ((a:as),s)

singleOutElems  [a]  [(a,[a])]
singleOutElems as = singleOut [] as where
	singleOut  [a]  [a]  [(a,[a])]
	singleOut _ [] = []
	singleOut prefix (a:as)= ((a,prefix++as) : singleOut (prefix++[a]) as)

-- | spanfilter cond xs = (filter cond xs, filter (not . cond) xs)
spanfilter  (a  Bool)  [a]  ([a],[a])
spanfilter cond []
	= ([],[])
spanfilter cond (x:xs)
	| cond x	= ((x:yes),no)
	| otherwise	= (yes,(x:no))
	where
	(yes,no)	= spanfilter cond xs

spanfilterSt  (a  s  (Bool,s))  [a]  s  (([a],[a]),s)
spanfilterSt cond [] s
	= (([],[]),s)
spanfilterSt cond (x:xs) s = runIdentity $ do
	(ok,s)		 return $ cond x s
	((yes,no),s)	 return $ spanfilterSt cond xs s
	return $ if ok	then (((x:yes),no),s) else ((yes,(x:no)),s)

{-| break cond (A ++ B ++ C) = (A,B,C)
		where for each x in A: not cond x     /\
	      for each x in B:     cond x     /\
	      if C=(x:_):      not cond x
-}
break'  (a  Bool)  [a]  ([a],[a],[a])
break' c xs = let
		(no,yes)	 = span (not . c) xs
		(yes',no') = span c yes
	in (no,yes',no')

{-| break1 cond (A ++ [B] ++ C) = (A,B,C)
		where for each x in A: not cond x     /\
	                           cond B     /\
	      if C=(x:_):      not cond x
-}
break1  (a  Bool)  [a]  ([a],a,[a])
break1 c xs
	= case break' c xs of
		(a,[b],c)	 (a,b,c)
		(a,b,c)		 error ("break1: [B] is of length: " ++ show (length b) ++ "\n")

-- | unbreak (a,b,c) = a ++ b ++ c
unbreak  ([a],[a],[a])  [a]
unbreak (a,b,c) = a ++ b ++ c


-- | unbreak1 (a,b,c) = a ++ [b] ++ c
unbreak1  ([a],a,[a])  [a]
unbreak1 (a,b,c) = a ++ [b] ++ c

{- [a1..x..aN] x = i
		where
		aJ /= x for all j<i
		aJ == x for j==i
-}
--(??) infixl 9 ∷ [a] → a → Int | == a
--(??) ys x = search ((==) x) ys 0
--
--(???) infixl 9 ∷ [a] → (a → Bool) → Int
--(???) ys c = search c ys 0

type AssocList k v = [(k,v)]

boundedBy  Ord a  a  (a,a)  a
boundedBy x (low,up)
	| low > x	= low
	| x > up	= up
	| otherwise	= x

{-| isbetween x low up
		returns True iff low <= x <= up
-}
isbetween  Ord a  a  a  a  Bool
isbetween x low up
	= low <= x && x <= up

-- | minmax (a,b) = (a,b) if a<=b; (b,a) otherwise
minmax  Ord a  (a,a)  (a,a)
minmax (a,b)
	| a<=b		= (a,b)
	| otherwise	= (b,a)

-- | perhaps p Nothing = False, and perhaps p (Just a) = p a
perhaps  (a  Bool)  (Maybe a)  Bool
perhaps p = maybe False p

removeMember  (Eq a)  a  [a]  [a]
removeMember x = filter (/= x)

removeMembers  (Eq a)  [a]  [a]  [a]
removeMembers xs ys = foldr removeMember xs ys