-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.


{-# LANGUAGE GADTs #-}
{-# LANGUAGE NoRebindableSyntax #-}
{-# LANGUAGE OverloadedStrings #-}

module Duckling.Time.EN.AU.Rules
  ( rules
  ) where

import Data.Maybe
import Prelude

import Duckling.Dimensions.Types
import Duckling.Numeral.Helpers (parseInt)
import Duckling.Regex.Types
import Duckling.Time.Computed (easterSunday)
import Duckling.Time.Helpers
import Duckling.Time.Types (TimeData (..))
import Duckling.Types
import qualified Duckling.Time.Types as TTime
import qualified Duckling.TimeGrain.Types as TG

ruleDDMM :: Rule
ruleDDMM :: Rule
ruleDDMM = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"dd/mm"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(3[01]|[12]\\d|0?[1-9])\\s?[/-]\\s?(1[0-2]|0?[1-9])"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (dd:mm:_)):[Token]
_) -> do
        Int
d <- Text -> Maybe Int
parseInt Text
dd
        Int
m <- Text -> Maybe Int
parseInt Text
mm
        TimeData -> Maybe Token
tt (TimeData -> Maybe Token) -> TimeData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Int -> Int -> TimeData
monthDay Int
m Int
d
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleDDMMYYYY :: Rule
ruleDDMMYYYY :: Rule
ruleDDMMYYYY = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"dd/mm/yyyy"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(3[01]|[12]\\d|0?[1-9])[-/\\s](1[0-2]|0?[1-9])[-/\\s](\\d{2,4})"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (dd:mm:yy:_)):[Token]
_) -> do
        Int
y <- Text -> Maybe Int
parseInt Text
yy
        Int
d <- Text -> Maybe Int
parseInt Text
dd
        Int
m <- Text -> Maybe Int
parseInt Text
mm
        TimeData -> Maybe Token
tt (TimeData -> Maybe Token) -> TimeData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int -> TimeData
yearMonthDay Int
y Int
m Int
d
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

-- Clashes with HHMMSS, hence only 4-digit years
ruleDDMMYYYYDot :: Rule
ruleDDMMYYYYDot :: Rule
ruleDDMMYYYYDot = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"dd.mm.yyyy"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(3[01]|[12]\\d|0?[1-9])\\.(1[0-2]|0?[1-9])\\.(\\d{4})"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
RegexMatch (GroupMatch (dd:mm:yy:_)):[Token]
_) -> do
        Int
y <- Text -> Maybe Int
parseInt Text
yy
        Int
d <- Text -> Maybe Int
parseInt Text
dd
        Int
m <- Text -> Maybe Int
parseInt Text
mm
        TimeData -> Maybe Token
tt (TimeData -> Maybe Token) -> TimeData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int -> TimeData
yearMonthDay Int
y Int
m Int
d
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

