-- 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 OverloadedStrings #-}

module Duckling.Time.FR.Corpus
  ( corpus
  , negativeCorpus
  ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Resolve
import Duckling.Testing.Types hiding (examples)
import Duckling.Time.Corpus
import Duckling.Time.Types hiding (Month)
import Duckling.TimeGrain.Types hiding (add)

corpus :: Corpus
corpus = (testContext {locale = makeLocale FR Nothing}, testOptions, allExamples)

negativeCorpus :: NegativeCorpus
negativeCorpus = (testContext {locale = makeLocale FR Nothing}, testOptions, examples)
  where
    examples =
      [ "Ana a un court de tennis"
      , "deux trois"
      , "deux trois minutes"
      , "74"
      ]

allExamples :: [Example]
allExamples = concat
  [ examples (datetime (2013, 2, 12, 4, 30, 0) Second)
             [ "maintenant"
             , "tout de suite"
             ]
  , examples (datetime (2013, 2, 12, 0, 0, 0) Day)
             [ "aujourd'hui"
             , "ce jour"
             , "dans la journÃ©e"
             , "en ce moment"
             ]
  , examples (datetime (2013, 2, 11, 0, 0, 0) Day)
             [ "hier"
             , "le jour d'avant"
             , "le jour prÃ©cÃ©dent"
             , "la veille"
             ]
  , examples (datetime (2013, 2, 10, 0, 0, 0) Day)
             [ "avant-hier"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "demain"
             , "jour suivant"
             , "le jour d'aprÃ¨s"
             , "le lendemain"
             , "un jour aprÃ¨s"
             ]
  , examples (datetime (2013, 2, 14, 0, 0, 0) Day)
             [ "aprÃ¨s-demain"
             , "le lendemain du 13 fÃ©vrier"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "lundi"
             , "lun."
             , "ce lundi"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "lundi 18 fÃ©vrier"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "mardi"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "mercredi 13 fÃ©vrier"
             ]
  , examples (datetime (2013, 2, 14, 0, 0, 0) Day)
             [ "jeudi"
             , "deux jours plus tard"
             , "deux jours aprÃ¨s"
             ]
  , examples (datetime (2013, 2, 15, 0, 0, 0) Day)
             [ "vendredi"
             ]
  , examples (datetime (2013, 2, 16, 0, 0, 0) Day)
             [ "samedi"
             ]
  , examples (datetime (2013, 2, 17, 0, 0, 0) Day)
             [ "dimanche"
             ]
  , examples (datetime (2013, 3, 1, 0, 0, 0) Day)
             [ "le 1er mars"
             , "premier mars"
             , "le 1 mars"
             , "vendredi 1er mars"
             ]
  , examples (datetime (2013, 3, 1, 0, 0, 0) Day)
             [ "le premier mars 2013"
             , "1/3/2013"
             , "2013-03-01"
             ]
  , examples (datetime (2013, 3, 2, 0, 0, 0) Day)
             [ "le 2 mars"
             , "2 mars"
             , "le 2/3"
             ]
  , examples (datetime (2013, 7, 5, 0, 0, 0) Day)
             [ "le 5 juillet"
             , "5 juillet"
             , "5 juil"
             , "5 jui"
             , "5 juil."
             , "5 jui."
             ]
  , examples (datetime (2013, 3, 2, 5, 0, 0) Hour)
             [ "le 2 mars Ã  5h"
             , "2 mars Ã  5h"
             , "le 2/3 Ã  5h"
             , "le 2 mars Ã  5h du matin"
             , "le 2 mars vers 5h"
             , "2 mars vers 5h"
             , "2 mars Ã  environ 5h"
             , "2 mars aux alentours de 5h"
             , "2 mars autour de 5h"
             , "le 2/3 vers 5h"
             ]
  , examples (datetime (2013, 3, 2, 0, 0, 0) Day)
             [ "le 2"
             ]
  , examples (datetime (2013, 3, 2, 5, 0, 0) Hour)
             [ "le 2 Ã  5h"
             , "le 2 vers 5h"
             , "le 2 Ã  5h du mat"
             ]
  , examples (datetime (2013, 3, 3, 0, 0, 0) Day)
             [ "le 3 mars"
             , "3 mars"
             , "le 3/3"
             ]
  , examples (datetime (2013, 4, 5, 0, 0, 0) Day)
             [ "le 5 avril"
             , "5 avril"
             ]
  , examples (datetime (2015, 3, 3, 0, 0, 0) Day)
             [ "le 3 mars 2015"
             , "3 mars 2015"
             , "3/3/2015"
             , "2015-3-3"
             , "2015-03-03"
             ]
  , examples (datetime (2013, 2, 15, 0, 0, 0) Day)
             [ "le 15 fÃ©vrier"
             , "15 fÃ©vrier"
             ]
  , examples (datetime (2013, 2, 15, 0, 0, 0) Day)
             [ "15/02/2013"
             , "15 fev 2013"
             ]
  , examples (datetime (2013, 2, 16, 0, 0, 0) Day)
             [ "le 16"
             ]
  , examples (datetime (2013, 2, 16, 18, 0, 0) Hour)
             [ "le 16 Ã  18h"
             , "le 16 vers 18h"
             , "le 16 plutÃ´t vers 18h"
             , "le 16 Ã  6h du soir"
             , "le 16 vers 6h du soir"
             , "le 16 vers 6h dans la soirÃ©e"
             , "samedi 16 Ã  18h"
             ]
  , examples (datetime (2013, 2, 17, 0, 0, 0) Day)
             [ "17 fÃ©vrier"
             , "le 17 fÃ©vrier"
             , "17/2"
             , "17/02"
             , "le 17/02"
             , "17 02"
             , "17 2"
             , "le 17 02"
             , "le 17 2"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "mercredi 13"
             ]
  , examples (datetime (2014, 2, 20, 0, 0, 0) Day)
             [ "20/02/2014"
             , "20/2/2014"
             , "20/02/14"
             , "le 20/02/14"
             , "le 20/2/14"
             , "20 02 2014"
             , "20 02 14"
             , "20 2 2014"
             , "20 2 14"
             , "le 20 02 2014"
             , "le 20 02 14"
             , "le 20 2 2014"
             , "le 20 2 14"
             ]
  , examples (datetime (2013, 10, 31, 0, 0, 0) Day)
             [ "31 octobre"
             , "le 31 octobre"
             , "31/10"
             , "le 31/10"
             , "31 10"
             , "le 31 10"
             ]
  , examples (datetime (2014, 12, 24, 0, 0, 0) Day)
             [ "24/12/2014"
             , "24/12/14"
             , "le 24/12/14"
             , "24 12 2014"
             , "24 12 14"
             , "le 24 12 2014"
             , "le 24 12 14"
             ]
  , examples (datetime (1974, 10, 31, 0, 0, 0) Day)
             [ "31/10/1974"
             , "31/10/74"
             , "31 octobre 74"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "lundi prochain"
             , "lundi la semaine prochaine"
             , "lundi de la semaine prochaine"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "mardi prochain"
             , "mardi suivant"
             , "mardi d'aprÃ¨s"
             , "mardi la semaine prochaine"
             , "mardi de la semaine prochaine"
             , "mardi la semaine suivante"
             , "mardi de la semaine suivante"
             , "mardi la semaine d'aprÃ¨s"
             , "mardi de la semaine d'aprÃ¨s"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "mercredi prochain"
             ]
  , examples (datetime (2013, 2, 20, 0, 0, 0) Day)
             [ "mercredi suivant"
             , "mercredi d'aprÃ¨s"
             , "mercredi la semaine prochaine"
             , "mercredi de la semaine prochaine"
             , "mercredi la semaine suivante"
             , "mercredi de la semaine suivante"
             , "mercredi la semaine d'aprÃ¨s"
             , "mercredi de la semaine d'aprÃ¨s"
             ]
  , examples (datetime (2013, 2, 25, 0, 0, 0) Day)
             [ "lundi en huit"
             , "lundi en 8"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "mardi en huit"
             , "mardi en 8"
             ]
  , examples (datetime (2013, 2, 20, 0, 0, 0) Day)
             [ "mercredi en huit"
             , "mercredi en 8"
             ]
  , examples (datetime (2013, 3, 4, 0, 0, 0) Day)
             [ "lundi en quinze"
             , "lundi en 15"
             ]
  , examples (datetime (2013, 2, 26, 0, 0, 0) Day)
             [ "mardi en quinze"
             , "mardi en 15"
             ]
  , examples (datetime (2013, 2, 27, 0, 0, 0) Day)
             [ "mercredi en quinze"
             , "mercredi en 15"
             ]
  , examples (datetime (2013, 2, 11, 0, 0, 0) Day)
             [ "lundi cette semaine"
             ]
  , examples (datetime (2013, 2, 12, 0, 0, 0) Day)
             [ "mardi cette semaine"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "mercredi cette semaine"
             ]
  , examples (datetime (2013, 2, 11, 0, 0, 0) Week)
             [ "cette semaine"
             , "dans la semaine"
             ]
  , examples (datetime (2013, 2, 4, 0, 0, 0) Week)
             [ "la semaine derniÃ¨re"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Week)
             [ "la semaine prochaine"
             , "la semaine suivante"
             , "la semaine qui suit"
             ]
  , examples (datetime (2013, 1, 0, 0, 0, 0) Month)
             [ "le mois dernier"
             ]
  , examples (datetime (2013, 3, 0, 0, 0, 0) Month)
             [ "le mois prochain"
             , "le mois suivant"
             ]
  , examples (datetime (2012, 0, 0, 0, 0, 0) Year)
             [ "l'annÃ©e derniÃ¨re"
             ]
  , examples (datetime (2013, 0, 0, 0, 0, 0) Year)
             [ "cette annÃ©e"
             ]
  , examples (datetime (2014, 0, 0, 0, 0, 0) Year)
             [ "l'annÃ©e prochaine"
             ]
  , examples (datetime (2013, 2, 10, 0, 0, 0) Day)
             [ "dimanche dernier"
             , "dimanche de la semaine derniÃ¨re"
             ]
  , examples (datetime (2013, 10, 3, 0, 0, 0) Day)
             [ "3eme jour d'octobre"
             , "le 3eme jour d'octobre"
             ]
  , examples (datetime (2014, 10, 6, 0, 0, 0) Week)
             [ "premiere semaine d'octobre 2014"
             , "la premiere semaine d'octobre 2014"
             ]
  , examples (datetime (2013, 10, 7, 0, 0, 0) Week)
             [ "la semaine du 6 octobre"
             , "la semaine du 7 octobre"
             ]
  , examples (datetime (2015, 10, 31, 0, 0, 0) Day)
             [ "dernier jour d'octobre 2015"
             , "le dernier jour d'octobre 2015"
             ]
  , examples (datetime (2014, 9, 22, 0, 0, 0) Week)
             [ "derniÃ¨re semaine de septembre 2014"
             , "la derniÃ¨re semaine de septembre 2014"
             ]
  , examples (datetime (2013, 2, 12, 15, 0, 0) Hour)
             [ "Ã  quinze heures"
             , "Ã  15 heures"
             , "Ã  3 heures cet aprÃ¨s-midi"
             , "15h"
             , "15H"
             , "vers 15 heures"
             , "Ã  environ 15 heures"
             ]
  , examples (datetime (2013, 2, 12, 15, 0, 0) Minute)
             [ "15:00"
             , "15h00"
             , "15H00"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Hour)
             [ "minuit"
             ]
  , examples (datetime (2013, 2, 12, 12, 0, 0) Hour)
             [ "midi"
             , "aujourd'hui Ã  midi"
             ]
  , examples (datetime (2013, 2, 12, 12, 15, 0) Minute)
             [ "midi et quart"
             , "midi quinze"
             ]
  , examples (datetime (2013, 2, 12, 11, 55, 0) Minute)
             [ "midi moins cinq"
             ]
  , examples (datetime (2013, 2, 12, 12, 30, 0) Minute)
             [ "midi et demi"
             , "midi trente"
             ]
  , examples (datetime (2013, 2, 13, 0, 3, 0) Minute)
             [ "minuit trois"
             ]
  , examples (datetime (2013, 2, 12, 0, 3, 0) Minute)
             [ "aujourd'hui Ã  minuit trois"
             ]
  , examples (datetime (2013, 2, 12, 15, 15, 0) Minute)
             [ "Ã  quinze heures quinze"
             , "Ã  quinze heures et quinze minutes"
             , "15h passÃ© de 15 minutes"
             , "Ã  trois heures et quart cet aprÃ¨s-midi"
             , "15:15"
             , "15h15"
             ]
  , examples (datetime (2013, 2, 13, 15, 15, 0) Minute)
             [ "Ã  trois heures et quart demain aprÃ¨s-midi"
             ]
  , examples (datetime (2013, 2, 12, 15, 30, 0) Minute)
             [ "Ã  quinze heures trente"
             , "Ã  quinze heures passÃ© de trente minutes"
             , "Ã  trois heures et demi cet aprÃ¨s-midi"
             , "15:30"
             , "15h30"
             ]
  , examples (datetime (2013, 2, 12, 11, 45, 0) Minute)
             [ "midi moins le quart"
             , "11h45"
             , "onze heures trois quarts"
             , "aujourd'hui Ã  11h45"
             ]
  , examples (datetime (2013, 2, 13, 11, 0, 0) Hour)
             [ "mercredi Ã  11h"
             ]
  , examples (datetime (2013, 2, 13, 11, 0, 0) Hour)
             [ "demain Ã  11 heures"
             , "demain Ã  11H"
             ]
  , examples (datetime (2013, 2, 14, 11, 0, 0) Hour)
             [ "jeudi Ã  11h"
             , "aprÃ¨s-demain Ã  11 heures"
             , "aprÃ¨s-demain Ã  11H"
             ]
  , examples (datetime (2013, 2, 15, 12, 0, 0) Hour)
             [ "vendredi Ã  midi"
             , "vendredi Ã  12h"
             ]
  , examples (datetime (2013, 2, 15, 16, 0, 0) Hour)
             [ "vendredi quinze Ã  seize heures"
             , "vendredi 15 Ã  16h"
             , "vendredi quinze Ã  16h"
             ]
  , examples (datetime (2013, 2, 12, 4, 30, 1) Second)
             [ "dans une seconde"
             , "dans 1\""
             ]
  , examples (datetime (2013, 2, 12, 4, 31, 0) Second)
             [ "dans une minute"
             , "dans 1 min"
             ]
  , examples (datetime (2013, 2, 12, 4, 32, 0) Second)
             [ "dans 2 minutes"
             , "dans deux min"
             , "dans 2'"
             ]
  , examples (datetime (2013, 2, 12, 5, 30, 0) Second)
             [ "dans 60 minutes"
             ]
  , examples (datetime (2013, 2, 12, 5, 30, 0) Minute)
             [ "dans une heure"
             ]
  , examples (datetime (2013, 2, 12, 2, 30, 0) Minute)
             [ "il y a deux heures"
             ]
  , examples (datetime (2013, 2, 13, 4, 30, 0) Minute)
             [ "dans 24 heures"
             , "dans vingt quatre heures"
             ]
  , examples (datetime (2013, 2, 13, 4, 0, 0) Hour)
             [ "dans un jour"
             ]
  , examples (datetime (2013, 2, 19, 4, 0, 0) Hour)
             [ "dans 7 jours"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "dans 1 semaine"
             , "dans une semaine"
             ]
  , examples (datetime (2013, 1, 22, 0, 0, 0) Day)
             [ "il y a trois semaines"
             ]
  , examples (datetime (2013, 4, 12, 0, 0, 0) Day)
             [ "dans deux mois"
             ]
  , examples (datetime (2012, 11, 12, 0, 0, 0) Day)
             [ "il y a trois mois"
             ]
  , examples (datetime (2014, 2, 0, 0, 0, 0) Month)
             [ "dans une annÃ©e"
             , "dans 1 an"
             ]
  , examples (datetime (2011, 2, 0, 0, 0, 0) Month)
             [ "il y a deux ans"
             ]
  , examples (datetimeInterval ((2013, 6, 21, 0, 0, 0), (2013, 9, 24, 0, 0, 0)) Day)
             [ "cet Ã©tÃ©"
             ]
  , examples (datetimeInterval ((2012, 12, 21, 0, 0, 0), (2013, 3, 21, 0, 0, 0)) Day)
             [ "cet hiver"
             ]
  , examples (datetime (2013, 12, 25, 0, 0, 0) Day)
             [ "Noel"
             , "noÃ«l"
             , "jour de noel"
             ]
  , examples (datetimeInterval ((2013, 12, 24, 18, 0, 0), (2013, 12, 25, 0, 0, 0)) Hour)
             [ "le soir de noÃ«l"
             ]
  , examples (datetime (2014, 1, 1, 0, 0, 0) Day)
             [ "jour de l'an"
             , "nouvel an"
             , "premier janvier"
             ]
  , examples (datetime (2013, 11, 1, 0, 0, 0) Day)
             [ "la toussaint"
             , "le jour de la toussaint"
             , "la journÃ©e de la toussaint"
             , "toussaint"
             , "le jour des morts"
             ]
  , examples (datetime (2013, 5, 1, 0, 0, 0) Day)
             [ "fÃªte du travail"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 12, 0, 0), (2013, 2, 12, 19, 0, 0)) Hour)
             [ "cet aprÃ¨s-midi"
             , "l'aprÃ¨s-midi"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 7, 0, 0), (2013, 2, 12, 9, 0, 0)) Hour)
             [ "aujourd'hui en dÃ©but de matinÃ©e"
             , "en dÃ©but de matinÃ©e"
             , "le 12 fÃ©vrier en dÃ©but de matinÃ©e"
             , "aujourd'hui trÃ¨s tÃ´t le matin"
             , "aujourd'hui tÃ´t le matin"
             , "aujourd'hui le matin tÃ´t"
             , "aujourd'hui le matin trÃ¨s tÃ´t"
             , "le matin trÃ¨s tÃ´t"
             , "le matin tÃ´t"
             , "tÃ´t le matin"
             , "trÃ¨s tÃ´t le matin"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 9, 0, 0), (2013, 2, 12, 11, 0, 0)) Hour)
             [ "aujourd'hui en milieu de matinÃ©e"
             , "le 12 fÃ©vrier en milieu de matinÃ©e"
             , "en milieu de matinÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 10, 0, 0), (2013, 2, 12, 12, 0, 0)) Hour)
             [ "aujourd'hui en fin de matinÃ©e"
             , "en fin de matinÃ©e"
             , "le 12 fÃ©vrier en fin de matinÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 13, 0, 0), (2013, 2, 12, 17, 0, 0)) Hour)
             [ "aprÃ¨s dÃ©jeuner"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 10, 0, 0), (2013, 2, 12, 12, 0, 0)) Hour)
             [ "avant dÃ©jeuner"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 12, 0, 0), (2013, 2, 12, 14, 0, 0)) Hour)
             [ "aujourd'hui pendant le dÃ©jeuner"
             , "Ã  l'heure du dÃ©jeuner"
             , "au moment de dÃ©jeuner"
             , "pendant le dÃ©jeuner"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 17, 0, 0), (2013, 2, 12, 21, 0, 0)) Hour)
             [ "aprÃ¨s le travail"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 0, 0), (2013, 2, 12, 12, 0, 0)) Hour)
             [ "dÃ¨s le matin"
             , "dÃ¨s la matinÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 12, 0, 0), (2013, 2, 12, 14, 0, 0)) Hour)
             [ "aujourd'hui en dÃ©but d'aprÃ¨s-midi"
             , "en dÃ©but d'aprÃ¨s-midi"
             , "le 12 fÃ©vrier en dÃ©but d'aprÃ¨s-midi"
             , "au dÃ©but de l'aprÃ¨s-midi"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 14, 0, 0), (2013, 2, 12, 17, 0, 0)) Hour)
             [ "aujourd'hui en milieu d'aprÃ¨s-midi"
             , "en milieu d'aprÃ¨s-midi"
             , "le 12 fÃ©vrier en milieu d'aprÃ¨s-midi"
             , "au milieu de l'aprÃ¨s-midi"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 17, 0, 0), (2013, 2, 12, 19, 0, 0)) Hour)
             [ "aujourd'hui en fin d'aprÃ¨s-midi"
             , "en fin d'aprÃ¨s-midi"
             , "le 12 fÃ©vrier en fin d'aprÃ¨s-midi"
             , "Ã  la fin de l'aprÃ¨s-midi"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 6, 0, 0), (2013, 2, 12, 10, 0, 0)) Hour)
             [ "aujourd'hui en dÃ©but de journÃ©e"
             , "le 12 fÃ©vrier en dÃ©but de journÃ©e"
             , "en dÃ©but de journÃ©e"
             , "au dÃ©but de la journÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 11, 0, 0), (2013, 2, 12, 16, 0, 0)) Hour)
             [ "aujourd'hui en milieu de journÃ©e"
             , "en milieu de journÃ©e"
             , "le 12 fÃ©vrier en milieu de journÃ©e"
             , "au milieu de la journÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 17, 0, 0), (2013, 2, 12, 21, 0, 0)) Hour)
             [ "aujourd'hui en fin de journÃ©e"
             , "en fin de journÃ©e"
             , "le 12 fÃ©vrier en fin de journÃ©e"
             , "Ã  la fin de la journÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 18, 0, 0), (2013, 2, 13, 0, 0, 0)) Hour)
             [ "ce soir"
             , "le soir"
             , "dans la soirÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 18, 0, 0), (2013, 2, 12, 21, 0, 0)) Hour)
             [ "aujourd'hui en dÃ©but de soirÃ©e"
             , "en dÃ©but de soirÃ©e"
             , "le 12 fÃ©vrier en dÃ©but de soirÃ©e"
             , "au dÃ©but de la soirÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 21, 0, 0), (2013, 2, 13, 0, 0, 0)) Hour)
             [ "aujourd'hui en fin de soirÃ©e"
             , "en fin de soirÃ©e"
             , "le 12 fÃ©vrier en fin de soirÃ©e"
             , "Ã  la fin de la soirÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 18, 0, 0), (2013, 2, 14, 0, 0, 0)) Hour)
             [ "demain soir"
             , "mercredi soir"
             , "mercredi en soirÃ©e"
             ]
  , examples (datetimeInterval ((2013, 2, 11, 18, 0, 0), (2013, 2, 12, 0, 0, 0)) Hour)
             [ "hier soir"
             , "la veille au soir"
             ]
  , examples (datetimeInterval ((2013, 2, 15, 18, 0, 0), (2013, 2, 18, 0, 0, 0)) Hour)
             [ "ce week-end"
             ]
  , examples (datetimeInterval ((2013, 2, 11, 0, 0, 0), (2013, 2, 13, 0, 0, 0)) Day)
             [ "en dÃ©but de semaine"
             , "au dÃ©but de la semaine"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 0, 0, 0), (2013, 2, 15, 0, 0, 0)) Day)
             [ "en milieu de semaine"
             , "au milieu de la semaine"
             ]
  , examples (datetimeInterval ((2013, 2, 14, 0, 0, 0), (2013, 2, 18, 0, 0, 0)) Day)
             [ "en fin de semaine"
             , "Ã  la fin de la semaine"
             ]
  , examples (datetimeInterval ((2013, 2, 11, 0, 0, 0), (2013, 2, 16, 0, 0, 0)) Day)
             [ "en semaine"
             ]
  , examples (datetimeInterval ((2013, 9, 6, 18, 0, 0), (2013, 9, 9, 0, 0, 0)) Hour)
             [ "le premier week-end de septembre"
             ]
  , examples (datetimeInterval ((2013, 9, 13, 18, 0, 0), (2013, 9, 16, 0, 0, 0)) Hour)
             [ "le deuxiÃ¨me week-end de septembre"
             ]
  , examples (datetimeInterval ((2013, 9, 27, 18, 0, 0), (2013, 9, 30, 0, 0, 0)) Hour)
             [ "le dernier week-end de septembre"
             ]
  , examples (datetimeInterval ((2013, 2, 18, 4, 0, 0), (2013, 2, 18, 12, 0, 0)) Hour)
             [ "lundi matin"
             ]
  , examples (datetimeInterval ((2013, 2, 18, 12, 0, 0), (2013, 2, 18, 19, 0, 0)) Hour)
             [ "lundi aprÃ¨s-midi"
             , "lundi dans l'aprÃ¨s-midi"
             ]
  , examples (datetimeInterval ((2013, 2, 18, 17, 0, 0), (2013, 2, 18, 19, 0, 0)) Hour)
             [ "lundi fin d'aprÃ¨s-midi"
             , "lundi en fin d'aprÃ¨s-midi"
             ]
  , examples (datetimeInterval ((2013, 2, 15, 4, 0, 0), (2013, 2, 15, 12, 0, 0)) Hour)
             [ "le 15 fÃ©vrier dans la matinÃ©e"
             , "matinÃ©e du 15 fÃ©vrier"
             , "le 15 fÃ©vrier le matin"
             ]
  , examples (datetime (2013, 2, 12, 20, 0, 0) Hour)
             [ "8 heures ce soir"
             , "8h du soir"
             ]
  , examples (datetime (2013, 2, 13, 3, 0, 0) Hour)
             [ "3 heures du matin"
             , "3h du mat"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 29, 58), (2013, 2, 12, 4, 30, 0)) Second)
             [ "2 derniÃ¨res secondes"
             , "deux dernieres secondes"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 30, 1), (2013, 2, 12, 4, 30, 4)) Second)
             [ "3 prochaines secondes"
             , "trois prochaines secondes"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 28, 0), (2013, 2, 12, 4, 30, 0)) Minute)
             [ "2 dernieres minutes"
             , "deux derniÃ¨res minutes"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 31, 0), (2013, 2, 12, 4, 34, 0)) Minute)
             [ "3 prochaines minutes"
             , "trois prochaines minutes"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 5, 0, 0), (2013, 2, 12, 8, 0, 0)) Hour)
             [ "3 prochaines heures"
             , "3 heures suivantes"
             ]
  , examples (datetimeInterval ((2013, 2, 10, 0, 0, 0), (2013, 2, 12, 0, 0, 0)) Day)
             [ "2 dernier jours"
             , "deux derniers jour"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 0, 0, 0), (2013, 2, 16, 0, 0, 0)) Day)
             [ "3 prochains jours"
             ]
  , examples (datetimeInterval ((2013, 1, 28, 0, 0, 0), (2013, 2, 11, 0, 0, 0)) Week)
             [ "2 dernieres semaines"
             , "2 semaines passÃ©es"
             ]
  , examples (datetimeInterval ((2013, 2, 18, 0, 0, 0), (2013, 3, 11, 0, 0, 0)) Week)
             [ "3 prochaines semaines"
             ]
  , examples (datetimeInterval ((2012, 12, 0, 0, 0, 0), (2013, 2, 0, 0, 0, 0)) Month)
             [ "2 derniers mois"
             ]
  , examples (datetimeInterval ((2013, 3, 0, 0, 0, 0), (2013, 6, 0, 0, 0, 0)) Month)
             [ "3 prochains mois"
             , "3 mois suivant"
             ]
  , examples (datetimeInterval ((2011, 0, 0, 0, 0, 0), (2013, 0, 0, 0, 0, 0)) Year)
             [ "2 dernieres annees"
             , "2 annÃ©es passÃ©es"
             ]
  , examples (datetimeInterval ((2014, 0, 0, 0, 0, 0), (2017, 0, 0, 0, 0, 0)) Year)
             [ "3 prochaines annÃ©es"
             ]
  , examples (datetimeInterval ((2013, 7, 13, 0, 0, 0), (2013, 7, 16, 0, 0, 0)) Day)
             [ "13-15 juillet"
             , "13 au 15 juillet"
             , "13 jusqu'au 15 juillet"
             , "13 juillet au 15 juillet"
             , "13 juillet - 15 juillet"
             , "entre le 13 et le 15 juillet"
             , "samedi 13 au dimanche 15e juillet"
             , "du samedi 13 au dimanche 15 juillet"
             , "du 13 au dimanche 15 juillet"
             , "entre le 13 et le quinze juillet"
             , "du treize au 15 juillet"
             , "du 13e au 15 juillet"
             ]
  , examples (datetimeInterval ((2013, 7, 1, 0, 0, 0), (2013, 7, 11, 0, 0, 0)) Day)
             [ "1er au 10 juillet"
             , "lundi 1er au mercredi 10 juillet"
             , "lundi 1 au mercredi 10e juillet"
             , "du lundi 1er au mercredi 10 juillet"
             , "du 1er au mercredi 10 juillet"
             , "du 1er au dix juillet"
             , "1er au dix juillet"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 0, 0, 0), (2013, 2, 19, 0, 0, 0)) Day)
             [ "du 13 au 18"
             , "entre le 13 et le dix-huit"
             , "du 13e au dix-huit"
             ]
  , examples (datetimeInterval ((2013, 6, 10, 0, 0, 0), (2013, 7, 2, 0, 0, 0)) Day)
             [ "10 juin au 1er juillet"
             , "entre le 10 juin et le 1er juillet"
             , "du 10 juin au 1er juillet"
             ]
  , examples (datetimeInterval ((2013, 2, 14, 9, 30, 0), (2013, 2, 14, 11, 1, 0)) Minute)
             [ "de 9h30 jusqu'Ã  11h jeudi"
             , "de 9 heures 30 Ã  11h jeudi"
             , "de 9 heures 30 a 11h jeudi"
             , "entre 9h30 et 11h jeudi"
             , "jeudi mais entre 9h30 et 11h"
             , "jeudi par exemple entre 9h30 et 11h"
             , "9h30 - 11h00 Jeudi"
             ]
  , examples (datetimeOpenInterval After (2013, 3, 8, 0, 0, 0) Day)
             [ "Ã  partir du 8"
             , "Ã  partir du 8 mars"
             ]
  , examples (datetimeOpenInterval After (2013, 2, 14, 9, 30, 0) Minute)
             [ "Ã  partir de 9h30 jeudi"
             , "jeudi aprÃ¨s 9h30"
             , "jeudi plus tard que 9h30"
             , "jeudi matin Ã  partir de 9 heures 30"
             ]
  , examples (datetimeOpenInterval After (2013, 11, 1, 16, 0, 0) Hour)
             [ "aprÃ¨s 16h le 1er novembre"
             , "plus tard que 16h le 1er novembre"
             ]
  , examples (datetimeOpenInterval After (2013, 11, 1, 0, 0, 0) Day)
             [ "aprÃ¨s le 1er novembre"
             ]
  , examples (datetimeOpenInterval Before (2013, 2, 12, 16, 0, 0) Hour)
             [ "avant 16h"
             , "n'importe quand avant 16h"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 0, 0, 0), (2013, 2, 13, 17, 0, 0)) Hour)
             [ "demain jusqu'Ã  16h"
             ]
  , examples (datetimeOpenInterval After (2013, 2, 20, 10, 0, 0) Hour)
             [ "le 20 Ã  partir de 10h"
             ]
  , examples (datetimeOpenInterval After (2013, 2, 15, 12, 0, 0) Hour)
             [ "vendredi Ã  partir de midi"
             ]
  , examples (datetimeInterval ((2013, 2, 20, 0, 0, 0), (2013, 2, 20, 19, 0, 0)) Hour)
             [ "le 20 jusqu'Ã  18h"
             ]
  , examples (datetimeInterval ((2014, 9, 14, 0, 0, 0), (2014, 9, 21, 0, 0, 0)) Day)
             [ "14 - 20 sept. 2014"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 30, 0), (2013, 2, 26, 0, 0, 0)) Second)
             [ "d'ici 2 semaines"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 30, 0), (2013, 2, 27, 4, 0, 0)) Second)
             [ "dans les 15 jours"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 5, 0, 0), (2013, 2, 12, 8, 0, 0)) Hour)
             [ "de 5 Ã  7"
             ]
  , examples (datetimeInterval ((2013, 2, 14, 9, 0, 0), (2013, 2, 14, 12, 0, 0)) Hour)
             [ "jeudi de 9h Ã  11h"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 12, 0, 0), (2013, 2, 12, 15, 0, 0)) Hour)
             [ "entre midi et 2"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 11, 30, 0), (2013, 2, 12, 13, 31, 0)) Minute)
             [ "11h30-1h30"
             , "de 11h30 Ã  1h30"
             , "de 11h30 jusqu'Ã  1h30"
             ]
  , examples (datetime (2013, 9, 21, 13, 30, 0) Minute)
             [ "13h30 samedi 21 septembre"
             ]
  , examples (datetime (2013, 2, 12, 13, 0, 0) Minute)
             [ "Ã  seize heures CET"
             ]
  , examples (datetimeInterval ((2013, 3, 21, 0, 0, 0), (2013, 4, 1, 0, 0, 0)) Day)
             [ "fin mars"
             , "fin du mois de mars"
             ]
  , examples (datetimeInterval ((2013, 4, 1, 0, 0, 0), (2013, 4, 6, 0, 0, 0)) Day)
             [ "dÃ©but avril"
             , "dÃ©but du mois d'avril"
             ]
  , examples (datetimeInterval ((2013, 4, 1, 0, 0, 0), (2013, 4, 15, 0, 0, 0)) Day)
             [ "la premiÃ¨re quinzaine d'avril"
             ]
  , examples (datetimeInterval ((2013, 4, 15, 0, 0, 0), (2013, 5, 1, 0, 0, 0)) Day)
             [ "la deuxiÃ¨me quinzaine d'avril"
             ]
  , examples (datetimeInterval ((2013, 4, 1, 0, 0, 0), (2013, 4, 6, 0, 0, 0)) Day)
             [ "dÃ©but avril"
             , "dÃ©but du mois d'avril"
             ]
  , examples (datetimeInterval ((2013, 12, 10, 0, 0, 0), (2013, 12, 20, 0, 0, 0)) Day)
             [ "mi-dÃ©cembre"
             ]
  , examples (datetimeInterval ((2013, 2, 21, 0, 0, 0), (2013, 3, 1, 0, 0, 0)) Day)
             [ "en fin de mois"
             , "Ã  la fin du mois"
             ]
  , examples (datetimeInterval ((2013, 11, 1, 0, 0, 0), (2014, 1, 1, 0, 0, 0)) Month)
             [ "en fin d'annÃ©e"
             , "Ã  la fin de l'annÃ©e"
             ]
  , examples (datetimeInterval ((2013, 1, 1, 0, 0, 0), (2013, 3, 1, 0, 0, 0)) Month)
             [ "en dÃ©but d'annÃ©e"
             , "au dÃ©but de l'annÃ©e"
             ]
  , examples (datetimeInterval ((2013, 3, 1, 0, 0, 0), (2013, 3, 11, 0, 0, 0)) Day)
             [ "au dÃ©but du mois"
             , "en dÃ©but de mois"
             ]
  , examples (datetime (2013, 3, 0, 0, 0, 0) Month)
             [ "mars"
             , "en mars"
             , "au mois de mars"
             , "le mois de mars"
             ]
  , examples (datetime (2013, 8, 15, 0, 0, 0) Day)
             [ "jeudi 15"
             ]
  , examples (datetime (2013, 8, 15, 8, 0, 0) Hour)
             [ "jeudi 15 Ã  8h"
             ]
  , examples (datetimeOpenInterval After (2013, 2, 12, 4, 40, 0) Minute)
             [ "plus tard"
             , "un peu plus tard"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 12, 0, 0), (2013, 2, 12, 19, 0, 0)) Hour)
             [ "plus tard dans l'aprÃ¨s-midi"
             , "un peu plus tard dans l'aprÃ¨s-midi"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 18, 0, 0), (2013, 2, 13, 00, 0, 0)) Hour)
             [ "plus tard dans la soirÃ©e"
             , "un peu plus tard dans la soirÃ©e"
             ]
  , examples (datetime (2013, 3, 6, 0, 0, 0) Day)
             [ "le premier mercredi de mois prochain"
             , "premier mercredi du mois prochain"
             ]
  ]


