module Hpgsql.Base where

import Control.Monad (void)
import Data.Bifunctor (second)
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import Data.Maybe (mapMaybe)

headMaybe :: [a] -> Maybe a
headMaybe :: forall a. [a] -> Maybe a
headMaybe [] = Maybe a
forall a. Maybe a
Nothing
headMaybe (a
x : [a]
_) = a -> Maybe a
forall a. a -> Maybe a
Just a
x

lastMaybe :: [a] -> Maybe a
lastMaybe :: forall a. [a] -> Maybe a
lastMaybe [] = Maybe a
forall a. Maybe a
Nothing
lastMaybe [a
x] = a -> Maybe a
forall a. a -> Maybe a
Just a
x
lastMaybe (a
_ : [a]
xs) = [a] -> Maybe a
forall a. [a] -> Maybe a
lastMaybe [a]
xs

lastAndInit :: [a] -> ([a], Maybe a)
lastAndInit :: forall a. [a] -> ([a], Maybe a)
lastAndInit [a]
xs = case [a] -> Maybe (NonEmpty a)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty [a]
xs of
  Maybe (NonEmpty a)
Nothing -> ([], Maybe a
forall a. Maybe a
Nothing)
  Just NonEmpty a
nxs -> (a -> Maybe a) -> ([a], a) -> ([a], Maybe a)
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second a -> Maybe a
forall a. a -> Maybe a
Just (([a], a) -> ([a], Maybe a)) -> ([a], a) -> ([a], Maybe a)
forall a b. (a -> b) -> a -> b
$ NonEmpty a -> ([a], a)
forall a. NonEmpty a -> ([a], a)
lastAndInitNE NonEmpty a
nxs

lastAndInitNE :: NonEmpty a -> ([a], a)
lastAndInitNE :: forall a. NonEmpty a -> ([a], a)
lastAndInitNE (a
x :| [a]
xs) =
  case [a] -> Maybe (NonEmpty a)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty [a]
xs of
    Maybe (NonEmpty a)
Nothing -> ([], a
x)
    Just NonEmpty a
neXs ->
      let ([a]
others, a
l) = NonEmpty a -> ([a], a)
forall a. NonEmpty a -> ([a], a)
lastAndInitNE NonEmpty a
neXs
       in (a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
others, a
l)

-- | Only returns a Just for list with 2 or more elements,
-- and no element from the input is missing in the returned
-- value, and no element is repeated.
lastTwoAndInit :: [a] -> ([a], Maybe (a, a))
lastTwoAndInit :: forall a. [a] -> ([a], Maybe (a, a))
lastTwoAndInit [a]
xs = case [a] -> ([a], Maybe a)
forall a. [a] -> ([a], Maybe a)
lastAndInit [a]
xs of
  ([a]
l, Maybe a
Nothing) -> ([a]
l, Maybe (a, a)
forall a. Maybe a
Nothing)
  ([a]
l, Just a
lst) -> case [a] -> ([a], Maybe a)
forall a. [a] -> ([a], Maybe a)
lastAndInit [a]
l of
    ([a]
_, Maybe a
Nothing) -> ([a]
l [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
lst], Maybe (a, a)
forall a. Maybe a
Nothing)
    ([a]
l', Just a
secLst) -> ([a]
l', (a, a) -> Maybe (a, a)
forall a. a -> Maybe a
Just (a
secLst, a
lst))

whenNonEmpty :: [a] -> (NonEmpty a -> IO b) -> IO ()
whenNonEmpty :: forall a b. [a] -> (NonEmpty a -> IO b) -> IO ()
whenNonEmpty [] NonEmpty a -> IO b
_ = () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
whenNonEmpty (a
x : [a]
xs) NonEmpty a -> IO b
f = IO b -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO b -> IO ()) -> IO b -> IO ()
forall a b. (a -> b) -> a -> b
$ NonEmpty a -> IO b
f (a
x a -> [a] -> NonEmpty a
forall a. a -> [a] -> NonEmpty a
:| [a]
xs)

ifM :: IO Bool -> IO a -> IO a -> IO a
ifM :: forall a. IO Bool -> IO a -> IO a -> IO a
ifM IO Bool
cond IO a
fTrue IO a
fFalse = do
  v <- IO Bool
cond
  if v then fTrue else fFalse

-- | Takes the minimum of the Just values only, or the default if there are none.
minimumOnOrDef :: (Ord b) => b -> [a] -> (a -> Maybe b) -> b
minimumOnOrDef :: forall b a. Ord b => b -> [a] -> (a -> Maybe b) -> b
minimumOnOrDef b
def [a]
xs a -> Maybe b
f =
  case (a -> Maybe b) -> [a] -> [b]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe a -> Maybe b
f [a]
xs of
    [] -> b
def
    [b]
ls -> [b] -> b
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [b]
ls

-- | Takes the maximum of the Just values only, or the default if there are none.
maximumOnOrDef :: (Ord b) => b -> [a] -> (a -> Maybe b) -> b
maximumOnOrDef :: forall b a. Ord b => b -> [a] -> (a -> Maybe b) -> b
maximumOnOrDef b
def [a]
xs a -> Maybe b
f =
  case (a -> Maybe b) -> [a] -> [b]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe a -> Maybe b
f [a]
xs of
    [] -> b
def
    [b]
ls -> [b] -> b
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [b]
ls

whenJust :: (Applicative m) => Maybe a -> (a -> m ()) -> m ()
whenJust :: forall (m :: * -> *) a.
Applicative m =>
Maybe a -> (a -> m ()) -> m ()
whenJust Maybe a
m a -> m ()
f = case Maybe a
m of
  Maybe a
Nothing -> () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  Just a
v -> a -> m ()
f a
v

-- whenM :: IO Bool -> IO a -> IO ()
-- whenM cond f = do
--   v <- cond
--   when v $ void f