{-# LANGUAGE RecordWildCards     #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE CPP                 #-}

module Distribution.Fedora.Products
  ( Release(releaseProductVersionId,releaseVersion,releaseProduct)
  , parseReleases
  )
where

import qualified Data.ByteString.Lazy.Char8 as BL
import           Control.Monad      (mzero)
import           Data.Aeson(eitherDecode, Value(..), FromJSON(..), ToJSON(..),
                            pairs,
                            (.:), (.=), object)
#if !MIN_VERSION_base(4,13,0)
import           Data.Monoid((<>))
#endif
import           Data.Text (Text)
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>), (<*>))
#endif

data Release = Release {
    Release -> Text
releaseProductVersionId :: Text,
    Release -> [Text]
releaseReleases :: [Text],
    Release -> [[Maybe Value]]
releaseAllowedPushTargets :: [[Maybe Value]],
    Release -> Bool
releaseActive :: Bool,
    Release -> Text
releaseName :: Text,
    Release -> Text
releaseVersion :: Text,
    Release -> Text
releaseShort :: Text,
    Release -> Text
releaseProduct :: Text
  } deriving (Int -> Release -> ShowS
[Release] -> ShowS
Release -> String
(Int -> Release -> ShowS)
-> (Release -> String) -> ([Release] -> ShowS) -> Show Release
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Release] -> ShowS
$cshowList :: [Release] -> ShowS
show :: Release -> String
$cshow :: Release -> String
showsPrec :: Int -> Release -> ShowS
$cshowsPrec :: Int -> Release -> ShowS
Show,Release -> Release -> Bool
(Release -> Release -> Bool)
-> (Release -> Release -> Bool) -> Eq Release
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Release -> Release -> Bool
$c/= :: Release -> Release -> Bool
== :: Release -> Release -> Bool
$c== :: Release -> Release -> Bool
Eq)

instance Ord Release where
  compare :: Release -> Release -> Ordering
compare Release
r1 Release
r2 =
    Text -> Text -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Release -> Text
releaseProductVersionId Release
r1) (Release -> Text
releaseProductVersionId Release
r2)

instance FromJSON Release where
  parseJSON :: Value -> Parser Release
parseJSON (Object Object
v) = Text
-> [Text]
-> [[Maybe Value]]
-> Bool
-> Text
-> Text
-> Text
-> Text
-> Release
Release (Text
 -> [Text]
 -> [[Maybe Value]]
 -> Bool
 -> Text
 -> Text
 -> Text
 -> Text
 -> Release)
-> Parser Text
-> Parser
     ([Text]
      -> [[Maybe Value]]
      -> Bool
      -> Text
      -> Text
      -> Text
      -> Text
      -> Release)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"product_version_id" Parser
  ([Text]
   -> [[Maybe Value]]
   -> Bool
   -> Text
   -> Text
   -> Text
   -> Text
   -> Release)
-> Parser [Text]
-> Parser
     ([[Maybe Value]]
      -> Bool -> Text -> Text -> Text -> Text -> Release)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser [Text]
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"releases" Parser
  ([[Maybe Value]]
   -> Bool -> Text -> Text -> Text -> Text -> Release)
-> Parser [[Maybe Value]]
-> Parser (Bool -> Text -> Text -> Text -> Text -> Release)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser [[Maybe Value]]
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"allowed_push_targets" Parser (Bool -> Text -> Text -> Text -> Text -> Release)
-> Parser Bool -> Parser (Text -> Text -> Text -> Text -> Release)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Bool
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"active" Parser (Text -> Text -> Text -> Text -> Release)
-> Parser Text -> Parser (Text -> Text -> Text -> Release)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"name" Parser (Text -> Text -> Text -> Release)
-> Parser Text -> Parser (Text -> Text -> Release)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"version" Parser (Text -> Text -> Release)
-> Parser Text -> Parser (Text -> Release)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"short" Parser (Text -> Release) -> Parser Text -> Parser Release
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"product"
  parseJSON Value
