{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE RecordWildCards       #-}

module Network.IPv6DB.Types where

import           Data.Aeson    as A
import qualified Data.Text     as T
import qualified Data.Vector   as V
import           Text.IPv6Addr

newtype Addresses = Addresses [IPv6Addr]

instance FromJSON Addresses where
  parseJSON :: Value -> Parser Addresses
parseJSON (Array Array
v) = do
    let rslts :: [Result IPv6Addr]
rslts = Value -> Result IPv6Addr
forall a. FromJSON a => Value -> Result a
fromJSON (Value -> Result IPv6Addr) -> [Value] -> [Result IPv6Addr]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Array -> [Value]
forall a. Vector a -> [a]
V.toList Array
v
    if (Result IPv6Addr -> Bool) -> [Result IPv6Addr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Result IPv6Addr -> Bool
forall a. Result a -> Bool
isSuccess [Result IPv6Addr]
rslts
      then Addresses -> Parser Addresses
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([IPv6Addr] -> Addresses
Addresses ([IPv6Addr] -> Addresses) -> [IPv6Addr] -> Addresses
forall a b. (a -> b) -> a -> b
$ Result IPv6Addr -> IPv6Addr
forall a. Result a -> a
fromSuccess (Result IPv6Addr -> IPv6Addr) -> [Result IPv6Addr] -> [IPv6Addr]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Result IPv6Addr]
rslts)
      else String -> Parser Addresses
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Bad JSON Array Of IPv6 Addresses"
  parseJSON Value
_         = String -> Parser Addresses
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"JSON Array Expected"

data Entry =
  Entry
    { Entry -> Text
list    :: !T.Text
    , Entry -> IPv6Addr
address :: IPv6Addr
    } deriving (Entry -> Entry -> Bool
(Entry -> Entry -> Bool) -> (Entry -> Entry -> Bool) -> Eq Entry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Entry -> Entry -> Bool
== :: Entry -> Entry -> Bool
$c/= :: Entry -> Entry -> Bool
/= :: Entry -> Entry -> Bool
Eq, Int -> Entry -> ShowS
[Entry] -> ShowS
Entry -> String
(Int -> Entry -> ShowS)
-> (Entry -> String) -> ([Entry] -> ShowS) -> Show Entry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Entry -> ShowS
showsPrec :: Int -> Entry -> ShowS
$cshow :: Entry -> String
show :: Entry -> String
$cshowList :: [Entry] -> ShowS
showList :: [Entry] -> ShowS
Show)

instance FromJSON Entry where
  parseJSON :: Value -> Parser Entry
parseJSON (Object Object
o) = do
    Text
list    <- Object
o Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"list"
    IPv6Addr
address <- Object
o Object -> Key -> Parser IPv6Addr
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"address"
    Entry -> Parser Entry
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Entry{IPv6Addr
Text
$sel:list:Entry :: Text
$sel:address:Entry :: IPv6Addr
list :: Text
address :: IPv6Addr
..}
  parseJSON Value
_          = String -> Parser Entry
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"JSON Object Expected"

newtype Entries = Entries [Entry]

instance FromJSON Entries where
  parseJSON :: Value -> Parser Entries
parseJSON (Array Array
v) = do
    let ents :: [Result Entry]
ents = Value -> Result Entry
forall a. FromJSON a => Value -> Result a
fromJSON (Value -> Result Entry) -> [Value] -> [Result Entry]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Array -> [Value]
forall a. Vector a -> [a]
V.toList Array
v
    if (Result Entry -> Bool) -> [Result Entry] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Result Entry -> Bool
forall a. Result a -> Bool
isSuccess [Result Entry]
ents
      then Entries -> Parser Entries
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Entry] -> Entries
Entries ([Entry] -> Entries) -> [Entry] -> Entries
forall a b. (a -> b) -> a -> b
$ Result Entry -> Entry
forall a. Result a -> a
fromSuccess (Result Entry -> Entry) -> [Result Entry] -> [Entry]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Result Entry]
ents)
      else String -> Parser Entries
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Malformed JSON Array"
  parseJSON Value
