-- | @since 0.1
module Kairos.Types.Exception
  ( ParseTimeException (..),
    ParseTZInputException (..),
    LocalTimeZoneException (..),
    LocalTZException (..),
    LocalSystemTimeException (..),
    SrcTZNoTimeStringException (..),
    DateNoTimeStringException (..),
  )
where

import Control.DeepSeq (NFData)
import Control.Exception (Exception (displayException))
import Data.List.NonEmpty (NonEmpty)
import Data.Text (Text)
import Data.Text qualified as T
import GHC.Generics (Generic)
import Kairos.Types.TimeFormat (TimeFormat (unTimeFormat))

-- | Exception parsing time string.
--
-- @since 0.1
data ParseTimeException = MkParseTimeException (NonEmpty TimeFormat) Text
  deriving stock
    ( -- | @since 0.1
      (forall x. ParseTimeException -> Rep ParseTimeException x)
-> (forall x. Rep ParseTimeException x -> ParseTimeException)
-> Generic ParseTimeException
forall x. Rep ParseTimeException x -> ParseTimeException
forall x. ParseTimeException -> Rep ParseTimeException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ParseTimeException -> Rep ParseTimeException x
from :: forall x. ParseTimeException -> Rep ParseTimeException x
$cto :: forall x. Rep ParseTimeException x -> ParseTimeException
to :: forall x. Rep ParseTimeException x -> ParseTimeException
Generic,
      -- | @since 0.1
      Int -> ParseTimeException -> ShowS
[ParseTimeException] -> ShowS
ParseTimeException -> String
(Int -> ParseTimeException -> ShowS)
-> (ParseTimeException -> String)
-> ([ParseTimeException] -> ShowS)
-> Show ParseTimeException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ParseTimeException -> ShowS
showsPrec :: Int -> ParseTimeException -> ShowS
$cshow :: ParseTimeException -> String
show :: ParseTimeException -> String
$cshowList :: [ParseTimeException] -> ShowS
showList :: [ParseTimeException] -> ShowS
Show
    )
  deriving anyclass
    ( -- | @since 0.1
      ParseTimeException -> ()
(ParseTimeException -> ()) -> NFData ParseTimeException
forall a. (a -> ()) -> NFData a
$crnf :: ParseTimeException -> ()
rnf :: ParseTimeException -> ()
NFData
    )

-- | @since 0.1
instance Exception ParseTimeException where
  displayException :: ParseTimeException -> String
displayException (MkParseTimeException NonEmpty TimeFormat
fmts Text
t) =
    [String] -> String
forall a. Monoid a => [a] -> a
mconcat
      [ String
"Could not parse time string '",
        Text -> String
T.unpack Text
t,
        String
"' with format(s): ",
        String
fmtStrs
      ]
    where
      fmtStrs :: String
fmtStrs = (TimeFormat -> String) -> NonEmpty TimeFormat -> String
forall m a. Monoid m => (a -> m) -> NonEmpty a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Text -> String
T.unpack (Text -> String) -> (TimeFormat -> Text) -> TimeFormat -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"\n - " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) (Text -> Text) -> (TimeFormat -> Text) -> TimeFormat -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (.unTimeFormat)) NonEmpty TimeFormat
fmts

-- | Exception parsing tz input names.
--
-- @since 0.1
newtype ParseTZInputException = MkParseTZInputException Text
  deriving stock
    ( -- | @since 0.1
      (forall x. ParseTZInputException -> Rep ParseTZInputException x)
-> (forall x. Rep ParseTZInputException x -> ParseTZInputException)
-> Generic ParseTZInputException
forall x. Rep ParseTZInputException x -> ParseTZInputException
forall x. ParseTZInputException -> Rep ParseTZInputException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ParseTZInputException -> Rep ParseTZInputException x
from :: forall x. ParseTZInputException -> Rep ParseTZInputException x
$cto :: forall x. Rep ParseTZInputException x -> ParseTZInputException
to :: forall x. Rep ParseTZInputException x -> ParseTZInputException
Generic,
      -- | @since 0.1
      Int -> ParseTZInputException -> ShowS
[ParseTZInputException] -> ShowS
ParseTZInputException -> String
(Int -> ParseTZInputException -> ShowS)
-> (ParseTZInputException -> String)
-> ([ParseTZInputException] -> ShowS)
-> Show ParseTZInputException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ParseTZInputException -> ShowS
showsPrec :: Int -> ParseTZInputException -> ShowS
$cshow :: ParseTZInputException -> String
show :: ParseTZInputException -> String
$cshowList :: [ParseTZInputException] -> ShowS
showList :: [ParseTZInputException] -> ShowS
Show
    )
  deriving anyclass
    ( -- | @since 0.1
      ParseTZInputException -> ()
(ParseTZInputException -> ()) -> NFData ParseTZInputException
forall a. (a -> ()) -> NFData a
$crnf :: ParseTZInputException -> ()
rnf :: ParseTZInputException -> ()
NFData
    )