rulePeriodicHolidays :: [Rule]
rulePeriodicHolidays :: [Rule]
rulePeriodicHolidays = [(Text, String, TimeData)] -> [Rule]
mkRuleHolidays
  -- Fixed dates, year over year
  [ ( Text
"ANZAC Day", String
"anzac day", Int -> Int -> TimeData
monthDay Int
4 Int
25 )
  , ( Text
"Australia Day", String
"(ana|anniversary|australia|foundation) day"
    , Int -> Int -> TimeData
monthDay Int
1 Int
26 )
  , ( Text
"Harmony Day", String
"harmony day", Int -> Int -> TimeData
monthDay Int
3 Int
21 )
  , ( Text
"National Sorry Day", String
"national sorry day", Int -> Int -> TimeData
monthDay Int
5 Int
26 )
  , ( Text
"Queensland Day", String
"queensland day", Int -> Int -> TimeData
monthDay Int
6 Int
6 )
  , ( Text
"Remembrance Day", String
"remembrance day", Int -> Int -> TimeData
monthDay Int
11 Int
11 )
  , ( Text
"Take our Daughters and Sons to Work Day"
    , String
"take our daughters and sons to work day", Int -> Int -> TimeData
monthDay Int
1 Int
5 )

  -- Fixed day/week/month, year over year
  , ( Text
"Adelaide Cup", String
"adelaide cup", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
1 Int
3 )
  , ( Text
"Administrative Professionals' Day"
    , String
"(administrative professional|secretarie|admin)('?s'?)? day"
    , Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
5 Int
5 )
  , ( Text
"Canberra Day", String
"canberra day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
1 Int
3 )
  , ( Text
"Eight Hours Day", String
"eight hours day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
1 Int
3 )
  , ( Text
"Father's Day", String
"father'?s?'? day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
7 Int
9 )
  , ( Text
"Labour Day", String
"labour day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
1 Int
10 )
  , ( Text
"Melbourne Cup Day", String
"melbourne cup day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
2 Int
11 )
  , ( Text
"Mother's Day", String
"mother'?s?'? day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
7 Int
5 )
  , ( Text
"National Close the Gap Day", String
"national close the gap day"
    , Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
3 Int
4 Int
3 )
  , ( Text
"National Tree Day", String
"(arbor|national tree) day"
    , TimeData -> TimeData -> TimeData
predLastOf (Int -> TimeData
dayOfWeek Int
7) (Int -> TimeData
month Int
6) )
  , ( Text
"National Schools Tree Day", String
"national schools tree day"
    , TimeData -> TimeData -> TimeData
predLastOf (Int -> TimeData
dayOfWeek Int
5) (Int -> TimeData
month Int
6) )
  , ( Text
"New South Wales Bank Holiday", String
"new south wales bank holiday"
    , Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
1 Int
8 )
  , ( Text
"Picnic Day", String
"(northern territory )?picnic day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
1 Int
8 )
  , ( Text
"Recreation Day", String
"recreation day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
1 Int
10 )
  , ( Text
"Thanksgiving Day", String
"thanks?giving( day)?", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
4 Int
4 Int
11 )
  , ( Text
"Western Australia Day", String
"western australia day", Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
1 Int
6 )

  -- Other
  , ( Text
"Reconciliation Day", String
"reconciliation\\s+day"
    , Int -> TimeData -> TimeData -> TimeData
predNthAfter Int
0 (Int -> TimeData
dayOfWeek Int
1) (Int -> Int -> TimeData
monthDay Int
5 Int
26) )
  ]

