{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}

module Data.Medea.Parser.Spec.Schema
  ( Specification (..),
    parseSpecification,
  )
where

import Control.Applicative.Permutations
  ( runPermutation,
    toPermutationWithDefault,
  )
import Data.Medea.Parser.Primitive
  ( Identifier,
    ReservedIdentifier (..),
    parseIdentifier,
    parseKeyVal,
    parseLine,
  )
import qualified Data.Medea.Parser.Spec.Array as Array
import qualified Data.Medea.Parser.Spec.Object as Object
import qualified Data.Medea.Parser.Spec.String as String
import qualified Data.Medea.Parser.Spec.Type as Type
import Data.Medea.Parser.Types (MedeaParser)
import Text.Megaparsec (MonadParsec (..))

data Specification = Specification
  { Specification -> Identifier
name :: !Identifier,
    Specification -> Specification
types :: !Type.Specification,
    Specification -> Specification
stringVals :: !String.Specification,
    Specification -> Specification
array :: !Array.Specification,
    Specification -> Maybe Specification
object :: !(Maybe Object.Specification)
  }
  deriving stock (Specification -> Specification -> Bool
(Specification -> Specification -> Bool)
-> (Specification -> Specification -> Bool) -> Eq Specification
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Specification -> Specification -> Bool
$c/= :: Specification -> Specification -> Bool
== :: Specification -> Specification -> Bool
$c== :: Specification -> Specification -> Bool
Eq)

parseSpecification :: MedeaParser Specification
parseSpecification :: MedeaParser Specification
parseSpecification = do
  Identifier
schemaName <- Int -> MedeaParser Identifier -> MedeaParser Identifier
forall a. Int -> MedeaParser a -> MedeaParser a
parseLine Int
0 (MedeaParser Identifier -> MedeaParser Identifier)
-> MedeaParser Identifier -> MedeaParser Identifier
forall a b. (a -> b) -> a -> b
$ ReservedIdentifier
-> MedeaParser Identifier -> MedeaParser Identifier
forall a. ReservedIdentifier -> MedeaParser a -> MedeaParser a
parseKeyVal ReservedIdentifier
RSchema MedeaParser Identifier
parseIdentifier
  Permutation (ParsecT ParseError Text Identity) Specification
-> MedeaParser Specification
forall (m :: * -> *) a.
(Alternative m, Monad m) =>
Permutation m a -> m a
runPermutation (Permutation (ParsecT ParseError Text Identity) Specification
 -> MedeaParser Specification)
-> Permutation (ParsecT ParseError Text Identity) Specification
-> MedeaParser Specification
forall a b. (a -> b) -> a -> b
$
    Identifier
-> Specification
-> Specification
-> Specification
-> Maybe Specification
-> Specification
Specification Identifier
schemaName
      (Specification
 -> Specification
 -> Specification
 -> Maybe Specification
 -> Specification)
-> Permutation (ParsecT ParseError Text Identity) Specification
-> Permutation
     (ParsecT ParseError Text Identity)
     (Specification
      -> Specification -> Maybe Specification -> Specification)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Specification
-> ParsecT ParseError Text Identity Specification
-> Permutation (ParsecT ParseError Text Identity) Specification
forall (m :: * -> *) a.
Alternative m =>
a -> m a -> Permutation m a
toPermutationWithDefault Specification
Type.defaultSpec (ParsecT ParseError Text Identity Specification
-> ParsecT ParseError Text Identity Specification
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try ParsecT ParseError Text Identity Specification
Type.parseSpecification)
      Permutation
  (ParsecT ParseError Text Identity)
  (Specification
   -> Specification -> Maybe Specification -> Specification)
-> Permutation (ParsecT ParseError Text Identity) Specification
-> Permutation
     (ParsecT ParseError Text Identity)
     (Specification -> Maybe Specification -> Specification)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Specification
-> ParsecT ParseError Text Identity Specification
-> Permutation (ParsecT ParseError Text Identity) Specification
forall (m :: * -> *) a.
Alternative m =>
a -> m a -> Permutation m a
toPermutationWithDefault Specification
String.defaultSpec (ParsecT ParseError Text Identity Specification
-> ParsecT ParseError Text Identity Specification
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try ParsecT ParseError Text Identity Specification
String.parseSpecification)
      Permutation
  (ParsecT ParseError Text Identity)
  (Specification -> Maybe Specification -> Specification)
-> Permutation (ParsecT ParseError Text Identity) Specification
-> Permutation
     (ParsecT ParseError Text Identity)
     (Maybe Specification -> Specification)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Specification
-> ParsecT ParseError Text Identity Specification
-> Permutation (ParsecT ParseError Text Identity) Specification
forall (m :: * -> *) a.
Alternative m =>
a -> m a -> Permutation m a
toPermutationWithDefault Specification
Array.defaultSpec (ParsecT ParseError Text Identity Specification
-> ParsecT ParseError Text Identity Specification
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try ParsecT ParseError Text Identity Specification
Array.parseSpecification)
      Permutation
  (ParsecT ParseError Text Identity)
  (Maybe Specification -> Specification)
-> Permutation
     (ParsecT ParseError Text Identity) (Maybe Specification)
-> Permutation (ParsecT ParseError Text Identity) Specification
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Specification
-> ParsecT ParseError Text Identity (Maybe Specification)
-> Permutation
     (ParsecT ParseError Text Identity) (Maybe Specification)
forall (m :: * -> *) a.
Alternative m =>
a -> m a -> Permutation m a
toPermutationWithDefault Maybe Specification
forall a. Maybe a
Nothing (Specification -> Maybe Specification
forall a. a -> Maybe a
Just (Specification -> Maybe Specification)
-> ParsecT ParseError Text Identity Specification
-> ParsecT ParseError Text Identity (Maybe Specification)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT ParseError Text Identity Specification
-> ParsecT ParseError Text Identity Specification
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try ParsecT ParseError Text Identity Specification
Object.parseSpecification)