_         = String -> Parser Entries
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"JSON Array Expected"

newtype Source = Source Value deriving (Source -> Source -> Bool
(Source -> Source -> Bool)
-> (Source -> Source -> Bool) -> Eq Source
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Source -> Source -> Bool
== :: Source -> Source -> Bool
$c/= :: Source -> Source -> Bool
/= :: Source -> Source -> Bool
Eq, Int -> Source -> ShowS
[Source] -> ShowS
Source -> String
(Int -> Source -> ShowS)
-> (Source -> String) -> ([Source] -> ShowS) -> Show Source
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Source -> ShowS
showsPrec :: Int -> Source -> ShowS
$cshow :: Source -> String
show :: Source -> String
$cshowList :: [Source] -> ShowS
showList :: [Source] -> ShowS
Show)

instance ToJSON Source where
  toJSON :: Source -> Value
toJSON (Source Value
v) = Value
v

instance FromJSON Source where
  parseJSON :: Value -> Parser Source
parseJSON Value
v = Source -> Parser Source
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Value -> Source
Source Value
v)

data Resource
  = Resource
      { Resource -> Text
list    :: !T.Text
      , Resource -> IPv6Addr
address :: !IPv6Addr
      , Resource -> Maybe Integer
ttl     :: !(Maybe Integer)
      , Resource -> Source
source  :: !Source
      }
  | ResourceError
      { list    :: !T.Text
      , address :: !IPv6Addr
      , Resource -> Text
error   :: !T.Text
      }
  deriving (Resource -> Resource -> Bool
(Resource -> Resource -> Bool)
-> (Resource -> Resource -> Bool) -> Eq Resource
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Resource -> Resource -> Bool
== :: Resource -> Resource -> Bool
$c/= :: Resource -> Resource -> Bool
/= :: Resource -> Resource -> Bool
Eq, Int -> Resource -> ShowS
[Resource] -> ShowS
Resource -> String
(Int -> Resource -> ShowS)
-> (Resource -> String) -> ([Resource] -> ShowS) -> Show Resource
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Resource -> ShowS
showsPrec :: Int -> Resource -> ShowS
$cshow :: Resource -> String
show :: Resource -> String
$cshowList :: [Resource] -> ShowS
showList :: [Resource] -> ShowS
Show)

instance ToJSON Resource where
  toJSON :: Resource -> Value
toJSON Resource{Maybe Integer
IPv6Addr
Text
Source
$sel:list:Resource :: Resource -> Text
$sel:address:Resource :: Resource -> IPv6Addr
$sel:ttl:Resource :: Resource -> Maybe Integer
$sel:source:Resource :: Resource -> Source
list :: Text
address :: IPv6Addr
ttl :: Maybe Integer
source :: Source
..} =
    [Pair] -> Value
object
      [ Key
"list"    Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
list
      , Key
"address" Key -> IPv6Addr -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= IPv6Addr
address
      , Key
"ttl"     Key -> Maybe Integer -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Integer
ttl
      , Key
"source"  Key -> Source -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Source
source
      ]
  toJSON ResourceError{$sel:error:Resource :: Resource -> Text
error=Text
err, IPv6Addr
Text
$sel:list:Resource :: Resource -> Text
$sel:address:Resource :: Resource -> IPv6Addr
list :: Text
address :: IPv6Addr
..} =
    [Pair] -> Value
object
      [ Key
"list"    Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
list
      , Key
"address" Key -> IPv6Addr -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= IPv6Addr
address
      , Key
"error"   Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
err
      ]

instance FromJSON Resource where
  parseJSON :: Value -> Parser Resource
parseJSON =
    String -> (Object -> Parser Resource) -> Value -> Parser Resource
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"resource" ((Object -> Parser Resource) -> Value -> Parser Resource)
-> (Object -> Parser Resource) -> Value -> Parser Resource
forall a b. (a -> b) -> a -> b
$
      \Object