-- 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 LambdaCase #-}
{-# LANGUAGE NoRebindableSyntax #-}
{-# LANGUAGE OverloadedStrings #-}

module Duckling.Time.FR.Rules
  ( rules
  ) where

import Prelude
import qualified Data.Text as Text

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

ruleAujourdhui :: Rule
ruleAujourdhui = Rule
  { name = "aujourd'hui"
  , pattern =
    [ regex "(aujourd'? ?hui)|(ce jour)|(dans la journ(Ã©|e)e?)|(en ce moment)"
    ]
  , prod = \_ -> tt today
  }

ruleDayofmonthNamedmonth :: Rule
ruleDayofmonthNamedmonth = Rule
  { name = "<day-of-month> <named-month>"
  , pattern =
    [ Predicate isDOMInteger
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (token:Token Time td:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleHier :: Rule
ruleHier = Rule
  { name = "hier"
  , pattern =
    [ regex "hier|la veille"
    ]
  , prod = \_ -> tt . cycleNth TG.Day $ - 1
  }

ruleDbutDeSoire :: Rule
ruleDbutDeSoire = Rule
  { name = "dÃ©but de soirÃ©e"
  , pattern =
    [ regex "(en |au )?d(Ã©|e)but de (la )?soir(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 18) (hour False 21)
  }

ruleFinDeSoire :: Rule
ruleFinDeSoire = Rule
  { name = "fin de soirÃ©e"
  , pattern =
    [ regex "(en |(Ã |a) la )?fin de (la )?soir(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 21) (hour False 0)
  }

ruleDbutDeMatine :: Rule
ruleDbutDeMatine = Rule
  { name = "dÃ©but de matinÃ©e"
  , pattern =
    [ regex "le matin (tr(e|Ã¨)s )?t(Ã´|o)t|(tr(e|Ã¨)s )?t(Ã´|o)t le matin|(en |au )?d(Ã©|e)but de (la )?matin(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 7) (hour False 9)
  }

ruleMilieuDeMatine :: Rule
ruleMilieuDeMatine = Rule
  { name = "milieu de matinÃ©e"
  , pattern =
    [ regex "(en |au )?milieu de (la )?matin(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 9) (hour False 11)
  }

ruleFinDeMatine :: Rule
ruleFinDeMatine = Rule
  { name = "fin de matinÃ©e"
  , pattern =
    [ regex "(en |(Ã |a) la )?fin de (la )?matin(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 10) (hour False 12)
  }

ruleDbutDaprsmidi :: Rule
ruleDbutDaprsmidi = Rule
  { name = "dÃ©but d'aprÃ¨s-midi"
  , pattern =
    [ regex "(au |en )?d(Ã©|e)but (d'|de l')apr(e|Ã©|Ã¨)s( |\\-)midi"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 12) (hour False 14)
  }

ruleMilieuDaprsmidi :: Rule
ruleMilieuDaprsmidi = Rule
  { name = "milieu d'aprÃ¨s-midi"
  , pattern =
    [ regex "(au |en )?milieu (d'|de l')apr(e|Ã©|Ã¨)s( |\\-)midi"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 14) (hour False 17)
  }

ruleFinDaprsmidi :: Rule
ruleFinDaprsmidi = Rule
  { name = "fin d'aprÃ¨s-midi"
  , pattern =
    [ regex "((Ã |a) la |en )?fin (d'|de l')apr(e|Ã©|Ã¨)s( |\\-)midi"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 17) (hour False 19)
  }

ruleDbutDeJourne :: Rule
ruleDbutDeJourne = Rule
  { name = "dÃ©but de journÃ©e"
  , pattern =
    [ regex "(en |au )?d(Ã©|e)but de (la )?journ(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
        interval TTime.Open (hour False 6) (hour False 10)
  }

ruleMilieuDeJourne :: Rule
ruleMilieuDeJourne = Rule
  { name = "milieu de journÃ©e"
  , pattern =
    [ regex "(en |au )?milieu de (la )?journ(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 11) (hour False 16)
  }

ruleFinDeJourne :: Rule
ruleFinDeJourne = Rule
  { name = "fin de journÃ©e"
  , pattern =
    [ regex "(en |(Ã |a) la )?fin de (la )?journ(Ã©|e)e"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 17) (hour False 21)
  }

ruleDbutDeSemaine :: Rule
ruleDbutDeSemaine = Rule
  { name = "dÃ©but de semaine"
  , pattern =
    [ regex "(en |au )?d(Ã©|e)but de (cette |la )?semaine"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (dayOfWeek 1) (dayOfWeek 2)
  }

ruleMilieuDeSemaine :: Rule
ruleMilieuDeSemaine = Rule
  { name = "milieu de semaine"
  , pattern =
    [ regex "(en |au )?milieu de (cette |la )?semaine"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (dayOfWeek 3) (dayOfWeek 4)
  }

ruleFinDeSemaine :: Rule
ruleFinDeSemaine = Rule
  { name = "fin de semaine"
  , pattern =
    [ regex "(en |(Ã |a) la )?fin de (cette |la )?semaine"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (dayOfWeek 4) (dayOfWeek 7)
  }

ruleLeLendemainDuTime :: Rule
ruleLeLendemainDuTime = Rule
  { name = "le lendemain du <time>"
  , pattern =
    [ regex "(le|au)? ?lendemain du"
    , Predicate $ isGrainCoarserThan TG.Hour
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ cycleNthAfter True TG.Day 1 td
      _ -> Nothing
  }

ruleCePartofday :: Rule
ruleCePartofday = Rule
  { name = "ce <part-of-day>"
  , pattern =
    [ regex "cet?t?e?"
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time . partOfDay . notLatent <$>
        intersect today td
      _ -> Nothing
  }

ruleCeTime :: Rule
ruleCeTime = Rule
  { name = "ce <time>"
  , pattern =
    [ regex "ce"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 0 False td
      _ -> Nothing
  }

ruleDurationAvantTime :: Rule
ruleDurationAvantTime = Rule
  { name = "<duration> avant <time>"
  , pattern =
    [ dimension Duration
    , regex "avant"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_:Token Time td:_) ->
        tt $ durationBefore dd td
      _ -> Nothing
  }

ruleMidi :: Rule
ruleMidi = Rule
  { name = "midi"
  , pattern =
    [ regex "midi"
    ]
  , prod = \_ -> tt $ hour False 12
  }

ruleDatetimeDatetimeInterval :: Rule
ruleDatetimeDatetimeInterval = Rule
  { name = "<datetime> - <datetime> (interval)"
  , pattern =
    [ Predicate isNotLatent
    , regex "\\-|au|jusqu'(au?|Ã )"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleDeTimeofdayTimeofdayInterval :: Rule
ruleDeTimeofdayTimeofdayInterval = Rule
  { name = "de <time-of-day> - <time-of-day> (interval)"
  , pattern =
    [ regex "(midi )?de"
    , Predicate isATimeOfDay
    , regex "\\-|(jusqu')?(Ã |au?)"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleNProchainsCycle :: Rule
ruleNProchainsCycle = Rule
  { name = "n prochains <cycle>"
  , pattern =
    [ Predicate $ isIntegerBetween 2 9999
    , regex "prochaine?s?|suivante?s?|apr(e|Ã¨|Ã©)s"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (token:_:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt $ cycleN True grain n
      _ -> Nothing
  }

ruleNDerniersCycle :: Rule
ruleNDerniersCycle = Rule
  { name = "n derniers <cycle>"
  , pattern =
    [ Predicate $ isIntegerBetween 2 9999
    , regex "derni(e|Ã¨|Ã©)re?s?"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (token:_:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt . cycleN True grain $ - n
      _ -> Nothing
  }

ruleNthTimeOfTime :: Rule
ruleNthTimeOfTime = Rule
  { name = "nth <day-of-week> of <month-or-greater>"
  , pattern =
    [ dimension Ordinal
    , Predicate isADayOfWeek
    , regex "d[eu]"
    , Predicate $ not . isGrainFinerThan TG.Month
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal od:Token Time td1:_:Token Time td2:_) -> Token Time .
        predNth (TOrdinal.value od - 1) False <$> intersect td2 td1
      _ -> Nothing
  }

ruleTheNthTimeOfTime :: Rule
ruleTheNthTimeOfTime = Rule
  { name = "the nth <day-of-week> of <month-or-greater>"
  , pattern =
    [ regex "le"
    , dimension Ordinal
    , Predicate isADayOfWeek
    , regex "d[eu]"
    , Predicate $ not . isGrainFinerThan TG.Month
    ]
  , prod = \tokens -> case tokens of
      (_:Token Ordinal od:Token Time td1:_:Token Time td2:_) -> Token Time .
         predNth (TOrdinal.value od - 1) False <$> intersect td2 td1
      _ -> Nothing
  }

ruleAvantTimeofday :: Rule
ruleAvantTimeofday = Rule
  { name = "avant <time-of-day>"
  , pattern =
    [ regex "(n[ ']importe quand )?(avant|jusqu'(a|Ã ))"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ withDirection TTime.Before td
      _ -> Nothing
  }

ruleEntreDatetimeEtDatetimeInterval :: Rule
ruleEntreDatetimeEtDatetimeInterval = Rule
  { name = "entre <datetime> et <datetime> (interval)"
  , pattern =
    [ regex "entre"
    , dimension Time
    , regex "et"
    , dimension Time
    ]
  , prod = \case
      (_:Token Time td1:_:Token Time td2:_)
        | sameGrain td1 td2 ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleDuDatetimedayofweekDdMonthinterval :: Rule
ruleDuDatetimedayofweekDdMonthinterval = Rule
  { name = "du <datetime>-<day-of-week> dd <month>(interval)"
  , pattern =
    [ regex "du"
    , dimension Time
    , regex "\\-|(jusqu')?au"
    , Predicate isADayOfWeek
    , Predicate isDOMValue
    , Predicate isAMonth
    ]
  , prod = \case
      (_:Token Time td1:_:_:token:Token Time td2:_) -> do
        from <- intersect td2 td1
        to <- intersectDOM td2 token
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleDuDdAuDdLatentMonthInterval :: Rule
ruleDuDdAuDdLatentMonthInterval = Rule
  { name = "du dd au dd (interval) (latent month)"
  , pattern =
    [ regex "du"
    , Predicate isDOMValue
    , regex "(jusqu')?au"
    , Predicate isDOMValue
    ]
  , prod = \case
      (_:token1:_:token2:_) -> do
        n1 <- getIntValue token1
        n2 <- getIntValue token2
        Token Time <$> interval TTime.Closed (dayOfMonth n1) (dayOfMonth n2)
      _ -> Nothing
  }

ruleDatetimedayofweekDdMonthinterval :: Rule
ruleDatetimedayofweekDdMonthinterval = Rule
  { name = "<datetime>-<day-of-week> dd <month>(interval)"
  , pattern =
    [ Predicate $ isGrainOfTime TG.Day
    , regex "\\-|(jusqu')?au"
    , Predicate isADayOfWeek
    , Predicate isDOMValue
    , Predicate isAMonth
    ]
  , prod = \case
      (Token Time td1:_:_:token:Token Time td2:_) -> do
        from <- intersect td2 td1
        to <- intersectDOM td2 token
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleEntreDdEtDdMonthinterval :: Rule
ruleEntreDdEtDdMonthinterval = Rule
  { name = "entre dd et dd <month>(interval)"
  , pattern =
    [ regex "entre( le)?"
    , Predicate isDOMValue
    , regex "et( le)?"
    , Predicate isDOMValue
    , Predicate isAMonth
    ]
  , prod = \case
      (_:token1:_:token2:Token Time td:_) -> do
        dom1 <- intersectDOM td token1
        dom2 <- intersectDOM td token2
        Token Time <$> interval TTime.Closed dom1 dom2
      _ -> Nothing
  }

ruleDatetimeddMonthinterval :: Rule
ruleDatetimeddMonthinterval = Rule
  { name = "<datetime>-dd <month>(interval)"
  , pattern =
    [ Predicate $ isGrainOfTime TG.Day
    , regex "\\-|(jusqu')?au"
    , Predicate isDOMValue
    , Predicate isAMonth
    ]
  , prod = \case
      (Token Time td1:_:token:Token Time td2:_) -> do
        from <- intersect td2 td1
        to <- intersectDOM td2 token
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleDuDdAuDdMonthInterval :: Rule
ruleDuDdAuDdMonthInterval = Rule
  { name = "du dd/nth au dd/nth month (interval)"
  , pattern =
    [ regex "du"
    , Predicate isDOMValue
    , regex "\\-|au|jusqu'(au?|Ã )"
    , Predicate isDOMValue
    , Predicate isAMonth
    ]
  , prod = \case
      (_:token1:_:token2:Token Time td:_) -> do
        dom1 <- intersectDOM td token1
        dom2 <- intersectDOM td token2
        Token Time <$> interval TTime.Closed dom1 dom2
      _ -> Nothing
  }

ruleHhhmmTimeofday :: Rule
ruleHhhmmTimeofday = Rule
  { name = "hh(:|h)mm (time-of-day)"
  , pattern =
    [ regex "((?:[01]?\\d)|(?:2[0-3]))[:h]([0-5]\\d)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
        h <- parseInt m1
        m <- parseInt m2
        tt $ hourMinute (h < 12) h m
      _ -> Nothing
  }

ruleDdMm :: Rule
ruleDdMm = Rule
  { name = "dd mm"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9]) (1[0-2]|0?[1-9])"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (dd:mm:_)):_) -> do
        m <- parseInt mm
        d <- parseInt dd
        tt $ monthDay m d
      _ -> Nothing
  }

ruleDdMmYyyy :: Rule
ruleDdMmYyyy = Rule
  { name = "dd mm yyyy"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9]) (1[0-2]|0?[1-9]) (\\d{2,4})"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (dd:mm:yy:_)):_) -> do
        y <- parseInt yy
        m <- parseInt mm
        d <- parseInt dd
        tt $ yearMonthDay y m d
      _ -> Nothing
  }

ruleNamedmonthProchain :: Rule
ruleNamedmonthProchain = Rule
  { name = "<named-month> prochain"
  , pattern =
    [ dimension Time
    , regex "prochain"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) ->
        tt $ predNth 1 False td
      _ -> Nothing
  }

ruleDiciDuration :: Rule
ruleDiciDuration = Rule
  { name = "d'ici <duration>"
  , pattern =
    [ regex "d'ici|dans l('|es?)"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) ->
        Token Time <$> interval TTime.Open now (inDuration dd)
      _ -> Nothing
  }

ruleToussaint :: Rule
ruleToussaint = Rule
  { name = "toussaint"
  , pattern =
    [ regex "((la |la journ(Ã©|e)e de la |jour de la )?toussaint|jour des morts)"
    ]
  , prod = \_ -> tt $ monthDay 11 1
  }

ruleDernierCycleDeTimeLatent :: Rule
ruleDernierCycleDeTimeLatent = Rule
  { name = "dernier <cycle> de <time> (latent)"
  , pattern =
    [ regex "derni(e|Ã©|Ã¨)re?"
    , dimension TimeGrain
    , regex "d['e]"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleLastOf grain td
      _ -> Nothing
  }

ruleDurationApresTime :: Rule
ruleDurationApresTime = Rule
  { name = "<duration> apres <time>"
  , pattern =
    [ dimension Duration
    , regex "apr(e|Ã¨)s"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_:Token Time td:_) ->
        tt $ durationAfter dd td
      _ -> Nothing
  }

ruleNCycleAprs :: Rule
ruleNCycleAprs = Rule
  { name = "n <cycle> aprÃ¨s"
  , pattern =
    [ Predicate $ isIntegerBetween 2 9999
    , dimension TimeGrain
    , regex "(d')? ?apr(e|Ã¨|Ã©)s|qui sui(t|ves?)|plus tard"
    ]
  , prod = \tokens -> case tokens of
      (token:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt $ cycleNth grain n
      _ -> Nothing
  }

ruleSeason4 :: Rule
ruleSeason4 = Rule
  { name = "season"
  , pattern =
    [ regex "(ce )?printemps"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (monthDay 3 20) (monthDay 6 21)
  }

ruleYearLatent2 :: Rule
ruleYearLatent2 = Rule
  { name = "year (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 2101 10000
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        n <- getIntValue token
        tt . mkLatent $ year n
      _ -> Nothing
  }

ruleNCycleAvant :: Rule
ruleNCycleAvant = Rule
  { name = "n <cycle> avant"
  , pattern =
    [ Predicate $ isIntegerBetween 2 9999
    , dimension TimeGrain
    , regex "(d')? ?avant|plus t(o|Ã´)t"
    ]
  , prod = \tokens -> case tokens of
      (token:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt . cycleNth grain $ - n
      _ -> Nothing
  }

ruleDimTimeDuMatin :: Rule
ruleDimTimeDuMatin = Rule
  { name = "<dim time> du matin"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "((du|dans|de) )?((au|le|la) )?mat(in(Ã©|e)?e?)?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> do
        morning <- partOfDay . mkLatent <$>
          interval TTime.Open (hour False 0) (hour False 12)
        Token Time <$> intersect td morning
      _ -> Nothing
  }

ruleOrdinalWeekendDeTime :: Rule
ruleOrdinalWeekendDeTime = Rule
  { name = "<ordinal> week-end de <time>"
  , pattern =
    [ dimension Ordinal
    , regex "week(\\s|-)?end (d['eu]|en|du mois de)"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (token:_:Token Time td:_) -> do
        n <- getIntValue token
        td2 <- intersect td weekend
        tt $ predNth (n - 1) False td2
      _ -> Nothing
  }

ruleHourofdayEtQuart :: Rule
ruleHourofdayEtQuart = Rule
  { name = "<hour-of-day> et quart"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "(et )?quart"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 15
      _ -> Nothing
  }

ruleHourofdayEtDemi :: Rule
ruleHourofdayEtDemi = Rule
  { name = "<hour-of-day> et demi"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "et demie?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 30
      _ -> Nothing
  }

ruleHourofdayEtTroisQuart :: Rule
ruleHourofdayEtTroisQuart = Rule
  { name = "<hour-of-day> et trois quarts"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "(et )?(3|trois) quarts?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 45
      _ -> Nothing
  }

ruleHourofdayEtpassDeNumeral :: Rule
ruleHourofdayEtpassDeNumeral = Rule
  { name = "<hour-of-day> et|passÃ© de <number>"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "et|(pass(Ã©|e)e? de)"
    , Predicate $ isIntegerBetween 1 59
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _:
       token:
       _) -> do
        n <- getIntValue token
        tt $ hourMinute is12H hours n
      _ -> Nothing
  }

ruleHourofdayEtpassDeNumeralMinutes :: Rule
ruleHourofdayEtpassDeNumeralMinutes = Rule
  { name = "<hour-of-day> et|passÃ© de <number> minutes"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "et|(pass(Ã©|e)e? de)"
    , Predicate $ isIntegerBetween 1 59
    , regex "min\\.?(ute)?s?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _:
       token:
       _) -> do
        n <- getIntValue token
        tt $ hourMinute is12H hours n
      _ -> Nothing
  }

ruleHourofdayInteger :: Rule
ruleHourofdayInteger = Rule
  { name = "<hour-of-day> <integer> (as relative minutes)"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isAnHourOfDay, hasNoDirection]
    , Predicate $ isIntegerBetween 1 59
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       token:
       _) -> do
        n <- getIntValue token
        tt $ hourMinute is12H hours n
      _ -> Nothing
  }

ruleHourofdayIntegerMinutes :: Rule
ruleHourofdayIntegerMinutes = Rule
  { name = "<hour-of-day> <integer> minutes"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isAnHourOfDay]
    , Predicate $ isIntegerBetween 1 59
    , regex "min\\.?(ute)?s?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       token:
       _) -> do
        n <- getIntValue token
        tt $ hourMinute is12H hours n
      _ -> Nothing
  }

ruleHourofdayMoinsIntegerAsRelativeMinutes :: Rule
ruleHourofdayMoinsIntegerAsRelativeMinutes = Rule
  { name = "<hour-of-day> moins <integer> (as relative minutes)"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "moins( le)?"
    , Predicate $ isIntegerBetween 1 59
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_:token:_) -> do
        n <- getIntValue token
        Token Time <$> minutesBefore n td
      _ -> Nothing
  }

ruleHourofdayMoinsQuart :: Rule
ruleHourofdayMoinsQuart = Rule
  { name = "<hour-of-day> moins quart"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "moins( le)? quart"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> Token Time <$> minutesBefore 15 td
      _ -> Nothing
  }

ruleAprsLeDayofmonth :: Rule
ruleAprsLeDayofmonth = Rule
  { name = "aprÃ¨s le <day-of-month>"
  , pattern =
    [ regex "(apr(e|Ã¨)s le|(a|Ã ) partir du)"
    , Predicate isDOMInteger
    ]
  , prod = \tokens -> case tokens of
      (_:token:_) -> do
        n <- getIntValue token
        tt . withDirection TTime.After $ dayOfMonth n
      _ -> Nothing
  }

ruleCycleDernier :: Rule
ruleCycleDernier = Rule
  { name = "<cycle> dernier"
  , pattern =
    [ dimension TimeGrain
    , regex "derni(Ã¨|e)re?|pass(Ã©|e)e?|pr(e|Ã©)c(e|Ã©)dente?|(d')? ?avant"
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_) ->
        tt . cycleNth grain $ - 1
      _ -> Nothing
  }

ruleLeOrdinalCycleDeTime :: Rule
ruleLeOrdinalCycleDeTime = Rule
  { name = "le <ordinal> <cycle> de <time>"
  , pattern =
    [ regex "l[ea]"
    , dimension Ordinal
    , dimension TimeGrain
    , regex "d['eu]|en"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:token:Token TimeGrain grain:_:Token Time td:_) -> do
        n <- getIntValue token
        tt $ cycleNthAfter True grain (n - 1) td
      _ -> Nothing
  }

ruleEnSemaine :: Rule
ruleEnSemaine = Rule
  { name = "en semaine"
  , pattern =
    [ regex "(pendant la |en )?semaine"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (dayOfWeek 1) (dayOfWeek 5)
  }

ruleDdmm :: Rule
ruleDdmm = Rule
  { name = "dd/-mm"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9])[/-](1[0-2]|0?[1-9])"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (dd:mm:_)):_) -> do
        m <- parseInt mm
        d <- parseInt dd
        tt $ monthDay m d
      _ -> Nothing
  }

ruleNamedmonthnameddayDernierpass :: Rule
ruleNamedmonthnameddayDernierpass = Rule
  { name = "<named-month|named-day> dernier|passÃ©"
  , pattern =
    [ Predicate $ isGrainCoarserThan TG.Hour
    , regex "derni(e|Ã©|Ã¨)re?|pass(Ã©|e)e?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) ->
        tt $ predNth (-1) False td
      _ -> Nothing
  }

ruleLeCycleDernier :: Rule
ruleLeCycleDernier = Rule
  { name = "le <cycle> dernier"
  , pattern =
    [ regex "l[ae']? ?"
    , dimension TimeGrain
    , regex "derni(Ã¨|e)re?|pass(Ã©|e)e?"
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) ->
        tt . cycleNth grain $ - 1
      _ -> Nothing
  }

ruleNCyclePassesprecedents :: Rule
ruleNCyclePassesprecedents = Rule
  { name = "n <cycle> passes|precedents"
  , pattern =
    [ Predicate $ isIntegerBetween 2 9999
    , dimension TimeGrain
    , regex "pass(e|Ã¨|Ã©)(e|Ã¨|Ã©)?s?|pr(e|Ã©)c(e|Ã©)dente?s?|(d')? ?avant|plus t(o|Ã´)t"
    ]
  , prod = \tokens -> case tokens of
      (token:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt . cycleN True grain $ - n
      _ -> Nothing
  }

ruleSoir :: Rule
ruleSoir = Rule
  { name = "soir"
  , pattern =
    [ regex "soir(Ã©|e)?e?"
    ]
  , prod = \_ -> Token Time . mkLatent . partOfDay <$>
      interval TTime.Open (hour False 18) (hour False 0)
  }

ruleDdddMonthinterval :: Rule
ruleDdddMonthinterval = Rule
  { name = "dd-dd <month>(interval)"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9])"
    , regex "\\-|(jusqu')?au"
    , regex "(3[01]|[12]\\d|0?[1-9])"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:_)):_:Token RegexMatch (GroupMatch (m2:_)):Token Time td:_) -> do
        d1 <- parseInt m1
        d2 <- parseInt m2
        from <- intersect td (dayOfMonth d1)
        to <- intersect td (dayOfMonth d2)
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleTimeofdayLatent :: Rule
ruleTimeofdayLatent = Rule
  { name = "time-of-day (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 0 23
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        n <- getIntValue token
        tt . mkLatent $ hour (n < 12) n
      _ -> Nothing
  }

ruleDuDddayofweekDdMonthinterval :: Rule
ruleDuDddayofweekDdMonthinterval = Rule
  { name = "du dd-<day-of-week> dd <month>(interval)"
  , pattern =
    [ regex "du"
    , regex "(3[01]|[12]\\d|0?[1-9])"
    , regex "\\-|(jusqu')?au"
    , Predicate isADayOfWeek
    , regex "(3[01]|[12]\\d|0?[1-9])"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token RegexMatch (GroupMatch (m1:_)):_:_:Token RegexMatch (GroupMatch (m2:_)):Token Time td:_) -> do
        d1 <- parseInt m1
        d2 <- parseInt m2
        from <- intersect (dayOfMonth d1) td
        to <- intersect (dayOfMonth d2) td
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleDbutNamedmonthinterval :: Rule
ruleDbutNamedmonthinterval = Rule
  { name = "dÃ©but <named-month>(interval)"
  , pattern =
    [ regex "d(Ã©|e)but( du mois d[e'] ?)?"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> do
        from <- intersect (dayOfMonth 1) td
        to <- intersect (dayOfMonth 5) td
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleLeCycleDeTime :: Rule
ruleLeCycleDeTime = Rule
  { name = "le <cycle> de <time>"
  , pattern =
    [ regex "l[ea]"
    , dimension TimeGrain
    , regex "d['eu]|en"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter True grain 0 td
      _ -> Nothing
  }

ruleSeason3 :: Rule
ruleSeason3 = Rule
  { name = "season"
  , pattern =
    [ regex "(cet )?hiver"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (monthDay 12 21) (monthDay 3 20)
  }

ruleSeason :: Rule
ruleSeason = Rule
  { name = "season"
  , pattern =
    [ regex "(cet )?(Ã©|e)t(Ã©|e)"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (monthDay 6 21) (monthDay 9 23)
  }

ruleAprsmidi :: Rule
ruleAprsmidi = Rule
  { name = "aprÃ¨s-midi"
  , pattern =
    [ regex "apr(e|Ã©|Ã¨)s( |\\-)midi"
    ]
  , prod = \_ -> Token Time . mkLatent . partOfDay <$>
      interval TTime.Open (hour False 12) (hour False 19)
  }

ruleNoel :: Rule
ruleNoel = Rule
  { name = "noel"
  , pattern =
    [ regex "(jour de )?no(e|Ã«)l"
    ]
  , prod = \_ -> tt $ monthDay 12 25
  }

ruleDayofweekProchain :: Rule
ruleDayofweekProchain = Rule
  { name = "<day-of-week> prochain"
  , pattern =
    [ Predicate isADayOfWeek
    , regex "prochain"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) ->
        tt $ predNth 0 True td
      _ -> Nothing
  }

ruleDemain :: Rule
ruleDemain = Rule
  { name = "demain"
  , pattern =
    [ regex "(le len)?demain"
    ]
  , prod = \_ -> tt $ cycleNth TG.Day 1
  }

ruleNamedmonthnameddaySuivantdaprs :: Rule
ruleNamedmonthnameddaySuivantdaprs = Rule
  { name = "<named-month|named-day> suivant|d'aprÃ¨s"
  , pattern =
    [ Predicate $ isGrainCoarserThan TG.Hour
    , regex "suivante?s?|d'apr(e|Ã©|Ã¨)s"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) ->
        tt $ predNth 1 False td
      _ -> Nothing
  }

ruleNameddayEnHuit :: Rule
ruleNameddayEnHuit = Rule
  { name = "<named-day> en huit"
  , pattern =
    [ Predicate isADayOfWeek
    , regex "en (huit|8)"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) ->
        tt $ predNth 1 False td
      _ -> Nothing
  }

ruleHhmmMilitaryTimeofday :: Rule
ruleHhmmMilitaryTimeofday = Rule
  { name = "hhmm (military time-of-day)"
  , pattern =
    [ regex "((?:[01]?\\d)|(?:2[0-3]))([0-5]\\d)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
        h <- parseInt m1
        m <- parseInt m2
        tt . mkLatent $ hourMinute False h m
      _ -> Nothing
  }

ruleDimTimeDuSoir :: Rule
ruleDimTimeDuSoir = Rule
  { name = "<dim time> du soir"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "((du|dans|de) )?((au|le|la) )?soir(Ã©|e)?e?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> do
        td2 <- mkLatent . partOfDay <$>
          interval TTime.Open (hour False 16) (hour False 0)
        Token Time <$> intersect td td2
      _ -> Nothing
  }

ruleAprsTimeofday :: Rule
ruleAprsTimeofday = Rule
  { name = "aprÃ¨s <time-of-day|day>"
  , pattern =
    [ regex "(apr(e|Ã¨)s|(a|Ã ) partir de|(un peu )?plus tard que)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ withDirection TTime.After td
      _ -> Nothing
  }

ruleAprsLeDjeuner :: Rule
ruleAprsLeDjeuner = Rule
  { name = "aprÃ¨s le dÃ©jeuner"
  , pattern =
    [ regex "apr(e|Ã¨)s (le )?d(e|Ã©|Ã¨)jeuner"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 13) (hour False 17)
      Token Time . partOfDay <$> intersect today td2
  }

ruleIntersect :: Rule
ruleIntersect = Rule
  { name = "intersect"
  , pattern =
    [ Predicate isNotLatent
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleErMai :: Rule
ruleErMai = Rule
  { name = "1er mai"
  , pattern =
    [ regex "f(e|Ãª)te du travail"
    ]
  , prod = \_ -> tt $ monthDay 5 1
  }

rulePremireQuinzaineDeNamedmonthinterval :: Rule
rulePremireQuinzaineDeNamedmonthinterval = Rule
  { name = "premiÃ¨re quinzaine de <named-month>(interval)"
  , pattern =
    [ regex "(premi(Ã¨|e)re|1 ?(Ã¨|e)re) (quinzaine|15 ?aine) d[e']"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> do
        from <- intersect (dayOfMonth 1) td
        to <- intersect (dayOfMonth 14) td
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleDeDatetimeDatetimeInterval :: Rule
ruleDeDatetimeDatetimeInterval = Rule
  { name = "de <datetime> - <datetime> (interval)"
  , pattern =
    [ regex "de|depuis|du"
    , dimension Time
    , regex "\\-|au|jusqu'(au?|Ã )"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_)
        | sameGrain td1 td2 ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleAvanthier :: Rule
ruleAvanthier = Rule
  { name = "avant-hier"
  , pattern =
    [ regex "avant[- ]?hier"
    ]
  , prod = \_ -> tt . cycleNth TG.Day $ - 2
  }

ruleCycleProchainsuivantdaprs :: Rule
ruleCycleProchainsuivantdaprs = Rule
  { name = "<cycle> prochain|suivant|d'aprÃ¨s"
  , pattern =
    [ dimension TimeGrain
    , regex "prochaine?|suivante?|qui suit|(d')? ?apr(e|Ã¨|Ã©)s"
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_) ->
        tt $ cycleNth grain 1
      _ -> Nothing
  }

ruleAprsLeTravail :: Rule
ruleAprsLeTravail = Rule
  { name = "aprÃ¨s le travail"
  , pattern =
    [ regex "apr(e|Ã¨)s (le )?travail"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 17) (hour False 21)
      Token Time . partOfDay <$> intersect today td2
  }

ruleLeDayofmonthDatetime :: Rule
ruleLeDayofmonthDatetime = Rule
  { name = "le <day-of-month> Ã  <datetime>"
  , pattern =
    [ regex "le"
    , Predicate isDOMInteger
    , regex "(a|Ã )"
    , Predicate $ isGrainFinerThan TG.Day
    ]
  , prod = \tokens -> case tokens of
      (_:token:_:Token Time td:_) -> do
        n <- getIntValue token
        Token Time <$> intersect (dayOfMonth n) td
      _ -> Nothing
  }

ruleWeekend :: Rule
ruleWeekend = Rule
  { name = "week-end"
  , pattern =
    [ regex "week(\\s|-)?end"
    ]
  , prod = \_ -> tt weekend
  }

ruleCedansLeCycle :: Rule
ruleCedansLeCycle = Rule
  { name = "ce|dans le <cycle>"
  , pattern =
    [ regex "(cet?t?e?s?)|(dans l[ae']? ?)"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) ->
        tt $ cycleNth grain 0
      _ -> Nothing
  }

ruleDansDuration :: Rule
ruleDansDuration = Rule
  { name = "dans <duration>"
  , pattern =
    [ regex "dans"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) ->
        tt $ inDuration dd
      _ -> Nothing
  }

ruleOrdinalCycleDeTime :: Rule
ruleOrdinalCycleDeTime = Rule
  { name = "<ordinal> <cycle> de <time>"
  , pattern =
    [ dimension Ordinal
    , dimension TimeGrain
    , regex "d['eu]|en"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (token:Token TimeGrain grain:_:Token Time td:_) -> do
        n <- getIntValue token
        tt $ cycleNthAfter True grain (n - 1) td
      _ -> Nothing
  }

ruleAvantLeDjeuner :: Rule
ruleAvantLeDjeuner = Rule
  { name = "avant le dÃ©jeuner"
  , pattern =
    [ regex "avant (le )?d(e|Ã©|Ã¨)jeuner"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 10) (hour False 12)
      Token Time . partOfDay <$> intersect today td2
  }

ruleDernierWeekendDeTime :: Rule
ruleDernierWeekendDeTime = Rule
  { name = "dernier week-end de <time>"
  , pattern =
    [ regex "dernier week(\\s|-)?end (d['eu]|en|du mois de)"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> do
        tt $ predLastOf weekend td
      _ -> Nothing
  }

ruleLeCycleProchainsuivantdaprs :: Rule
ruleLeCycleProchainsuivantdaprs = Rule
  { name = "le <cycle> prochain|suivant|d'aprÃ¨s"
  , pattern =
    [ regex "l[ae']? ?|une? ?"
    , dimension TimeGrain
    , regex "prochaine?|suivante?|qui suit|(d'? ?)?apr(e|Ã¨|Ã©)s"
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) ->
        tt $ cycleNth grain 1
      _ -> Nothing
  }

ruleDimTimePartofday :: Rule
ruleDimTimePartofday = Rule
  { name = "<dim time> <part-of-day>"
  , pattern =
    [ Predicate $ isGrainOfTime TG.Day
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleEnNamedmonth :: Rule
ruleEnNamedmonth = Rule
  { name = "en <named-month>"
  , pattern =
    [ regex "en|au mois de?'?"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:x:_) -> Just x
      _ -> Nothing
  }

ruleEntreTimeofdayEtTimeofdayInterval :: Rule
ruleEntreTimeofdayEtTimeofdayInterval = Rule
  { name = "entre <time-of-day> et <time-of-day> (interval)"
  , pattern =
    [ regex "entre"
    , Predicate isATimeOfDay
    , regex "et"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleIntersectByDeOr :: Rule
ruleIntersectByDeOr = Rule
  { name = "intersect by 'de' or ','"
  , pattern =
    [ Predicate isNotLatent
    , regex "de|,"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleDeuximeQuinzaineDeNamedmonthinterval :: Rule
ruleDeuximeQuinzaineDeNamedmonthinterval = Rule
  { name = "deuxiÃ¨me quinzaine de <named-month>(interval)"
  , pattern =
    [ regex "(deuxi(Ã¨|e)me|2 ?(Ã¨|e)me) (quinzaine|15 ?aine) d[e']"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> do
        from <- intersect (dayOfMonth 15) td
        let to = cycleLastOf TG.Day td
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

rulePartofdayDuDimTime :: Rule
rulePartofdayDuDimTime = Rule
  { name = "<part-of-day> du <dim time>"
  , pattern =
    [ Predicate isAPartOfDay
    , regex "du"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleYyyymmdd :: Rule
ruleYyyymmdd = Rule
  { name = "yyyy-mm-dd"
  , pattern =
    [ regex "(\\d{2,4})-(1[0-2]|0?[1-9])-(3[01]|[12]\\d|0?[1-9])"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
        y <- parseInt m1
        m <- parseInt m2
        d <- parseInt m3
        tt $ yearMonthDay y m d
      _ -> Nothing
  }

ruleTimeofdayHeures :: Rule
ruleTimeofdayHeures = Rule
  { name = "<time-of-day> heures"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "h\\.?(eure)?s?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) ->
        tt $ notLatent td
      _ -> Nothing
  }

ruleDernierDayofweekDeTimeLatent :: Rule
ruleDernierDayofweekDeTimeLatent = Rule
  { name = "dernier <day-of-week> de <time> (latent)"
  , pattern =
    [ regex "derni(e|Ã©|Ã¨)re?"
    , Predicate isADayOfWeek
    , regex "d['e]"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        tt $ predLastOf td1 td2
      _ -> Nothing
  }

ruleCeDayofweek :: Rule
ruleCeDayofweek = Rule
  { name = "ce <day-of-week>"
  , pattern =
    [ regex "ce"
    , Predicate isADayOfWeek
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth 0 True td
      _ -> Nothing
  }

ruleMatin :: Rule
ruleMatin = Rule
  { name = "matin"
  , pattern =
    [ regex "mat(in(Ã©|e)?e?)?"
    ]
  , prod = \_ -> Token Time . mkLatent . partOfDay <$>
      interval TTime.Open (hour False 4) (hour False 12)
  }

ruleYearLatent :: Rule
ruleYearLatent = Rule
  { name = "year (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 1 999
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        n <- getIntValue token
        tt . mkLatent $ year n
      _ -> Nothing
  }

ruleSeason2 :: Rule
ruleSeason2 = Rule
  { name = "season"
  , pattern =
    [ regex "(cet )?automne"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (monthDay 9 23) (monthDay 12 21)
  }

ruleVersTimeofday :: Rule
ruleVersTimeofday = Rule
  { name = "Ã |vers <time-of-day>"
  , pattern =
    [ regex "(vers|autour de|(a|Ã ) environ|aux alentours de|(a|Ã ))"
    , Predicate $ and . sequence [isATimeOfDay, isNotLatent]
    ]
  , prod = \tokens -> case tokens of
      (_:x:_) -> Just x
      _ -> Nothing
  }

ruleFinNamedmonthinterval :: Rule
ruleFinNamedmonthinterval = Rule
  { name = "fin <named-month>(interval)"
  , pattern =
    [ regex "fin( du mois d[e']? ?)?"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> do
        from <- intersect (dayOfMonth 21) td
        let to = cycleLastOf TG.Day td
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleDayofweekDayofmonth :: Rule
ruleDayofweekDayofmonth = Rule
  { name = "<day-of-week> <day-of-month>"
  , pattern =
    [ Predicate isADayOfWeek
    , Predicate isDOMInteger
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:token:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleNameddayEnQuinze :: Rule
ruleNameddayEnQuinze = Rule
  { name = "<named-day> en quinze"
  , pattern =
    [ Predicate isADayOfWeek
    , regex "en (quinze|15)"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) ->
        tt $ predNth 2 False td
      _ -> Nothing
  }

ruleLeDayofmonthNonOrdinal :: Rule
ruleLeDayofmonthNonOrdinal = Rule
  { name = "le <day-of-month> (non ordinal)"
  , pattern =
    [ regex "le"
    , Predicate isDOMInteger
    ]
  , prod = \tokens -> case tokens of
      (_:token:_) -> do
        n <- getIntValue token
        tt $ dayOfMonth n
      _ -> Nothing
  }

ruleIntersectByMaisparExempleplutt :: Rule
ruleIntersectByMaisparExempleplutt = Rule
  { name = "intersect by 'mais/par exemple/plutÃ´t'"
  , pattern =
    [ Predicate isNotLatent
    , regex "mais|par exemple|plut(Ã´|o)t"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleLeCycleAprssuivantTime :: Rule
ruleLeCycleAprssuivantTime = Rule
  { name = "le <cycle> aprÃ¨s|suivant <time>"
  , pattern =
    [ regex "l[ea']?"
    , dimension TimeGrain
    , regex "suivante?|apr(e|Ã¨|Ã©)s"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain 1 td
      _ -> Nothing
  }

ruleAprsdemain :: Rule
ruleAprsdemain = Rule
  { name = "aprÃ¨s-demain"
  , pattern =
    [ regex "apr(e|Ã¨)s[- ]?demain"
    ]
  , prod = \_ -> tt $ cycleNth TG.Day 2
  }

ruleIlYADuration :: Rule
ruleIlYADuration = Rule
  { name = "il y a <duration>"
  , pattern =
    [ regex "il y a"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) ->
        tt $ durationAgo dd
      _ -> Nothing
  }

ruleDudansLePartofday :: Rule
ruleDudansLePartofday = Rule
  { name = "du|dans le <part-of-day>"
  , pattern =
    [ regex "du|dans l[ae']? ?|au|en|l[ae' ]|d(Ã¨|e)s l?[ae']?"
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ notLatent td
      _ -> Nothing
  }

ruleAuDjeuner :: Rule
ruleAuDjeuner = Rule
  { name = "au dÃ©jeuner"
  , pattern =
    [ regex "((Ã |a) l'heure du|au moment de|pendant( le)?|au)? d(e|Ã©|Ã¨)jeuner"
    ]
  , prod = \_ -> Token Time . partOfDay <$>
      interval TTime.Open (hour False 12) (hour False 14)
  }

ruleYear :: Rule
ruleYear = Rule
  { name = "year"
  , pattern =
    [ Predicate $ isIntegerBetween 1000 2100
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        n <- getIntValue token
        tt $ year n
      _ -> Nothing
  }

ruleMaintenant :: Rule
ruleMaintenant = Rule
  { name = "maintenant"
  , pattern =
    [ regex "maintenant|tout de suite"
    ]
  , prod = \_ -> tt now
  }

ruleDdmmyyyy :: Rule
ruleDdmmyyyy = Rule
  { name = "dd/-mm/-yyyy"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9])[/-](1[0-2]|0?[1-9])[-/](\\d{2,4})"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
        y <- parseInt m3
        m <- parseInt m2
        d <- parseInt m1
        tt $ yearMonthDay y m d
      _ -> Nothing
  }

ruleLeCycleAvantprcdentTime :: Rule
ruleLeCycleAvantprcdentTime = Rule
  { name = "le <cycle> avant|prÃ©cÃ©dent <time>"
  , pattern =
    [ regex "l[ea']?"
    , dimension TimeGrain
    , regex "avant|pr(Ã©|e)c(Ã©|e)dent"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain (-1) td
      _ -> Nothing
  }

ruleDayOfMonthPremier :: Rule
ruleDayOfMonthPremier = Rule
  { name = "day of month (premier)"
  , pattern =
    [ regex "premier|prem\\.?|1 ?er"
    ]
  , prod = \_ -> tt $ dayOfMonth 1
  }

ruleTimeofdayTimeofdayInterval :: Rule
ruleTimeofdayTimeofdayInterval = Rule
  { name = "<time-of-day> - <time-of-day> (interval)"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "\\-|(jusqu')?(au?|Ã )"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleLeVeilleDuTime :: Rule
ruleLeVeilleDuTime = Rule
  { name = "le veille du <time>"
  , pattern =
    [ regex "(la )?veille du"
    , Predicate $ isGrainCoarserThan TG.Hour
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ cycleNthAfter True TG.Day (-1) td
      _ -> Nothing
  }

ruleLeTime :: Rule
ruleLeTime = Rule
  { name = "le <time>"
  , pattern =
    [ regex "l[ea]"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (_:x:_) -> Just x
      _ -> Nothing
  }

ruleSoirDeNol :: Rule
ruleSoirDeNol = Rule
  { name = "soir de noÃ«l"
  , pattern =
    [ regex "soir(Ã©e)? de no(e|Ã«)l"
    ]
  , prod = \_ -> do
      from <- intersect (monthDay 12 24) (hour False 18)
      to <- intersect (monthDay 12 25) (hour False 0)
      Token Time <$> interval TTime.Open from to
  }

ruleDayofweekDayofmonthTimeofday :: Rule
ruleDayofweekDayofmonthTimeofday = Rule
  { name = "<day-of-week> <day-of-month> Ã  <time-of-day>)"
  , pattern =
    [ Predicate isADayOfWeek
    , Predicate isDOMInteger
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:token:Token Time td2:_) -> do
        dom <- intersectDOM td1 token
        Token Time <$> intersect dom td2
      _ -> Nothing
  }

ruleJourDeLan :: Rule
ruleJourDeLan = Rule
  { name = "jour de l'an"
  , pattern =
    [ regex "(jour de l'|nouvel )an"
    ]
  , prod = \_ -> tt $ monthDay 1 1
  }

ruleMinuit :: Rule
ruleMinuit = Rule
  { name = "minuit"
  , pattern =
    [ regex "minuit"
    ]
  , prod = \_ -> tt $ hour False 0
  }

ruleNCycleSuivants :: Rule
ruleNCycleSuivants = Rule
  { name = "n <cycle> suivants"
  , pattern =
    [ Predicate $ isIntegerBetween 2 9999
    , dimension TimeGrain
    , regex "prochaine?s?|suivante?s?|apr(e|Ã¨|Ã©)s|qui sui(t|ves?)|plus tard"
    ]
  , prod = \tokens -> case tokens of
      (token:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt $ cycleN True grain n
      _ -> Nothing
  }

ruleMidMonth :: Rule
ruleMidMonth = Rule
  { name = "<named-month>"
  , pattern =
    [ regex "mi[- ]"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> do
        from <- intersect (dayOfMonth 10) td
        to <- intersect (dayOfMonth 19) td
        Token Time <$> interval TTime.Open from to
      _ -> Nothing
  }

ruleDayofweekErdayofweekDdMonthinterval :: Rule
ruleDayofweekErdayofweekDdMonthinterval = Rule
  { name = "<day-of-week> 1er-<day-of-week> dd <month>(interval)"
  , pattern =
    [ Predicate isADayOfWeek
    , regex "premier|prem\\.?|1er|1 er"
    , regex "\\-|(jusqu')?au"
    , Predicate isADayOfWeek
    , regex "(3[01]|[12]\\d|0?[1-9])"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:_:_:_:Token RegexMatch (GroupMatch (m:_)):Token Time td:_) -> do
        n <- parseInt m
        from <- intersect (dayOfMonth 1) td
        to <- intersect (dayOfMonth n) td
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleFinDuMois :: Rule
ruleFinDuMois = Rule
  { name = "fin du mois"
  , pattern =
    [ regex "(en |((Ã |a) la ))?fin (du|de) (ce )?mois"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (dayOfMonth 21) (dayOfMonth 0)
  }

ruleDbutDuMois :: Rule
ruleDbutDuMois = Rule
  { name = "dÃ©but du mois"
  , pattern =
    [ regex "(en |au )?d(Ã©|e)but (du|de) (ce )?mois"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (dayOfMonth 1) (dayOfMonth 10)
  }

ruleFinDAnnee :: Rule
ruleFinDAnnee = Rule
  { name = "fin d'annÃ©e"
  , pattern =
    [ regex "(en |(Ã |a) la )?fin (d'|de l'|de cette )ann(Ã©|e)e"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (month 11) (month 1)
  }

ruleDbutDAnnee :: Rule
ruleDbutDAnnee = Rule
  { name = "dÃ©but d'annÃ©e"
  , pattern =
    [ regex "(en |au )?d(Ã©|e)but (d'|de l'|de cette )ann(Ã©|e)e"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (month 1) (month 3)
  }

rulePlusTard :: Rule
rulePlusTard = Rule
  { name = "plus tard"
  , pattern =
    [ regex "(un peu )?plus tard"
    ]
  , prod = \_ -> tt $ withDirection TTime.After $ cycleNth TG.Minute 10

  }

rulePlusTardPartofday :: Rule
rulePlusTardPartofday = Rule
  { name = "plus tard <part-of-day>"
  , pattern =
    [ regex "(un peu )?plus tard"
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleDDMonthYY :: Rule
ruleDDMonthYY = Rule
  { name = "DD month YY"
  , pattern =
    [ Predicate $ isIntegerBetween 0 31
    , Predicate isAMonth
    , Predicate $ isIntegerBetween 32 99
    ]
  , prod = \case
      (dayd:Token Time monthd:yeard:_) -> do
        d <- getIntValue dayd
        y <- getIntValue yeard
        dayMonth <- intersect monthd (dayOfMonth d)
        ymd <- intersect dayMonth (year y)
        tt ymd
      _ -> Nothing
  }

ruleTimezone :: Rule
ruleTimezone = Rule
  { name = "<time> timezone"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isATimeOfDay]
    , regex "\\b(YEKT|YEKST|YAKT|YAKST|WITA|WIT|WIB|WGT|WGST|WFT|WET|WEST|WAT|WAST|VUT|VLAT|VLAST|VET|UZT|UYT|UYST|UTC|ULAT|TVT|TMT|TLT|TKT|TJT|TFT|TAHT|SST|SRT|SGT|SCT|SBT|SAST|SAMT|RET|PYT|PYST|PWT|PST|PONT|PMST|PMDT|PKT|PHT|PHOT|PGT|PETT|PETST|PET|PDT|OMST|OMSST|NZST|NZDT|NUT|NST|NPT|NOVT|NOVST|NFT|NDT|NCT|MYT|MVT|MUT|MST|MSK|MSD|MMT|MHT|MDT|MAWT|MART|MAGT|MAGST|LINT|LHST|LHDT|KUYT|KST|KRAT|KRAST|KGT|JST|IST|IRST|IRKT|IRKST|IRDT|IOT|IDT|ICT|HOVT|HKT|GYT|GST|GMT|GILT|GFT|GET|GAMT|GALT|FNT|FKT|FKST|FJT|FJST|EST|EGT|EGST|EET|EEST|EDT|ECT|EAT|EAST|EASST|DAVT|ChST|CXT|CVT|CST|COT|CLT|CLST|CKT|CHAST|CHADT|CET|CEST|CDT|CCT|CAT|CAST|BTT|BST|BRT|BRST|BOT|BNT|AZT|AZST|AZOT|AZOST|AWST|AWDT|AST|ART|AQTT|ANAT|ANAST|AMT|AMST|ALMT|AKST|AKDT|AFT|AEST|AEDT|ADT|ACST|ACDT)\\b"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:
       Token RegexMatch (GroupMatch (tz:_)):
       _) -> Token Time <$> inTimezone (Text.toUpper tz) td
      _ -> Nothing
  }

ruleMonths :: [Rule]
ruleMonths = mkRuleMonths
  [ ( "Janvier"   , "janvier|janv\\.?"          )
  , ( "Fevrier"   , "f(Ã©|e)vrier|f(Ã©|e)v\\.?"   )
  , ( "Mars"      , "mars|mar\\.?"              )
  , ( "Avril"     , "avril|avr\\.?"             )
  , ( "Mai"       , "mai"                       )
  , ( "Juin"      , "juin|jun\\.?"              )
  , ( "Juillet"   , "juillet|juil?\\.?"         )
  , ( "Aout"      , "ao(Ã»|u)t|aou\\.?"          )
  , ( "Septembre" , "septembre|sept?\\.?"       )
  , ( "Octobre"   , "octobre|oct\\.?"           )
  , ( "Novembre"  , "novembre|nov\\.?"          )
  , ( "Decembre"  ,  "d(Ã©|e)cembre|d(Ã©|e)c\\.?" )
  ]

ruleDaysOfWeek :: [Rule]
ruleDaysOfWeek = mkRuleDaysOfWeek
  [ ( "Lundi"    , "lun\\.?(di)?"    )
  , ( "Mardi"    , "mar\\.?(di)?"    )
  , ( "Mercredi" , "mer\\.?(credi)?" )
  , ( "Jeudi"    , "jeu\\.?(di)?"    )
  , ( "Vendredi" , "ven\\.?(dredi)?" )
  , ( "Samedi"   , "sam\\.?(edi)?"   )
  , ( "Dimanche" , "dim\\.?(anche)?" )
  ]

rules :: [Rule]
rules =
  [ ruleAprsLeDayofmonth
  , ruleAprsLeDjeuner
  , ruleAprsLeTravail
  , ruleAprsTimeofday
  , ruleAprsdemain
  , ruleAprsmidi
  , ruleAuDjeuner
  , ruleAujourdhui
  , ruleAvantLeDjeuner
  , ruleAvantTimeofday
  , ruleAvanthier
  , ruleCeDayofweek
  , ruleCePartofday
  , ruleCeTime
  , ruleCedansLeCycle
  , ruleCycleDernier
  , ruleCycleProchainsuivantdaprs
  , ruleDansDuration
  , ruleDatetimeDatetimeInterval
  , ruleDatetimedayofweekDdMonthinterval
  , ruleDatetimeddMonthinterval
  , ruleDayOfMonthPremier
  , ruleDayofmonthNamedmonth
  , ruleDayofweekDayofmonth
  , ruleDayofweekDayofmonthTimeofday
  , ruleMidMonth
  , ruleDayofweekErdayofweekDdMonthinterval
  , ruleDayofweekProchain
  , ruleDbutDaprsmidi
  , ruleDbutDeJourne
  , ruleDbutDeMatine
  , ruleDbutDeSemaine
  , ruleDbutNamedmonthinterval
  , ruleDdMm
  , ruleDdMmYyyy
  , ruleDdddMonthinterval
  , ruleDdmm
  , ruleDdmmyyyy
  , ruleDeDatetimeDatetimeInterval
  , ruleDeTimeofdayTimeofdayInterval
  , ruleDemain
  , ruleDernierCycleDeTimeLatent
  , ruleDernierDayofweekDeTimeLatent
  , ruleDernierWeekendDeTime
  , ruleDeuximeQuinzaineDeNamedmonthinterval
  , ruleDiciDuration
  , ruleDimTimeDuMatin
  , ruleDimTimeDuSoir
  , ruleDimTimePartofday
  , ruleDuDatetimedayofweekDdMonthinterval
  , ruleDuDdAuDdLatentMonthInterval
  , ruleDuDdAuDdMonthInterval
  , ruleDuDddayofweekDdMonthinterval
  , ruleDudansLePartofday
  , ruleDurationApresTime
  , ruleDurationAvantTime
  , ruleEnNamedmonth
  , ruleEnSemaine
  , ruleEntreDatetimeEtDatetimeInterval
  , ruleEntreDdEtDdMonthinterval
  , ruleEntreTimeofdayEtTimeofdayInterval
  , ruleErMai
  , ruleMilieuDaprsmidi
  , ruleFinDaprsmidi
  , ruleMilieuDeJourne
  , ruleFinDeJourne
  , ruleMilieuDeMatine
  , ruleFinDeMatine
  , ruleFinDeSemaine
  , ruleFinNamedmonthinterval
  , ruleHhhmmTimeofday
  , ruleHhmmMilitaryTimeofday
  , ruleHier
  , ruleIlYADuration
  , ruleIntersect
  , ruleIntersectByDeOr
  , ruleIntersectByMaisparExempleplutt
  , ruleJourDeLan
  , ruleLeCycleAprssuivantTime
  , ruleLeCycleAvantprcdentTime
  , ruleLeCycleDeTime
  , ruleLeCycleDernier
  , ruleLeCycleProchainsuivantdaprs
  , ruleLeDayofmonthDatetime
  , ruleLeDayofmonthNonOrdinal
  , ruleLeLendemainDuTime
  , ruleLeOrdinalCycleDeTime
  , ruleLeTime
  , ruleLeVeilleDuTime
  , ruleMaintenant
  , ruleMatin
  , ruleMidi
  , ruleMilieuDeSemaine
  , ruleMinuit
  , ruleNCycleAprs
  , ruleNCycleAvant
  , ruleNCyclePassesprecedents
  , ruleNCycleSuivants
  , ruleNDerniersCycle
  , ruleNProchainsCycle
  , ruleNameddayEnHuit
  , ruleNameddayEnQuinze
  , ruleNamedmonthProchain
  , ruleNamedmonthnameddayDernierpass
  , ruleNamedmonthnameddaySuivantdaprs
  , ruleNoel
  , ruleOrdinalCycleDeTime
  , ruleOrdinalWeekendDeTime
  , rulePartofdayDuDimTime
  , rulePremireQuinzaineDeNamedmonthinterval
  , ruleSeason
  , ruleSeason2
  , ruleSeason3
  , ruleSeason4
  , ruleSoir
  , ruleDbutDeSoire
  , ruleFinDeSoire
  , ruleSoirDeNol
  , ruleTimeofdayHeures
  , ruleTimeofdayLatent
  , ruleTimeofdayTimeofdayInterval
  , ruleToussaint
  , ruleVersTimeofday
  , ruleWeekend
  , ruleYear
  , ruleYearLatent
  , ruleYearLatent2
  , ruleYyyymmdd
  , ruleHourofdayMoinsQuart
  , ruleHourofdayMoinsIntegerAsRelativeMinutes
  , ruleHourofdayIntegerMinutes
  , ruleHourofdayInteger
  , ruleHourofdayEtpassDeNumeral
  , ruleHourofdayEtpassDeNumeralMinutes
  , ruleHourofdayEtTroisQuart
  , ruleHourofdayEtQuart
  , ruleHourofdayEtDemi
  , ruleFinDuMois
  , ruleTimezone
  , ruleDbutDuMois
  , ruleFinDAnnee
  , ruleDbutDAnnee
  , rulePlusTard
  , rulePlusTardPartofday
  , ruleNthTimeOfTime
  , ruleTheNthTimeOfTime
  , ruleDDMonthYY
  ]
  ++ ruleMonths
  ++ ruleDaysOfWeek


-- 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 OverloadedStrings #-}

module Duckling.Time.GA.Corpus
  ( corpus
  ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Resolve
import Duckling.Time.Corpus
import Duckling.TimeGrain.Types hiding (add)
import Duckling.Testing.Types hiding (examples)

corpus :: Corpus
corpus = (testContext {locale = makeLocale GA Nothing}, testOptions, allExamples)

allExamples :: [Example]
allExamples = concat
  [ examples (datetime (2013, 2, 12, 4, 30, 0) Second)
             [ "anois"
             ]
  , examples (datetime (2013, 2, 12, 0, 0, 0) Day)
             [ "inniu"
             ]
  , examples (datetime (2013, 2, 11, 0, 0, 0) Day)
             [ "innÃ©"
             ]
  , examples (datetime (2013, 2, 10, 0, 0, 0) Day)
             [ "arÃº innÃ©"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "amÃ¡rach"
             ]
  , examples (datetime (2013, 2, 14, 0, 0, 0) Day)
             [ "arÃº amÃ¡rach"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "dÃ© luain"
             , "an luan"
             , "an luan seo"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "an luan seo chugainn"
             , "an luan seo atÃ¡ ag teacht"
             , "dÃ© luain seo chugainn"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "18/2/2013"
             ]
  ]