content: {-# LANGUAGE BangPatterns               #-}
  {-# LANGUAGE CPP                        #-}
  {-# LANGUAGE DeriveDataTypeable         #-}
  {-# LANGUAGE FlexibleInstances          #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses      #-}
  {-# LANGUAGE ScopedTypeVariables        #-}
  {-# LANGUAGE UndecidableInstances       #-}
  
  {-|
  
  Internal types and accessors.  There are no guarantees that heist will
  preserve backwards compatibility for symbols in this module.  If you use them,
  no complaining when your code breaks.
  
  -}
  
  module Heist.Internal.Types
    ( module Heist.Internal.Types.HeistState
    , module Heist.Internal.Types
    ) where
  
  ------------------------------------------------------------------------------
  import           Data.HashMap.Strict (HashMap)
  import           Data.Text (Text)
  
  #if !MIN_VERSION_base(4,8,0)
  import           Control.Applicative
  #endif
  #if !MIN_VERSION_base(4,11,0)
  import           Data.Semigroup
  #endif
  
  ------------------------------------------------------------------------------
  import qualified Heist.Compiled.Internal       as C
  import qualified Heist.Interpreted.Internal    as I
  import           Heist.Internal.Types.HeistState
  ------------------------------------------------------------------------------
  
  
  ------------------------------------------------------------------------------
  type TemplateRepo = HashMap TPath DocumentFile
  
  
  ------------------------------------------------------------------------------
  -- | An IO action for getting a template repo from this location.  By not just
  -- using a directory path here, we support templates loaded from a database,
  -- retrieved from the network, or anything else you can think of.
  type TemplateLocation = IO (Either [String] TemplateRepo)
  
  
  ------------------------------------------------------------------------------
  -- | My lens creation function to avoid a dependency on lens.
  lens :: Functor f => (t1 -> t) -> (t1 -> a -> b) -> (t -> f a) -> t1 -> f b
  lens sa sbt afb s = sbt s <$> afb (sa s)
  
  
  ------------------------------------------------------------------------------
  -- | The splices and templates Heist will use.  To bind a splice simply
  -- include it in the appropriate place here.
  data SpliceConfig m = SpliceConfig
      { _scInterpretedSplices     :: Splices (I.Splice m)
          -- ^ Interpreted splices are the splices that Heist has always had.
          -- They return a list of nodes and are processed at runtime.
      , _scLoadTimeSplices        :: Splices (I.Splice IO)
          -- ^ Load time splices are like interpreted splices because they
          -- return a list of nodes.  But they are like compiled splices because
          -- they are processed once at load time.  All of Heist's built-in
          -- splices should be used as load time splices.
      , _scCompiledSplices        :: Splices (C.Splice m)
          -- ^ Compiled splices return a DList of Chunks and are processed at
          -- load time to generate a runtime monad action that will be used to
          -- render the template.
      , _scAttributeSplices       :: Splices (AttrSplice m)
          -- ^ Attribute splices are bound to attribute names and return a list
          -- of attributes.
      , _scTemplateLocations      :: [TemplateLocation]
          -- ^ A list of all the locations that Heist should get its templates
          -- from.
      , _scCompiledTemplateFilter :: TPath -> Bool
          -- ^ Predicate function to control which templates to compile.  Using
          -- templates filtered out with this is still possible via
          -- callTemplate.
      }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for interpreted splices
  -- :: Simple Lens (SpliceConfig m) (Splices (I.Splice m))
  scInterpretedSplices
      :: Functor f
      => (Splices (I.Splice m) -> f (Splices (I.Splice m)))
      -> SpliceConfig m -> f (SpliceConfig m)
  scInterpretedSplices = lens _scInterpretedSplices setter
    where
      setter sc v = sc { _scInterpretedSplices = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for load time splices
  -- :: Simple Lens (SpliceConfig m) (Splices (I.Splice IO))
  scLoadTimeSplices
      :: Functor f
      => (Splices (I.Splice IO) -> f (Splices (I.Splice IO)))
      -> SpliceConfig m -> f (SpliceConfig m)
  scLoadTimeSplices = lens _scLoadTimeSplices setter
    where
      setter sc v = sc { _scLoadTimeSplices = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for complied splices
  -- :: Simple Lens (SpliceConfig m) (Splices (C.Splice m))
  scCompiledSplices
      :: Functor f
      => (Splices (C.Splice m) -> f (Splices (C.Splice m)))
      -> SpliceConfig m -> f (SpliceConfig m)
  scCompiledSplices = lens _scCompiledSplices setter
    where
      setter sc v = sc { _scCompiledSplices = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for attribute splices
  -- :: Simple Lens (SpliceConfig m) (Splices (AttrSplice m))
  scAttributeSplices
      :: Functor f
      => (Splices (AttrSplice m) -> f (Splices (AttrSplice m)))
      -> SpliceConfig m -> f (SpliceConfig m)
  scAttributeSplices = lens _scAttributeSplices setter
    where
      setter sc v = sc { _scAttributeSplices = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for template locations
  -- :: Simple Lens (SpliceConfig m) [TemplateLocation]
  scTemplateLocations
      :: Functor f
      => ([TemplateLocation] -> f [TemplateLocation])
      -> SpliceConfig m -> f (SpliceConfig m)
  scTemplateLocations = lens _scTemplateLocations setter
    where
      setter sc v = sc { _scTemplateLocations = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for compiled template filter
  -- :: Simple Lens (SpliceConfig m) (TBool -> Bool)
  scCompiledTemplateFilter
      :: Functor f
      => ((TPath -> Bool) -> f (TPath -> Bool))
      -> SpliceConfig m -> f (SpliceConfig m)
  scCompiledTemplateFilter = lens _scCompiledTemplateFilter setter
    where
      setter sc v = sc { _scCompiledTemplateFilter = v }
  
  
  instance Semigroup (SpliceConfig m) where
      SpliceConfig a1 b1 c1 d1 e1 f1 <> SpliceConfig a2 b2 c2 d2 e2 f2 =
        SpliceConfig (a1 <> a2) (b1 <> b2) (c1 <> c2)
                     (d1 <> d2) (e1 <> e2) (\x -> f1 x && f2 x)
  
  instance Monoid (SpliceConfig m) where
      mempty = SpliceConfig mempty mempty mempty mempty mempty (const True)
  #if !MIN_VERSION_base(4,11,0)
      mappend = (<>)
  #endif
  
  
  data HeistConfig m = HeistConfig
      { _hcSpliceConfig  :: SpliceConfig m
          -- ^ Splices and templates
      , _hcNamespace     :: Text
          -- ^ A namespace to use for all tags that are bound to splices.  Use
          -- empty string for no namespace.
      , _hcErrorNotBound :: Bool
          -- ^ Whether to throw an error when a tag wih the heist namespace does
          -- not correspond to a bound splice.  When not using a namespace, this
          -- flag is ignored.
      }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for the SpliceConfig
  -- :: Simple Lens (HeistConfig m) (SpliceConfig m)
  hcSpliceConfig
      :: Functor f
      => ((SpliceConfig m) -> f (SpliceConfig m))
      -> HeistConfig m -> f (HeistConfig m)
  hcSpliceConfig = lens _hcSpliceConfig setter
    where
      setter hc v = hc { _hcSpliceConfig = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for the namespace
  -- :: Simple Lens (HeistConfig m) Text
  hcNamespace
      :: Functor f
      => (Text -> f Text)
      -> HeistConfig m -> f (HeistConfig m)
  hcNamespace = lens _hcNamespace setter
    where
      setter hc v = hc { _hcNamespace = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for the namespace error flag
  -- :: Simple Lens (HeistConfig m) Bool
  hcErrorNotBound
      :: Functor f
      => (Bool -> f Bool)
      -> HeistConfig m -> f (HeistConfig m)
  hcErrorNotBound = lens _hcErrorNotBound setter
    where
      setter hc v = hc { _hcErrorNotBound = v }
  
  
  ------------------------------------------------------------------------------
  -- | Lens for interpreted splices
  -- :: Simple Lens (HeistConfig m) (Splices (I.Splice m))
  hcInterpretedSplices
      :: Functor f
      => (Splices (I.Splice m) -> f (Splices (I.Splice m)))
      -> HeistConfig m -> f (HeistConfig m)
  hcInterpretedSplices = hcSpliceConfig . scInterpretedSplices
  
  
  ------------------------------------------------------------------------------
  -- | Lens for load time splices
  -- :: Simple Lens (HeistConfig m) (Splices (I.Splice IO))
  hcLoadTimeSplices
      :: Functor f
      => (Splices (I.Splice IO) -> f (Splices (I.Splice IO)))
      -> HeistConfig m -> f (HeistConfig m)
  hcLoadTimeSplices = hcSpliceConfig . scLoadTimeSplices 
  
  
  ------------------------------------------------------------------------------
  -- | Lens for compiled splices
  -- :: Simple Lens (HeistConfig m) (Splices (C.Splice m))
  hcCompiledSplices
      :: Functor f
      => (Splices (C.Splice m) -> f (Splices (C.Splice m)))
      -> HeistConfig m -> f (HeistConfig m)
  hcCompiledSplices = hcSpliceConfig . scCompiledSplices 
  
  
  ------------------------------------------------------------------------------
  -- | Lens for attribute splices
  -- :: Simple Lens (HeistConfig m) (Splices (AttrSplice m))
  hcAttributeSplices
      :: Functor f
      => (Splices (AttrSplice m) -> f (Splices (AttrSplice m)))
      -> HeistConfig m -> f (HeistConfig m)
  hcAttributeSplices = hcSpliceConfig . scAttributeSplices 
  
  
  ------------------------------------------------------------------------------
  -- | Lens for template locations
  -- :: Simple Lens (HeistConfig m) [TemplateLocation]
  hcTemplateLocations
      :: Functor f
      => ([TemplateLocation] -> f [TemplateLocation])
      -> HeistConfig m -> f (HeistConfig m)
  hcTemplateLocations = hcSpliceConfig . scTemplateLocations 
  
  
  ------------------------------------------------------------------------------
  -- | Lens for compiled template filter
  -- :: Simple Lens (SpliceConfig m) (TBool -> Bool)
  hcCompiledTemplateFilter
      :: Functor f
      => ((TPath -> Bool) -> f (TPath -> Bool))
      -> HeistConfig m -> f (HeistConfig m)
  hcCompiledTemplateFilter = hcSpliceConfig . scCompiledTemplateFilter
  
  
  