o -> do
        Text
list    <- Object
o Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"list"
        IPv6Addr
address <- do
          Text
ma <- Object
o Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"address"
          case Text -> Maybe IPv6Addr
maybeIPv6Addr Text
ma of
            Just IPv6Addr
a  -> IPv6Addr -> Parser IPv6Addr
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure IPv6Addr
a
            Maybe IPv6Addr
Nothing -> String -> Parser IPv6Addr
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Not an IPv6 Address"
        Maybe Integer
ttl     <- Object
o Object -> Key -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"ttl"
        Source
source  <- Object
o Object -> Key -> Parser Source
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"source"
        Resource -> Parser Resource
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return Resource{Maybe Integer
IPv6Addr
Text
Source
$sel:list:Resource :: Text
$sel:address:Resource :: IPv6Addr
$sel:ttl:Resource :: Maybe Integer
$sel:source:Resource :: Source
list :: Text
address :: IPv6Addr
ttl :: Maybe Integer
source :: Source
..}

newtype Resources = Resources [Resource] deriving (Resources -> Resources -> Bool
(Resources -> Resources -> Bool)
-> (Resources -> Resources -> Bool) -> Eq Resources
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Resources -> Resources -> Bool
== :: Resources -> Resources -> Bool
$c/= :: Resources -> Resources -> Bool
/= :: Resources -> Resources -> Bool
Eq, Int -> Resources -> ShowS
[Resources] -> ShowS
Resources -> String
(Int -> Resources -> ShowS)
-> (Resources -> String)
-> ([Resources] -> ShowS)
-> Show Resources
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Resources -> ShowS
showsPrec :: Int -> Resources -> ShowS
$cshow :: Resources -> String
show :: Resources -> String
$cshowList :: [Resources] -> ShowS
showList :: [Resources] -> ShowS
Show)

instance ToJSON Resources where
  toJSON :: Resources -> Value
toJSON (Resources [Resource]
rs) =
    [Pair] -> Value
object [ (Key
"resources", Array -> Value
Array ([Value] -> Array
forall a. [a] -> Vector a
V.fromList ([Value] -> Array) -> [Value] -> Array
forall a b. (a -> b) -> a -> b
$ Resource -> Value
forall a. ToJSON a => a -> Value
toJSON (Resource -> Value) -> [Resource] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Resource]
rs)) ]

instance FromJSON Resources where
  parseJSON :: Value -> Parser Resources
parseJSON (Array Array
v) = do
    let rsrcs :: [Result Resource]
rsrcs = Value -> Result Resource
forall a. FromJSON a => Value -> Result a
fromJSON (Value -> Result Resource) -> [Value] -> [Result Resource]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Array -> [Value]
forall a. Vector a -> [a]
V.toList Array
v
    if (Result Resource -> Bool) -> [Result Resource] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Result Resource -> Bool
forall a. Result a -> Bool
isSuccess [Result Resource]
rsrcs
      then Resources -> Parser Resources
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Resource] -> Resources
Resources ([Resource] -> Resources) -> [Resource] -> Resources
forall a b. (a -> b) -> a -> b
$ Result Resource -> Resource
forall a. Result a -> a
fromSuccess (Result Resource -> Resource) -> [Result Resource] -> [Resource]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Result Resource]
rsrcs)
      else String -> Parser Resources
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Malformed JSON Array Of Resources"
  parseJSON Value
_         = String -> Parser Resources
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"JSON Array Expected"

isSuccess :: Result a -> Bool
isSuccess :: forall a. Result a -> Bool
isSuccess (A.Success a
_) = Bool
True
isSuccess (A.Error String
_)   = Bool
False

fromSuccess :: Result a -> a
fromSuccess :: forall a. Result a -> a
fromSuccess (A.Success a
e) = a
e
fromSuccess (A.Error String
_)   = String -> a
forall a. HasCallStack => String -> a
Prelude.error String
"Success value only"