_          = Parser Release
forall (m :: * -> *) a. MonadPlus m => m a
mzero

instance ToJSON Release where
  toJSON :: Release -> Value
toJSON     Release {Bool
[[Maybe Value]]
[Text]
Text
releaseProduct :: Text
releaseShort :: Text
releaseVersion :: Text
releaseName :: Text
releaseActive :: Bool
releaseAllowedPushTargets :: [[Maybe Value]]
releaseReleases :: [Text]
releaseProductVersionId :: Text
releaseShort :: Release -> Text
releaseName :: Release -> Text
releaseActive :: Release -> Bool
releaseAllowedPushTargets :: Release -> [[Maybe Value]]
releaseReleases :: Release -> [Text]
releaseProduct :: Release -> Text
releaseVersion :: Release -> Text
releaseProductVersionId :: Release -> Text
..} = [Pair] -> Value
object [Text
"product_version_id" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseProductVersionId, Text
"releases" Text -> [Text] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Text]
releaseReleases, Text
"allowed_push_targets" Text -> [[Maybe Value]] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Maybe Value]]
releaseAllowedPushTargets, Text
"active" Text -> Bool -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
releaseActive, Text
"name" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseName, Text
"version" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseVersion, Text
"short" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseShort, Text
"product" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseProduct]
  toEncoding :: Release -> Encoding
toEncoding Release {Bool
[[Maybe Value]]
[Text]
Text
releaseProduct :: Text
releaseShort :: Text
releaseVersion :: Text
releaseName :: Text
releaseActive :: Bool
releaseAllowedPushTargets :: [[Maybe Value]]
releaseReleases :: [Text]
releaseProductVersionId :: Text
releaseShort :: Release -> Text
releaseName :: Release -> Text
releaseActive :: Release -> Bool
releaseAllowedPushTargets :: Release -> [[Maybe Value]]
releaseReleases :: Release -> [Text]
releaseProduct :: Release -> Text
releaseVersion :: Release -> Text
releaseProductVersionId :: Release -> Text
..} = Series -> Encoding
pairs  (Text
"product_version_id" Text -> Text -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseProductVersionIdSeries -> Series -> Series
forall a. Semigroup a => a -> a -> a
<>Text
"releases" Text -> [Text] -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Text]
releaseReleasesSeries -> Series -> Series
forall a. Semigroup a => a -> a -> a
<>Text
"allowed_push_targets" Text -> [[Maybe Value]] -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Maybe Value]]
releaseAllowedPushTargetsSeries -> Series -> Series
forall a. Semigroup a => a -> a -> a
<>Text
"active" Text -> Bool -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
releaseActiveSeries -> Series -> Series
forall a. Semigroup a => a -> a -> a
<>Text
"name" Text -> Text -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseNameSeries -> Series -> Series
forall a. Semigroup a => a -> a -> a
<>Text
"version" Text -> Text -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseVersionSeries -> Series -> Series
forall a. Semigroup a => a -> a -> a
<>Text
"short" Text -> Text -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseShortSeries -> Series -> Series
forall a. Semigroup a => a -> a -> a
<>Text
"product" Text -> Text -> Series
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
releaseProduct)

parseReleases :: FilePath -> IO [Release]
parseReleases :: String -> IO [Release]
parseReleases String
filename = do
    ByteString
input <- String -> IO ByteString
BL.readFile String
filename
    case ByteString -> Either String [Release]
forall a. FromJSON a => ByteString -> Either String a
eitherDecode ByteString
input of
      Left  String
err -> String -> IO [Release]
forall a. HasCallStack => String -> a
error (String -> IO [Release]) -> String -> IO [Release]
forall a b. (a -> b) -> a -> b
$ String
"Invalid JSON file: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
filename String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
err
      Right [Release]
r   -> [Release] -> IO [Release]
forall (m :: * -> *) a. Monad m => a -> m a
return [Release]
r