{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ConstraintKinds  #-}
{-# LANGUAGE CPP              #-}

-- | Internal utilities.
module Safe.Util(
    fromNoteModule, fromNoteEitherModule,
    liftMay,
    (.^), (.^^), (.^^^),
    eitherToMaybe,
    withFrozenCallStack
    ) where

import Data.Maybe
import Safe.Partial

-- Let things work through ghci alone
#if __GLASGOW_HASKELL__ >= 800
import GHC.Stack
#else
withFrozenCallStack :: a -> a
withFrozenCallStack = id
#endif


(.^) :: Partial => (b -> c) -> (a1 -> a2 -> b) -> a1 -> a2 -> c
(.^) f g x1 x2 = f (g x1 x2)

(.^^) :: Partial => (b -> c) -> (a1 -> a2 -> a3 -> b) -> a1 -> a2 -> a3 -> c
(.^^) f g x1 x2 x3 = f (g x1 x2 x3)

(.^^^) :: Partial => (b -> c) -> (a1 -> a2 -> a3 -> a4 -> b) -> a1 -> a2 -> a3 -> a4 -> c
(.^^^) f g x1 x2 x3 x4 = f (g x1 x2 x3 x4)

liftMay :: (a -> Bool) -> (a -> b) -> (a -> Maybe b)
liftMay test func val = if test val then Nothing else Just $ func val

fromNoteModule :: Partial => String -> String -> String -> Maybe a -> a
fromNoteModule modu note func = fromMaybe (error msg)
    where msg = modu ++ "." ++ func ++ (if null note then "" else ", " ++ note)

fromNoteEitherModule :: Partial => String -> String -> String -> Either String a -> a
fromNoteEitherModule modu note func = either (error . msg) id
    where msg ex = modu ++ "." ++ func ++ " " ++ ex ++ (if null note then "" else ", " ++ note)

eitherToMaybe :: Either a b -> Maybe b
eitherToMaybe = either (const Nothing) Just