    {-# LANGUAGE CPP #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE TemplateHaskell #-}
    module System.Taffybar.DBus.Client.Util where

    import           Control.Applicative
    import           DBus.Generation
    import qualified DBus.Internal.Types as T
    import qualified DBus.Introspection as I
    import qualified Data.Char as Char
    import           Data.Coerce
    import           Data.Maybe
    import           Language.Haskell.TH
    import           StatusNotifier.Util (getIntrospectionObjectFromFile)

    #if __GLASGOW_HASKELL__ >= 802
    deriveShowAndEQ :: [DerivClause]
    deriveShowAndEQ :: [DerivClause]
    deriveShowAndEQ =
      [Maybe DerivStrategy -> Cxt -> DerivClause
    DerivClause Maybe DerivStrategy
    forall a. Maybe a
    Nothing [Name -> Type
    ConT ''Eq, Name -> Type
    ConT ''Show]]
    #endif

    buildDataFromNameTypePairs :: Name -> [(Name, Type)] -> Dec
    buildDataFromNameTypePairs :: Name -> [(Name, Type)] -> Dec
    buildDataFromNameTypePairs Name
    name [(Name, Type)]
    pairs =
      Cxt
    -> Name
    -> [TyVarBndr ()]
    -> Maybe Type
    -> [Con]
    -> [DerivClause]
    -> Dec
    DataD [] Name
    name [] Maybe Type
    forall a. Maybe a
    Nothing [Name -> [VarBangType] -> Con
    RecC Name
    name (((Name, Type) -> VarBangType) -> [(Name, Type)] -> [VarBangType]
    forall a b. (a -> b) -> [a] -> [b]
    map (Name, Type) -> VarBangType
    forall {a} {c}. (a, c) -> (a, Bang, c)
    mkVarBangType [(Name, Type)]
    pairs)]
    #if __GLASGOW_HASKELL__ >= 802
            [DerivClause]
    deriveShowAndEQ
    #else
            []
    #endif
      where mkVarBangType :: (a, c) -> (a, Bang, c)
    mkVarBangType (a
    fieldName, c
    fieldType) =
              (a
    fieldName, SourceUnpackedness -> SourceStrictness -> Bang
    Bang SourceUnpackedness
    NoSourceUnpackedness SourceStrictness
    NoSourceStrictness, c
    fieldType)

    standaloneDeriveEqShow :: Name -> [Dec]
    #if __GLASGOW_HASKELL__ < 802
    standaloneDeriveEqShow name =
      [ StandaloneDerivD [] (ConT ''Eq `AppT` ConT name)
      , StandaloneDerivD [] (ConT ''Show `AppT` ConT name)
      ]
    #else
    standaloneDeriveEqShow :: Name -> [Dec]
    standaloneDeriveEqShow Name
    _ = []
    #endif

    type GetTypeForName = String -> T.Type -> Maybe Type

    data RecordGenerationParams = RecordGenerationParams
      { RecordGenerationParams -> Maybe [Char]
    recordName :: Maybe String
      , RecordGenerationParams -> [Char]
    recordPrefix :: String
      , RecordGenerationParams -> GetTypeForName
    recordTypeForName :: GetTypeForName
      }

    defaultRecordGenerationParams :: RecordGenerationParams
    defaultRecordGenerationParams :: RecordGenerationParams
    defaultRecordGenerationParams = RecordGenerationParams
      { recordName :: Maybe [Char]
    recordName = Maybe [Char]
    forall a. Maybe a
    Nothing
      , recordPrefix :: [Char]
    recordPrefix = [Char]
    "_"
      , recordTypeForName :: GetTypeForName
    recordTypeForName = (Type -> Maybe Type) -> GetTypeForName
    forall a b. a -> b -> a
    const ((Type -> Maybe Type) -> GetTypeForName)
    -> (Type -> Maybe Type) -> GetTypeForName
    forall a b. (a -> b) -> a -> b
    $ Maybe Type -> Type -> Maybe Type
    forall a b. a -> b -> a
    const Maybe Type
    forall a. Maybe a
    Nothing
      }

    generateGetAllRecord
      :: RecordGenerationParams
      -> GenerationParams
      -> I.Interface
      -> Q [Dec]
    generateGetAllRecord :: RecordGenerationParams -> GenerationParams -> Interface -> Q [Dec]
    generateGetAllRecord
                   RecordGenerationParams
                   { recordName :: RecordGenerationParams -> Maybe [Char]
    recordName = Maybe [Char]
    recordNameString
                   , recordPrefix :: RecordGenerationParams -> [Char]
    recordPrefix = [Char]
    prefix
                   , recordTypeForName :: RecordGenerationParams -> GetTypeForName
    recordTypeForName = GetTypeForName
    getTypeForName
                   }
                   GenerationParams { getTHType :: GenerationParams -> Type -> Type
    getTHType = Type -> Type
    getArgType }
                   I.Interface { interfaceName :: Interface -> InterfaceName
    I.interfaceName = InterfaceName
    interfaceName
                               , interfaceProperties :: Interface -> [Property]
    I.interfaceProperties = [Property]
    properties
                               } = do
      let theRecordName :: Name
    theRecordName =
            Name -> ([Char] -> Name) -> Maybe [Char] -> Name
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ([Char] -> Name
    mkName ([Char] -> Name) -> [Char] -> Name
    forall a b. (a -> b) -> a -> b
    $ (Char -> Char) -> [Char] -> [Char]
    forall a b. (a -> b) -> [a] -> [b]
    map Char -> Char
    Char.toUpper ([Char] -> [Char]) -> [Char] -> [Char]
    forall a b. (a -> b) -> a -> b
    $ (Char -> Bool) -> [Char] -> [Char]
    forall a. (a -> Bool) -> [a] -> [a]
    filter Char -> Bool
    Char.isLetter ([Char] -> [Char]) -> [Char] -> [Char]
    forall a b. (a -> b) -> a -> b
    $ InterfaceName -> [Char]
    forall a b. Coercible a b => a -> b
    coerce InterfaceName
    interfaceName)
                  [Char] -> Name
    mkName Maybe [Char]
    recordNameString
      let getPairFromProperty :: Property -> (Name, Type)
    getPairFromProperty I.Property
                                { propertyName :: Property -> [Char]
    I.propertyName = [Char]
    propName
                                , propertyType :: Property -> Type
    I.propertyType = Type
    propType
                                } =
                                ( [Char] -> Name
    mkName ([Char] -> Name) -> [Char] -> Name
    forall a b. (a -> b) -> a -> b
    $ [Char]
    prefix [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    propName
                                , Type -> Maybe Type -> Type
    forall a. a -> Maybe a -> a
    fromMaybe (Type -> Type
    getArgType Type
    propType) (Maybe Type -> Type) -> Maybe Type -> Type
    forall a b. (a -> b) -> a -> b
    $ GetTypeForName
    getTypeForName [Char]
    propName Type
    propType
                                )
          getAllRecord :: Dec
    getAllRecord =
            Name -> [(Name, Type)] -> Dec
    buildDataFromNameTypePairs
            Name
    theRecordName ([(Name, Type)] -> Dec) -> [(Name, Type)] -> Dec
    forall a b. (a -> b) -> a -> b
    $ (Property -> (Name, Type)) -> [Property] -> [(Name, Type)]
    forall a b. (a -> b) -> [a] -> [b]
    map Property -> (Name, Type)
    getPairFromProperty [Property]
    properties
      [Dec] -> Q [Dec]
    forall a. a -> Q a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Dec] -> Q [Dec]) -> [Dec] -> Q [Dec]
    forall a b. (a -> b) -> a -> b
    $ Dec
    getAllRecordDec -> [Dec] -> [Dec]
    forall a. a -> [a] -> [a]
    :Name -> [Dec]
    standaloneDeriveEqShow Name
    theRecordName

    generateClientFromFile :: RecordGenerationParams -> GenerationParams -> Bool -> FilePath -> Q [Dec]
    generateClientFromFile :: RecordGenerationParams
    -> GenerationParams -> Bool -> [Char] -> Q [Dec]
    generateClientFromFile RecordGenerationParams
    recordGenerationParams GenerationParams
    params Bool
    useObjectPath [Char]
    filepath = do
      Object
    object <- [Char] -> ObjectPath -> Q Object
    getIntrospectionObjectFromFile [Char]
    filepath ObjectPath
    "/"
      let interface :: Interface
    interface = [Interface] -> Interface
    forall a. HasCallStack => [a] -> a
    head ([Interface] -> Interface) -> [Interface] -> Interface
    forall a b. (a -> b) -> a -> b
    $ Object -> [Interface]
    I.objectInterfaces Object
    object
          actualObjectPath :: ObjectPath
    actualObjectPath = Object -> ObjectPath
    I.objectPath Object
    object
          realParams :: GenerationParams
    realParams =
            if Bool
    useObjectPath
              then GenerationParams
    params {genObjectPath = Just actualObjectPath}
              else GenerationParams
    params
          <++> :: Q [a] -> Q [a] -> Q [a]
    (<++>) = ([a] -> [a] -> [a]) -> Q [a] -> Q [a] -> Q [a]
    forall a b c. (a -> b -> c) -> Q a -> Q b -> Q c
    forall (f :: * -> *) a b c.
    Applicative f =>
    (a -> b -> c) -> f a -> f b -> f c
    liftA2 [a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    (++)
      RecordGenerationParams -> GenerationParams -> Interface -> Q [Dec]
    generateGetAllRecord RecordGenerationParams
    recordGenerationParams GenerationParams
    params Interface
    interface Q [Dec] -> Q [Dec] -> Q [Dec]
    forall {a}. Q [a] -> Q [a] -> Q [a]
    <++>
        GenerationParams -> Interface -> Q [Dec]
    generateClient GenerationParams
    realParams Interface
    interface Q [Dec] -> Q [Dec] -> Q [Dec]
    forall {a}. Q [a] -> Q [a] -> Q [a]
    <++>
        GenerationParams -> Interface -> Q [Dec]
    generateSignalsFromInterface GenerationParams
    realParams Interface
    interface