content: module Puppet.Language.NativeTypes.Cron (nativeCron) where
  
  import qualified Data.Text as Text
  import Puppet.Language.NativeTypes.Helpers
  
  nativeCron :: (NativeTypeName, NativeTypeMethods)
  nativeCron = ("cron", nativetypemethods parameterfunctions return)
  
  -- Autorequires: If Puppet is managing the user or group that owns a file, the file resource will autorequire them. If Puppet is managing any parent directories of a file, the file resource will autorequire them.
  parameterfunctions :: [(Text, [Text -> NativeTypeValidate])]
  parameterfunctions =
    [ ("ensure", [defaultvalue "present", string, values ["present", "absent"]]),
      ("command", [string, mandatoryIfNotAbsent]),
      ("environment", []),
      ("hour", [vrange 0 23 []]),
      ("minute", [vrange 0 59 []]),
      ("month", [vrange 1 12 ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]]),
      ("monthday", [vrange 1 31 []]),
      ("name", [nameval]),
      ("provider", [defaultvalue "crontab", string, values ["crontab"]]),
      ("special", [string]),
      ("target", [string]),
      ("user", [defaultvalue "root", string]),
      ("weekday", [vrange 0 7 ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]])
    ]
  
  vrange :: Integer -> Integer -> [Text] -> Text -> NativeTypeValidate
  vrange mi ma valuelist param res = case res ^. rattributes . at param of
    Just (PArray xs) -> foldM (vrange' mi ma valuelist param) res xs
    Just x -> vrange' mi ma valuelist param res x
    Nothing -> defaultvalue "*" param res
  
  vrange' :: Integer -> Integer -> [Text] -> Text -> Resource -> PValue -> Either PrettyError Resource
  vrange' mi ma valuelist param res y = case y of
    PString "*" -> Right res
    PString "absent" -> Right res
    PNumber n -> checkint' n mi ma param res
    PString x ->
      if x `elem` valuelist
        then Right res
        else parseval x mi ma param res
    x -> perror $ "Parameter" <+> paramname param <+> "value should be a valid cron declaration and not" <+> pretty x
  
  parseval :: Text -> Integer -> Integer -> Text -> NativeTypeValidate
  parseval resval mi ma pname res
    | "*/" `Text.isPrefixOf` resval = checkint (Text.drop 2 resval) 1 ma pname res
    | otherwise = checkint resval mi ma pname res
  
  checkint :: Text -> Integer -> Integer -> Text -> NativeTypeValidate
  checkint st mi ma pname res =
    case text2Scientific st of
      Just n -> checkint' n mi ma pname res
      Nothing -> perror $ "Invalid value type for parameter" <+> paramname pname <+> ": " <+> red (ppline st)
  
  checkint' :: Scientific -> Integer -> Integer -> Text -> NativeTypeValidate
  checkint' i mi ma param res =
    if (i >= fromIntegral mi) && (i <= fromIntegral ma)
      then Right res
      else perror $ "Parameter" <+> paramname param <+> "value is out of bound, should satisfy" <+> pretty mi <+> "<=" <+> pplines (show i) <+> "<=" <+> pretty ma
  