rulePeriodicHolidays' :: [Rule]
rulePeriodicHolidays' :: [Rule]
rulePeriodicHolidays' = [(Text, String, Maybe TimeData)] -> [Rule]
mkRuleHolidays'
  -- Fixed day/week/month, year over year
  -- Week from Sunday of July until following Sunday that has the second Friday
  [ ( Text
"NAIDOC Week"
    , String
"(naidoc|national aboriginal and islander day observance committee) week"
    , let fri :: TimeData
fri = Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
5 Int
7
          start :: TimeData
start = Bool -> Grain -> Int -> TimeData -> TimeData
cycleNthAfter Bool
False Grain
TG.Day (- Int
5) TimeData
fri
          end :: TimeData
end = Bool -> Grain -> Int -> TimeData -> TimeData
cycleNthAfter Bool
False Grain
TG.Day Int
2 TimeData
fri
      in TimeIntervalType -> TimeData -> TimeData -> Maybe TimeData
interval TimeIntervalType
TTime.Open TimeData
start TimeData
end )
  -- 3 days ending on the second Monday of February
  , ( Text
"Royal Hobart Regatta", String
"royal hobart regatta"
    , let end :: TimeData
end = Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
1 Int
2
      in TimeIntervalType -> TimeData -> TimeData -> Maybe TimeData
interval TimeIntervalType
TTime.Open (Bool -> Grain -> Int -> TimeData -> TimeData
cycleNthAfter Bool
False Grain
TG.Day (- Int
2) TimeData
end) TimeData
end )

  -- Other
  -- Wednesday of the Royal Queensland Show
  -- Starts on the first Friday of August if it's not before August 5th
  -- Otherwise on the second Friday of August
  , ( Text
"Royal Queensland Show Day"
    , String
"(royal (national agricultural|queensland)|rna) show day|ekka day"
    , let tentative :: TimeData
tentative = Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
5 Int
8
          alternative :: TimeData
alternative = Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
5 Int
8
      in do
        TimeData
forbidden <- TimeIntervalType -> TimeData -> TimeData -> Maybe TimeData
interval TimeIntervalType
TTime.Open (Int -> Int -> TimeData
monthDay Int
8 Int
1) (Int -> Int -> TimeData
monthDay Int
8 Int
4)
        TimeData
start <- TimeData -> TimeData -> TimeData -> Maybe TimeData
intersectWithReplacement TimeData
forbidden TimeData
tentative TimeData
alternative
        TimeData -> Maybe TimeData
forall (m :: * -> *) a. Monad m => a -> m a
return (TimeData -> Maybe TimeData) -> TimeData -> Maybe TimeData
forall a b. (a -> b) -> a -> b
$ Bool -> Grain -> Int -> TimeData -> TimeData
cycleNthAfter Bool
False Grain
TG.Day Int
5 TimeData
start )
  -- Starts on the first Friday of August if it's not before August 5th
  -- Otherwise on the second Friday of August
  , ( Text
"Royal Queensland Show"
    , String
"ekka|(royal (national agricultural|queensland)|rna) show"
    , let tentative :: TimeData
tentative = Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
1 Int
5 Int
8
          alternative :: TimeData
alternative = Int -> Int -> Int -> TimeData
nthDOWOfMonth Int
2 Int
5 Int
8
      in do
        TimeData
forbidden <- TimeIntervalType -> TimeData -> TimeData -> Maybe TimeData
interval TimeIntervalType
TTime.Open (Int -> Int -> TimeData
monthDay Int
8 Int
1) (Int -> Int -> TimeData
monthDay Int
8 Int
4)
        TimeData
start <- TimeData -> TimeData -> TimeData -> Maybe TimeData
intersectWithReplacement TimeData
forbidden TimeData
tentative TimeData
alternative
        TimeIntervalType -> TimeData -> TimeData -> Maybe TimeData
interval TimeIntervalType
TTime.Open TimeData
start (TimeData -> Maybe TimeData) -> TimeData -> Maybe TimeData
forall a b. (a -> b) -> a -> b
$ Bool -> Grain -> Int -> TimeData -> TimeData
cycleNthAfter Bool
False Grain
TG.Day Int
9 TimeData
start )
  ]

ruleComputedHolidays :: [Rule]
ruleComputedHolidays :: [Rule]
ruleComputedHolidays = [(Text, String, TimeData)] -> [Rule]
mkRuleHolidays
  [ ( Text
"Easter Tuesday", String
"easter\\s+tue(sday)?"
    , Bool -> Grain -> Int -> TimeData -> TimeData
cycleNthAfter Bool
False Grain
TG.Day Int
2 TimeData
easterSunday )
  ]

rules :: [Rule]
rules :: [Rule]
rules =
  [ Rule
ruleDDMM
  , Rule
ruleDDMMYYYY
  , Rule
ruleDDMMYYYYDot
  ]
  [Rule] -> [Rule] -> [Rule]
forall a. [a] -> [a] -> [a]
++ [Rule]
ruleComputedHolidays
  [Rule] -> [Rule] -> [Rule]
forall a. [a] -> [a] -> [a]
++ [Rule]
rulePeriodicHolidays
  [Rule] -> [Rule] -> [Rule]
forall a. [a] -> [a] -> [a]
++ [Rule]
rulePeriodicHolidays'