-- | @since 0.1
instance Exception ParseTZInputException where
  displayException :: ParseTZInputException -> String
displayException (MkParseTZInputException Text
tzdb) =
    String
"Could not parse timezone from '"
      String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
tzdb
      String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"'. Wanted a name or offset e.g. 'America/New_York', '+0800'."

-- | Exception reading local system timezone.
--
-- @since 0.1
data LocalTimeZoneException
  = forall e. (Exception e) => MkLocalTimeZoneException e

-- | @since 0.1
deriving stock instance Show LocalTimeZoneException

-- | @since 0.1
instance Exception LocalTimeZoneException where
  displayException :: LocalTimeZoneException -> String
displayException (MkLocalTimeZoneException e
e) =
    String
"Local timezone exception: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> e -> String
forall e. Exception e => e -> String
displayException e
e

-- | Exception reading local system tz. In contrast to
-- 'LocalTimeZoneException', this is for when we try and fail to find
-- the local tz_database name e.g. America/New_York.
--
-- @since 0.1
data LocalTZException = forall e. (Exception e) => MkLocalTZException e

-- | @since 0.1
deriving stock instance Show LocalTZException

-- | @since 0.1
instance Exception LocalTZException where
  displayException :: LocalTZException -> String
displayException (MkLocalTZException e
e) =
    [String] -> String
forall a. Monoid a => [a] -> a
mconcat
      [ String
"Could not find local tz_database name: ",
        e -> String
forall e. Exception e => e -> String
displayException e
e,
        String
"\nTry again, explictly setting your location e.g. ",
        String
"'-s america/new_york'."
      ]

-- | Exception reading local system time.
--
-- @since 0.1
data LocalSystemTimeException
  = forall e. (Exception e) => MkLocalSystemTimeException e

-- | @since 0.1
deriving stock instance Show LocalSystemTimeException

-- | @since 0.1
instance Exception LocalSystemTimeException where
  displayException :: LocalSystemTimeException -> String
displayException (MkLocalSystemTimeException e
e) =
    String
"Local system time exception: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> e -> String
forall e. Exception e => e -> String
displayException e
e

-- | Exception for when --src-tz is specified but time string is not.
--
-- @since 0.1
data SrcTZNoTimeStringException = MkSrcTZNoTimeStringException
  deriving stock
    ( -- | @since 0.1
      Int -> SrcTZNoTimeStringException -> ShowS
[SrcTZNoTimeStringException] -> ShowS
SrcTZNoTimeStringException -> String
(Int -> SrcTZNoTimeStringException -> ShowS)
-> (SrcTZNoTimeStringException -> String)
-> ([SrcTZNoTimeStringException] -> ShowS)
-> Show SrcTZNoTimeStringException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SrcTZNoTimeStringException -> ShowS
showsPrec :: Int -> SrcTZNoTimeStringException -> ShowS
$cshow :: SrcTZNoTimeStringException -> String
show :: SrcTZNoTimeStringException -> String
$cshowList :: [SrcTZNoTimeStringException] -> ShowS
showList :: [SrcTZNoTimeStringException] -> ShowS
Show
    )

-- | @since 0.1
instance Exception SrcTZNoTimeStringException where
  displayException :: SrcTZNoTimeStringException -> String
displayException SrcTZNoTimeStringException
MkSrcTZNoTimeStringException =
    String
"The --src-tz option was specified without required time string"

-- | Exception for when --date specified but time string is not.
--
-- @since 0.1
data DateNoTimeStringException = MkDateNoTimeStringException
  deriving stock
    ( -- | @since 0.1
      Int -> DateNoTimeStringException -> ShowS
[DateNoTimeStringException] -> ShowS
DateNoTimeStringException -> String
(Int -> DateNoTimeStringException -> ShowS)
-> (DateNoTimeStringException -> String)
-> ([DateNoTimeStringException] -> ShowS)
-> Show DateNoTimeStringException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DateNoTimeStringException -> ShowS
showsPrec :: Int -> DateNoTimeStringException -> ShowS
$cshow :: DateNoTimeStringException -> String
show :: DateNoTimeStringException -> String
$cshowList :: [DateNoTimeStringException] -> ShowS
showList :: [DateNoTimeStringException] -> ShowS
Show
    )

-- | @since 0.1
instance Exception DateNoTimeStringException where
  displayException :: DateNoTimeStringException -> String
displayException DateNoTimeStringException
MkDateNoTimeStringException =
    String
"The --date option was specified without required time string"