{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
#if __GLASGOW_HASKELL__ == 706
{-# OPTIONS_GHC -fsimpl-tick-factor=120 #-} -- 7.6.3 only, it seems; fixes #29
#endif

#include "thyme.h"
#if HLINT
#include "cabal_macros.h"
#endif

-- | Various Week Date formats
module Data.Thyme.Calendar.WeekDate
    ( Year, WeekOfYear, DayOfWeek
    -- * ISO 8601 Week Date
    , WeekDate (..), _wdYear, _wdWeek, _wdDay
    , weekDate, weekDateValid, showWeekDate

    -- * Weeks starting Sunday
    , SundayWeek (..), _swYear, _swWeek, _swDay
    , sundayWeek, sundayWeekValid

    -- * Weeks starting Monday
    , MondayWeek (..), _mwYear, _mwWeek, _mwDay
    , mondayWeek, mondayWeekValid

    , module Data.Thyme.Calendar.WeekDate
    ) where

import Prelude
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative
#endif
import Control.Arrow
import Control.Lens
import Data.Thyme.Calendar.OrdinalDate
import Data.Thyme.Calendar.Internal
import System.Random
import Test.QuickCheck

instance Bounded WeekDate where
    minBound :: WeekDate
minBound = forall a. Bounded a => a
minBound forall s a. s -> Getting a s a -> a
^. Iso' Day WeekDate
weekDate
    maxBound :: WeekDate
maxBound = forall a. Bounded a => a
maxBound forall s a. s -> Getting a s a -> a
^. Iso' Day WeekDate
weekDate

instance Bounded SundayWeek where
    minBound :: SundayWeek
minBound = forall a. Bounded a => a
minBound forall s a. s -> Getting a s a -> a
^. Iso' Day SundayWeek
sundayWeek
    maxBound :: SundayWeek
maxBound = forall a. Bounded a => a
maxBound forall s a. s -> Getting a s a -> a
^. Iso' Day SundayWeek
sundayWeek

instance Bounded MondayWeek where
    minBound :: MondayWeek
minBound = forall a. Bounded a => a
minBound forall s a. s -> Getting a s a -> a
^. Iso' Day MondayWeek
mondayWeek
    maxBound :: MondayWeek
maxBound = forall a. Bounded a => a
maxBound forall s a. s -> Getting a s a -> a
^. Iso' Day MondayWeek
mondayWeek

instance Random WeekDate where
    randomR :: forall g. RandomGen g => (WeekDate, WeekDate) -> g -> (WeekDate, g)
randomR = forall s g a.
(Random s, RandomGen g) =>
Iso' s a -> (a, a) -> g -> (a, g)
randomIsoR Iso' Day WeekDate
weekDate
    random :: forall g. RandomGen g => g -> (WeekDate, g)
random = forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (forall s a. s -> Getting a s a -> a
^. Iso' Day WeekDate
weekDate) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a g. (Random a, RandomGen g) => g -> (a, g)
random

instance Random SundayWeek where
    randomR :: forall g.
RandomGen g =>
(SundayWeek, SundayWeek) -> g -> (SundayWeek, g)
randomR = forall s g a.
(Random s, RandomGen g) =>
Iso' s a -> (a, a) -> g -> (a, g)
randomIsoR Iso' Day SundayWeek
sundayWeek
    random :: forall g. RandomGen g => g -> (SundayWeek, g)
random = forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (forall s a. s -> Getting a s a -> a
^. Iso' Day SundayWeek
sundayWeek) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a g. (Random a, RandomGen g) => g -> (a, g)
random

instance Random MondayWeek where
    randomR :: forall g.
RandomGen g =>
(MondayWeek, MondayWeek) -> g -> (MondayWeek, g)
randomR = forall s g a.
(Random s, RandomGen g) =>
Iso' s a -> (a, a) -> g -> (a, g)
randomIsoR Iso' Day MondayWeek
mondayWeek
    random :: forall g. RandomGen g => g -> (MondayWeek, g)
random = forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (forall s a. s -> Getting a s a -> a
^. Iso' Day MondayWeek
mondayWeek) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a g. (Random a, RandomGen g) => g -> (a, g)
random

instance Arbitrary WeekDate where
    arbitrary :: Gen WeekDate
arbitrary = forall a s. Getting a s a -> s -> a
view Iso' Day WeekDate
weekDate forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => Gen a
arbitrary
    shrink :: WeekDate -> [WeekDate]
shrink WeekDate
wd = forall a s. Getting a s a -> s -> a
view Iso' Day WeekDate
weekDate forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => a -> [a]
shrink (Iso' Day WeekDate
weekDate forall s t a b. AReview s t a b -> b -> t
# WeekDate
wd)

instance Arbitrary SundayWeek where
    arbitrary :: Gen SundayWeek
arbitrary = forall a s. Getting a s a -> s -> a
view Iso' Day SundayWeek
sundayWeek forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => Gen a
arbitrary
    shrink :: SundayWeek -> [SundayWeek]
shrink SundayWeek
sw = forall a s. Getting a s a -> s -> a
view Iso' Day SundayWeek
sundayWeek forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => a -> [a]
shrink (Iso' Day SundayWeek
sundayWeek forall s t a b. AReview s t a b -> b -> t
# SundayWeek
sw)

instance Arbitrary MondayWeek where
    arbitrary :: Gen MondayWeek
arbitrary = forall a s. Getting a s a -> s -> a
view Iso' Day MondayWeek
mondayWeek forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => Gen a
arbitrary
    shrink :: MondayWeek -> [MondayWeek]
shrink MondayWeek
mw = forall a s. Getting a s a -> s -> a
view Iso' Day MondayWeek
mondayWeek forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Arbitrary a => a -> [a]
shrink (Iso' Day MondayWeek
mondayWeek forall s t a b. AReview s t a b -> b -> t
# MondayWeek
mw)

instance CoArbitrary WeekDate where
    coarbitrary :: forall b. WeekDate -> Gen b -> Gen b
coarbitrary (WeekDate Year
y Year
w Year
d)
        = forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
y forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
w forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
d

instance CoArbitrary SundayWeek where
    coarbitrary :: forall b. SundayWeek -> Gen b -> Gen b
coarbitrary (SundayWeek Year
y Year
w Year
d)
        = forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
y forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
w forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
d

instance CoArbitrary MondayWeek where
    coarbitrary :: forall b. MondayWeek -> Gen b -> Gen b
coarbitrary (MondayWeek Year
y Year
w Year
d)
        = forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
y forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
w forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary Year
d

-- * Compatibility

-- | Converts a 'Day' to an <https://en.wikipedia.org/wiki/ISO_week_date ISO week date>.
--
-- @
-- 'toWeekDate' ('view' 'weekDate' -> 'WeekDate' y w d) = (y, w, d)
-- @
{-# INLINE toWeekDate #-}
toWeekDate :: Day -> (Year, WeekOfYear, DayOfWeek)
toWeekDate :: Day -> (Year, Year, Year)
toWeekDate (forall a s. Getting a s a -> s -> a
view Iso' Day WeekDate
weekDate -> WeekDate Year
y Year
w Year
d) = (Year
y, Year
w, Year
d)

-- | Converts an <https://en.wikipedia.org/wiki/ISO_week_date ISO week date>
-- to a 'Day'.
-- Does not validate the input.
--
-- @
-- 'fromWeekDate' y w d = 'weekDate' 'Control.Lens.#' 'WeekDate' y w d
-- @
{-# INLINE fromWeekDate #-}
fromWeekDate :: Year -> WeekOfYear -> DayOfWeek -> Day
fromWeekDate :: Year -> Year -> Year -> Day
fromWeekDate Year
y Year
w Year
d = Iso' Day WeekDate
weekDate forall s t a b. AReview s t a b -> b -> t
# Year -> Year -> Year -> WeekDate
WeekDate Year
y Year
w Year
d

-- | Converts an <https://en.wikipedia.org/wiki/ISO_week_date ISO week date>
-- to a 'Day'.
-- Returns 'Nothing' for invalid input.
--
-- @
-- 'fromWeekDateValid' y w d = 'weekDateValid' ('WeekDate' y w d)
-- @
{-# INLINE fromWeekDateValid #-}
fromWeekDateValid :: Year -> WeekOfYear -> DayOfWeek -> Maybe Day
fromWeekDateValid :: Year -> Year -> Year -> Maybe Day
fromWeekDateValid Year
y Year
w Year
d = WeekDate -> Maybe Day
weekDateValid (Year -> Year -> Year -> WeekDate
WeekDate Year
y Year
w Year
d)