module Data.BAByNF.ABNF.Rules.Element
    ( ref
    , rule
    , fromTree
    ) where

import Data.Functor ((<&>))
import Data.List qualified as List

import Data.BAByNF.ABNF.Model qualified as Model
import {-# SOURCE #-} Data.BAByNF.ABNF.Rules.Option qualified as Option
import Data.BAByNF.ABNF.Rules.CharVal qualified as CharVal
import Data.BAByNF.ABNF.Rules.NumVal qualified as NumVal
import Data.BAByNF.ABNF.Rules.Rulename qualified as Rulename
import Data.BAByNF.ABNF.Rules.Group qualified as Group
import Data.BAByNF.ABNF.Rules.ProseVal qualified as ProseVal
import Data.BAByNF.Util.Ascii qualified as Ascii
import Data.BAByNF.Core.Tree (Tree)
import Data.BAByNF.Core.Tree qualified as Tree
import Data.BAByNF.Core.Ref qualified as Ref


ref :: Model.Rulename
ref :: Rulename
ref = ByteString -> Rulename
Model.Rulename (String -> ByteString
Ascii.stringAsBytesUnsafe  String
"element")

rule :: Model.Rule
rule :: Rule
rule = Rulename -> DefinedAs -> Elements -> Rule
Model.Rule Rulename
ref DefinedAs
Model.BasicDefinition 
    (Elements -> Rule)
-> ([Concatenation] -> Elements) -> [Concatenation] -> Rule
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Alternation -> Elements
Model.Elements 
    (Alternation -> Elements)
-> ([Concatenation] -> Alternation) -> [Concatenation] -> Elements
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Concatenation] -> Alternation
Model.Alternation
    ([Concatenation] -> Rule) -> [Concatenation] -> Rule
forall a b. (a -> b) -> a -> b
$ 
        [ [Repetition] -> Concatenation
Model.Concatenation 
            ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
            (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
Rulename.ref
        , [Repetition] -> Concatenation
Model.Concatenation 
            ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
            (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
Group.ref
        , [Repetition] -> Concatenation
Model.Concatenation 
            ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
            (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
Option.ref
        , [Repetition] -> Concatenation
Model.Concatenation 
            ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
            (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
CharVal.ref
        , [Repetition] -> Concatenation
Model.Concatenation 
            ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
            (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
NumVal.ref
        , [Repetition] -> Concatenation
Model.Concatenation 
            ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
            (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
ProseVal.ref
        ]

fromTree :: Tree Model.Rulename -> Either String Model.Element
fromTree :: Tree Rulename -> Either String Element
fromTree Tree Rulename
tree = 
    case Tree Rulename -> [Node Rulename]
forall a. Ref a => Tree a -> [Node a]
Tree.nodes Tree Rulename
tree of
        [Tree.RefNode Rulename
r Tree Rulename
subtree] -> 
            if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
Rulename.ref then Element -> Either String Element
forall a b. b -> Either a b
Right (Element -> Either String Element)
-> (Tree Rulename -> Element)
-> Tree Rulename
-> Either String Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rulename -> Element
Model.RulenameElement (Rulename -> Element)
-> (Tree Rulename -> Rulename) -> Tree Rulename -> Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree Rulename -> Rulename
Rulename.fromTree (Tree Rulename -> Either String Element)
-> Tree Rulename -> Either String Element
forall a b. (a -> b) -> a -> b
$ Tree Rulename
subtree  
            else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
Group.ref then Tree Rulename -> Either String Group
Group.fromTree Tree Rulename
subtree Either String Group -> (Group -> Element) -> Either String Element
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> Group -> Element
Model.GroupElement
            else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
Option.ref then Tree Rulename -> Either String Option
Option.fromTree Tree Rulename
subtree Either String Option
-> (Option -> Element) -> Either String Element
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> Option -> Element
Model.OptionElement
            else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
CharVal.ref then Tree Rulename -> Either String CharVal
CharVal.fromTree Tree Rulename
subtree Either String CharVal
-> (CharVal -> Element) -> Either String Element
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> CharVal -> Element
Model.CharValElement
            else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
NumVal.ref then Tree Rulename -> Either String NumVal
NumVal.fromTree Tree Rulename
subtree Either String NumVal
-> (NumVal -> Element) -> Either String Element
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> NumVal -> Element
Model.NumValElement
            else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
ProseVal.ref then Tree Rulename -> Either String ProseVal
ProseVal.fromTree Tree Rulename
subtree Either String ProseVal
-> (ProseVal -> Element) -> Either String Element
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> ProseVal -> Element
Model.ProseValElement
            else String -> Either String Element
forall a b. a -> Either a b
Left String
"element must be rulename | group | option | char-val | num-val | prose-val"
        [Node Rulename]
_ -> String -> Either String Element
forall a b. a -> Either a b
Left String
"structural mismatch for <element>"