{-# LANGUAGE LambdaCase         #-}
{-# LANGUAGE GADTs              #-}
{-# LANGUAGE NamedFieldPuns     #-}
{-# LANGUAGE RankNTypes         #-}
{-# LANGUAGE RecordWildCards    #-}
{-# LANGUAGE StandaloneDeriving #-}

module GhcTags.CTag.Header
  ( Header (..)
  , HeaderType (..)
  , SomeHeaderType (..)
  -- * Utils
  , SingHeaderType (..)
  , headerTypeSing
  ) where

import           Control.DeepSeq (NFData (..))
import           Data.Text (Text)


-- | A type safe representation of a /ctag/ header.
--
data Header where
    Header :: forall ty. (NFData ty, Show ty) =>
              { ()
headerType     :: HeaderType ty
              , Header -> Maybe Text
headerLanguage :: Maybe Text
              , ()
headerArg      :: ty
              , Header -> Text
headerComment  :: Text
              }
            -> Header

instance Eq Header where
    Header  { headerType :: ()
headerType = HeaderType ty
headerType0
            , headerLanguage :: Header -> Maybe Text
headerLanguage = Maybe Text
headerLanguage0
            , headerArg :: ()
headerArg  = ty
headerArg0
            , headerComment :: Header -> Text
headerComment = Text
headerComment0
            }
      == :: Header -> Header -> Bool
==
      Header { headerType :: ()
headerType = HeaderType ty
headerType1
             , headerLanguage :: Header -> Maybe Text
headerLanguage = Maybe Text
headerLanguage1
             , headerArg :: ()
headerArg  = ty
headerArg1
             , headerComment :: Header -> Text
headerComment = Text
headerComment1
             } =
        case (HeaderType ty
headerType0, HeaderType ty
headerType1) of
          (HeaderType ty
FileEncoding, HeaderType ty
FileEncoding) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
FileFormat, HeaderType ty
FileFormat) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
FileSorted, HeaderType ty
FileSorted) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
OutputMode, HeaderType ty
OutputMode) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
KindDescription, HeaderType ty
KindDescription) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
KindSeparator, HeaderType ty
KindSeparator) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
ProgramAuthor, HeaderType ty
ProgramAuthor) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
ProgramName, HeaderType ty
ProgramName) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
ProgramUrl, HeaderType ty
ProgramUrl) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
ProgramVersion, HeaderType ty
ProgramVersion) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
ExtraDescription, HeaderType ty
ExtraDescription) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty
FieldDescription, HeaderType ty
FieldDescription) ->
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (PseudoTag Text
name0, PseudoTag Text
name1) ->
            Text
name0 forall a. Eq a => a -> a -> Bool
== Text
name1 Bool -> Bool -> Bool
&&
            Maybe Text
headerLanguage0 forall a. Eq a => a -> a -> Bool
== Maybe Text
headerLanguage1 Bool -> Bool -> Bool
&&
            ty
headerArg0 forall a. Eq a => a -> a -> Bool
== ty
headerArg1 Bool -> Bool -> Bool
&&
            Text
headerComment0 forall a. Eq a => a -> a -> Bool
== Text
headerComment1
          (HeaderType ty, HeaderType ty)
_ -> Bool
False

deriving instance Show Header

instance NFData Header where
  rnf :: Header -> ()
rnf Header {ty
Maybe Text
Text
HeaderType ty
headerComment :: Text
headerArg :: ty
headerLanguage :: Maybe Text
headerType :: HeaderType ty
headerComment :: Header -> Text
headerArg :: ()
headerLanguage :: Header -> Maybe Text
headerType :: ()
..} = forall a. NFData a => a -> ()
rnf HeaderType ty
headerType
              seq :: forall a b. a -> b -> b
`seq` forall a. NFData a => a -> ()
rnf Maybe Text
headerLanguage
              seq :: forall a b. a -> b -> b
`seq` forall a. NFData a => a -> ()
rnf ty
headerArg
              seq :: forall a b. a -> b -> b
`seq` forall a. NFData a => a -> ()
rnf Text
headerComment

-- | Enumeration of header type and values of their corresponding argument
--
data HeaderType ty where
    FileEncoding      :: HeaderType Text
    FileFormat        :: HeaderType Int
    FileSorted        :: HeaderType Int
    OutputMode        :: HeaderType Text
    KindDescription   :: HeaderType Text
    KindSeparator     :: HeaderType Text
    ProgramAuthor     :: HeaderType Text
    ProgramName       :: HeaderType Text
    ProgramUrl        :: HeaderType Text
    ProgramVersion    :: HeaderType Text

    ExtraDescription  :: HeaderType Text
    FieldDescription  :: HeaderType Text
    PseudoTag         :: Text -> HeaderType Text

deriving instance Eq (HeaderType ty)
deriving instance Ord (HeaderType ty)
deriving instance Show (HeaderType ty)
instance NFData (HeaderType ty) where
    rnf :: HeaderType ty -> ()
rnf HeaderType ty
a = HeaderType ty
a seq :: forall a b. a -> b -> b
`seq` ()

-- | Existential wrapper.
--
data SomeHeaderType where
    SomeHeaderType :: forall ty. HeaderType ty -> SomeHeaderType


-- | Singletons which makes it easier to work with 'HeaderType'
--
data SingHeaderType ty where
    SingHeaderTypeText :: SingHeaderType Text
    SingHeaderTypeInt  :: SingHeaderType Int

headerTypeSing :: HeaderType ty -> SingHeaderType ty
headerTypeSing :: forall ty. HeaderType ty -> SingHeaderType ty
headerTypeSing = \case
    HeaderType ty
FileEncoding     -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
FileFormat       -> SingHeaderType Int
SingHeaderTypeInt
    HeaderType ty
FileSorted       -> SingHeaderType Int
SingHeaderTypeInt
    HeaderType ty
OutputMode       -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
KindDescription  -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
KindSeparator    -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
ProgramAuthor    -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
ProgramName      -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
ProgramUrl       -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
ProgramVersion   -> SingHeaderType Text
SingHeaderTypeText

    HeaderType ty
ExtraDescription -> SingHeaderType Text
SingHeaderTypeText
    HeaderType ty
FieldDescription -> SingHeaderType Text
SingHeaderTypeText
    PseudoTag {}     -> SingHeaderType Text
SingHeaderTypeText