{-# LANGUAGE OverloadedStrings #-}

{-| @feed-gipeda.yaml@ related stuff like decoding and syntax checking.
-}


module FeedGipeda.Config
  ( Config
  , empty
  , repos
  , decodeFile
  , checkFile
  ) where


import           Control.Arrow          (left)
import           Control.Monad          (forever)
import           Control.Monad.IO.Class (MonadIO, liftIO)
import           Data.Set               (Set)
import qualified Data.Set               as Set
import           Data.Yaml              (FromJSON (..), Value (Object), (.:))
import qualified Data.Yaml              as Yaml
import           FeedGipeda.Repo        (Repo (..))
import qualified FeedGipeda.Repo        as Repo
import           Network.URI            (parseURI)
import           System.FilePath        (dropFileName, equalFilePath)


{-| Represents a decoded config file. Has the appropriate @FromJSON@ config to
    be deserializable from YAML.
-}
data Config
  = Config
  { repos :: Set Repo
  } deriving (Eq, Show)


-- | A config with no repositories to watch.
empty :: Config
empty =
  Config Set.empty


instance FromJSON Repo where
  parseJSON v = do
    s <- parseJSON v
    uri <- maybe (fail "Could not parse URI") return (parseURI s)
    return (Repo uri)


instance FromJSON Config where
  parseJSON (Object v) =
    fmap (Config . Set.fromList) (v .: "repositories")
  parseJSON _ =
    fail "Object"


{-| @decodeFile file@ @Either@ decodes a @Config@ from a YAML @file@
    (such as @feed-gipeda.yaml@) or returns a parse error message.
-}
decodeFile :: FilePath -> IO (Either String Config)
decodeFile file = fmap (left errorToString) (Yaml.decodeFileEither file)
  where
    errorToString :: Yaml.ParseException -> String
    errorToString e =
      unlines
        [ "Could not decode the config file:"
        , Yaml.prettyPrintParseException e
        ]


{-| Checks for syntax errors while reading a @Config@ from the supplied YAML
    file.
-}
checkFile :: FilePath -> IO (Maybe String)
checkFile file =
  fmap (either Just (const Nothing)) (decodeFile file)