content: {-# LANGUAGE DeriveFunctor #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE DeriveDataTypeable #-}
  {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE FunctionalDependencies #-}
  
  -- | (More than just) Van Laarhoven lenses for XMPP types. The accessors in here
  -- are designed to work with an optics library like lens or lens-family. This
  -- module also provides a few simple functions ('view', 'modify', 'set' and
  -- 'getAll') so you don't need to pull in another library to get some use out
  -- of them.
  --
  -- * The name of the lenses corresponds to the field name of the data types with
  -- an upper-case L appended. For documentation of the fields refer to the documentation of the data types (linked in the section header)
  --
  -- * Same goes for Traversals, except they are suffixed with a \'T\'
  --
  -- * Prism generally start with an underscore
  --
  -- /NB/ you do not need to import this module to get access to the optics
  -- defined herein. They are also exported from Network.Xmpp. You only need to
  -- import this module if you want to use the complementary accessor functions
  -- without using an optics library like lens or lens-family
  
  module Network.Xmpp.Lens
         ( Lens
         , Traversal
         , Prism
         , Iso
           -- * Accessors
           -- | Reimplementation of the basic lens functions so you don't have to
           -- bring in a lens library to use the optics
  
           -- ** Lenses
         , LF.view
         , modify
         , LF.set
           -- * Traversals
         , getAll
           -- * Prisms
  
           -- ** Construction
         , prism'
         , mkLens
         , mkIso
           -- * Lenses
  
           -- ** JID
         , _JidText
         , _isFull
         , _isBare
  
           -- ** Stanzas and Nonzas
         , _Stanza
         , _Nonza
         , _IQRequest
         , _IQResult
         , _IQError
         , _Message
         , _MessageError
         , _Presence
         , _PresenceError
         , IsStanza(..)
         , HasStanzaPayload(..)
         , IsErrorStanza(..)
         , messageTypeL
         , presenceTypeL
         , iqRequestTypeL
           -- *** 'StanzaError'
         , stanzaErrorTypeL
         , stanzaErrorConditionL
         , stanzaErrorTextL
         , stanzaErrorApplL
           -- ** Stream
  
           -- ** Stream Features
         , featureTlsL
         , featureMechanismsL
         , featureRosterVerL
         , featurePreApprovalL
         , featuresOtherL
           -- *** 'StreamConfiguration'
         , preferredLangL
         , toJidL
         , connectionDetailsL
         , resolvConfL
         , tlsBehaviourL
         , tlsParamsL
           -- **** TLS parameters
         , clientServerIdentificationL
         , tlsServerIdentificationL
         , clientSupportedL
         , supportedCiphersL
         , supportedVersionsL
         , tlsSupportedCiphersL
         , tlsSupportedVersionsL
         , clientUseServerNameIndicationL
         , tlsUseNameIndicationL
           -- *** 'SessionConfiguration'
         , streamConfigurationL
         , onConnectionClosedL
         , sessionStanzaIDsL
         , ensableRosterL
         , onRosterPushL
         , pluginsL
         , onPresenceChangeL
           -- ** IM
           -- *** Roster
           -- **** 'Roster'
         , verL
         , itemsL
           -- **** 'Item'
         , riApprovedL
         , riAskL
         , riJidL
         , riNameL
         , riSubscriptionL
         , riGroupsL
           -- **** 'QueryItem'
         , qiApprovedL
         , qiAskL
         , qiJidL
         , qiNameL
         , qiSubscriptionL
         , qiGroupsL
           -- **** 'Query'
         , queryVerL
         , queryItemsL
           -- ** IM Message
           -- *** 'MessageBody'
         , bodyLangL
         , bodyContentL
           -- *** 'MessageThread'
         , threadIdL
         , threadParentL
           -- *** 'MessageSubject'
         , subjectLangL
         , subjectContentL
           -- *** 'InstantMessage'
         , imThreadL
         , imSubjectL
         , imBodyL
           -- ** 'IMPresence'
         , showStatusL
         , statusL
         , priorityL
  
         )
         where
  
  import           Control.Applicative
  import qualified Data.ByteString as BS
  import           Data.Functor.Identity (Identity(..))
  import qualified Data.Map as Map
  import           Data.Profunctor
  import           Data.Text (Text)
  import qualified Data.Text as Text
  import           Data.XML.Types (Element)
  import qualified Lens.Family2 as LF
  import           Network.DNS (ResolvConf)
  import           Network.TLS as TLS
  import           Network.Xmpp.Concurrent.Types
  import           Network.Xmpp.IM.Message
  import           Network.Xmpp.IM.Presence
  import           Network.Xmpp.IM.PresenceTracker.Types
  import           Network.Xmpp.IM.Roster.Types
  import           Network.Xmpp.Types
  
  -- | Van-Laarhoven lenses.
  {-# DEPRECATED Lens "Use Lens' from lens-family or lens" #-}
  type Lens a b = forall f . Functor f => (b -> f b) -> a -> f a
  
  {-# DEPRECATED Traversal "Use Traversal' from lens-family or lens" #-}
  type Traversal a b = forall f . Applicative f => (b -> f b) -> a -> f a
  
  type Prism a b = forall p f. (Choice p, Applicative f) => p b (f b) -> p a (f a)
  
  type Iso a b = forall p f. (Profunctor p, Functor f) => p b (f b) -> p a (f a)
  
  prism' :: (b -> s) -> (s -> Maybe b) -> Prism s b
  prism' bs sma = dimap (\s -> maybe (Left s) Right (sma s))
                        (either pure (fmap bs)) . right'
  
  mkLens :: (a -> b) -> (b -> a ->  a) -> Lens a b
  mkLens get set = \inj x -> fmap (flip set x) (inj $ get x)
  
  mkIso :: (a -> b) -> (b -> a) -> Iso a b
  mkIso t f = dimap t (fmap f)
  
  newtype Collect a b = Collect {getCollection :: [a]} deriving Functor
  
  instance Applicative (Collect a) where
      pure _ = Collect []
      Collect xs <*> Collect ys = Collect $ xs ++ ys
  
  {-# DEPRECATED getAll "use toListOf (lens-family), partsOf (lens) or similar" #-}
  -- | Return all the values a Traversal is pointing to in a list
  getAll :: Traversal a b -> a -> [b]
  getAll t = getCollection . t (Collect . pure)
  
  {-# DEPRECATED modify "use over (lens-family, lens)" #-}
  modify :: Traversal a b -> (b -> b) -> a -> a
  modify t f = runIdentity . t (Identity . f)
  
  -- Xmpp Lenses
  --------------------
  
  _JidText :: Prism Text Jid
  _JidText = prism' jidToText jidFromText
  
  _isFull :: Prism Jid Jid
  _isFull = prism' id (\j -> if isFull j then Just j else Nothing)
  
  _isBare :: Prism Jid Jid
  _isBare = prism' toBare (\j -> if isBare j then Just j else Nothing)
  
  _Stanza :: Prism XmppElement Stanza
  _Stanza = prism' XmppStanza (\v -> case v of
                                      XmppStanza s -> Just s
                                      _ -> Nothing)
  
  _Nonza :: Prism XmppElement Element
  _Nonza = prism' XmppNonza (\v -> case v of
                                    XmppNonza n -> Just n
                                    _ -> Nothing)
  
  
  class IsStanza s where
      -- | From-attribute of the stanza
      from :: Lens s (Maybe Jid)
      -- | To-attribute of the stanza
      to   :: Lens s (Maybe Jid)
      -- | Langtag of the stanza
      lang :: Lens s (Maybe LangTag)
      -- | Stanza ID. Setting this to /Nothing/ for IQ* stanzas will set the id to
      -- the empty Text.
      sid :: Lens s (Maybe Text)
      -- | Traversal over the payload elements.
      payloadT :: Traversal s Element
  
  traverseList :: Traversal [a] a
  traverseList _inj [] = pure []
  traverseList inj  (x:xs) = (:) <$> inj x <*> traverseList inj xs
  
  instance IsStanza Message where
      from inj m@(Message{messageFrom=f}) = (\f' -> m{messageFrom = f'}) <$> inj f
      to inj m@(Message{messageTo=t}) = (\t' -> m{messageTo = t'}) <$> inj t
      lang inj m@(Message{messageLangTag=t}) =
          (\t' -> m{messageLangTag = t'}) <$> inj t
      sid inj m@(Message{messageID = i}) =
          ((\i' -> m{messageID = i'}) <$> inj i)
      payloadT inj m@(Message{messagePayload=pl}) =
          (\pl' -> m{messagePayload=pl'}) <$> traverseList inj pl
  
  
  instance IsStanza MessageError where
      from inj m@(MessageError{messageErrorFrom=f}) =
          (\f' -> m{messageErrorFrom = f'}) <$> inj f
      to inj m@(MessageError{messageErrorTo=t}) =
          (\t' -> m{messageErrorTo = t'}) <$> inj t
      lang inj m@(MessageError{messageErrorLangTag=t}) =
          (\t' -> m{messageErrorLangTag = t'}) <$> inj t
      sid inj m@(MessageError{messageErrorID = i}) =
          ((\i' -> m{messageErrorID = i'}) <$> inj i)
      payloadT inj m@(MessageError{messageErrorPayload=pl}) =
          (\pl' -> m{messageErrorPayload=pl'}) <$> traverseList inj pl
  
  instance IsStanza Presence where
      from inj m@(Presence{presenceFrom=f}) = (\f' -> m{presenceFrom = f'}) <$> inj f
      to inj m@(Presence{presenceTo=t}) = (\t' -> m{presenceTo = t'}) <$> inj t
      lang inj m@(Presence{presenceLangTag=t}) =
          (\t' -> m{presenceLangTag = t'}) <$> inj t
      sid inj m@(Presence{presenceID = i}) =
          ((\i' -> m{presenceID = i'}) <$> inj i)
      payloadT inj m@(Presence{presencePayload=pl}) =
          (\pl' -> m{presencePayload=pl'}) <$> traverseList inj pl
  
  instance IsStanza PresenceError where
      from inj m@(PresenceError{presenceErrorFrom=f}) =
          (\f' -> m{presenceErrorFrom = f'}) <$> inj f
      to inj m@(PresenceError{presenceErrorTo=t}) =
          (\t' -> m{presenceErrorTo = t'}) <$> inj t
      lang inj m@(PresenceError{presenceErrorLangTag=t}) =
          (\t' -> m{presenceErrorLangTag = t'}) <$> inj t
      sid inj m@(PresenceError{presenceErrorID = i}) =
          ((\i' -> m{presenceErrorID = i'}) <$> inj i)
      payloadT inj m@(PresenceError{presenceErrorPayload=pl}) =
          (\pl' -> m{presenceErrorPayload=pl'}) <$> traverseList inj pl
  
  instance IsStanza IQRequest where
      from inj m@(IQRequest{iqRequestFrom=f}) =
          (\f' -> m{iqRequestFrom = f'}) <$> inj f
      to inj m@(IQRequest{iqRequestTo=t}) =
          (\t' -> m{iqRequestTo = t'}) <$> inj t
      lang inj m@(IQRequest{iqRequestLangTag=t}) =
          (\t' -> m{iqRequestLangTag = t'}) <$> inj t
      sid inj m@(IQRequest{iqRequestID = i}) =
          ((\i' -> m{iqRequestID = i'}) <$> maybeNonempty inj i)
      payloadT inj m@(IQRequest{iqRequestPayload=pl}) =
          (\pl' -> m{iqRequestPayload=pl'}) <$> inj pl
  
  instance IsStanza IQResult where
      from inj m@(IQResult{iqResultFrom=f}) =
          (\f' -> m{iqResultFrom = f'}) <$> inj f
      to inj m@(IQResult{iqResultTo=t}) =
          (\t' -> m{iqResultTo = t'}) <$> inj t
      lang inj m@(IQResult{iqResultLangTag=t}) =
          (\t' -> m{iqResultLangTag = t'}) <$> inj t
      sid inj m@(IQResult{iqResultID = i}) =
          ((\i' -> m{iqResultID = i'}) <$> maybeNonempty inj i)
      payloadT inj m@(IQResult{iqResultPayload=pl}) =
          (\pl' -> m{iqResultPayload=pl'}) <$> maybe (pure Nothing)
                                                     (fmap Just . inj) pl
  
  instance IsStanza IQError where
      from inj m@(IQError{iqErrorFrom=f}) =
          (\f' -> m{iqErrorFrom = f'}) <$> inj f
      to inj m@(IQError{iqErrorTo=t}) =
          (\t' -> m{iqErrorTo = t'}) <$> inj t
      lang inj m@(IQError{iqErrorLangTag=t}) =
          (\t' -> m{iqErrorLangTag = t'}) <$> inj t
      sid inj m@(IQError{iqErrorID = i}) =
          ((\i' -> m{iqErrorID = i'}) <$> maybeNonempty inj i)
      payloadT inj m@(IQError{iqErrorPayload=pl}) =
          (\pl' -> m{iqErrorPayload=pl'}) <$> maybe (pure Nothing)
                                                    (fmap Just . inj) pl
  
  liftLens :: (forall s. IsStanza s => Lens s a) -> Lens Stanza a
  liftLens f inj (IQRequestS     s) = IQRequestS     <$> f inj s
  liftLens f inj (IQResultS      s) = IQResultS      <$> f inj s
  liftLens f inj (IQErrorS       s) = IQErrorS       <$> f inj s
  liftLens f inj (MessageS       s) = MessageS       <$> f inj s
  liftLens f inj (MessageErrorS  s) = MessageErrorS  <$> f inj s
  liftLens f inj (PresenceS      s) = PresenceS      <$> f inj s
  liftLens f inj (PresenceErrorS s) = PresenceErrorS <$> f inj s
  
  liftTraversal :: (forall s. IsStanza s => Traversal s a) -> Traversal Stanza a
  liftTraversal f inj (IQRequestS     s) = IQRequestS     <$> f inj s
  liftTraversal f inj (IQResultS      s) = IQResultS      <$> f inj s
  liftTraversal f inj (IQErrorS       s) = IQErrorS       <$> f inj s
  liftTraversal f inj (MessageS       s) = MessageS       <$> f inj s
  liftTraversal f inj (MessageErrorS  s) = MessageErrorS  <$> f inj s
  liftTraversal f inj (PresenceS      s) = PresenceS      <$> f inj s
  liftTraversal f inj (PresenceErrorS s) = PresenceErrorS <$> f inj s
  
  instance IsStanza Stanza where
      from     = liftLens from
      to       = liftLens to
      lang     = liftLens lang
      sid      = liftLens sid
      payloadT = liftTraversal payloadT
  
  maybeNonempty :: Lens Text (Maybe Text)
  maybeNonempty inj x = (maybe Text.empty id)
                        <$> inj (if Text.null x then Nothing else Just x)
  
  
  _IQRequest :: Prism Stanza IQRequest
  _IQRequest = prism' IQRequestS fromIQRequestS
    where
      fromIQRequestS (IQRequestS s) = Just s
      fromIQRequestS _ = Nothing
  
  _IQResult :: Prism Stanza IQResult
  _IQResult = prism' IQResultS fromIQResultS
    where
      fromIQResultS (IQResultS s) = Just s
      fromIQResultS _ = Nothing
  
  _IQError :: Prism Stanza IQError
  _IQError = prism' IQErrorS fromIQErrorS
    where
      fromIQErrorS (IQErrorS s) = Just s
      fromIQErrorS _ = Nothing
  
  _Message :: Prism Stanza Message
  _Message = prism' MessageS fromMessageS
    where
      fromMessageS (MessageS s) = Just s
      fromMessageS _ = Nothing
  
  _MessageError :: Prism Stanza MessageError
  _MessageError = prism' MessageErrorS fromMessageErrorS
    where
      fromMessageErrorS (MessageErrorS s) = Just s
      fromMessageErrorS _ = Nothing
  
  _Presence :: Prism Stanza Presence
  _Presence = prism' PresenceS fromPresenceS
    where
      fromPresenceS (PresenceS s) = Just s
      fromPresenceS _ = Nothing
  
  _PresenceError :: Prism Stanza PresenceError
  _PresenceError = prism' PresenceErrorS fromPresenceErrorS
    where
      fromPresenceErrorS (PresenceErrorS s) = Just s
      fromPresenceErrorS _ = Nothing
  
  class IsErrorStanza s where
      -- | Error element of the stanza
      stanzaError :: Lens s StanzaError
  
  instance IsErrorStanza IQError where
      stanzaError inj m@IQError{iqErrorStanzaError = i} =
          (\i' -> m{iqErrorStanzaError = i'}) <$> inj i
  
  instance IsErrorStanza MessageError where
      stanzaError inj m@MessageError{messageErrorStanzaError = i} =
          (\i' -> m{messageErrorStanzaError = i'}) <$> inj i
  
  instance IsErrorStanza PresenceError where
      stanzaError inj m@PresenceError{presenceErrorStanzaError = i} =
          (\i' -> m{presenceErrorStanzaError = i'}) <$> inj i
  
  class HasStanzaPayload s p | s -> p where
      -- | Payload element(s) of the stanza. Since the amount of elements possible
      -- in a stanza vary by type, this lens can't be used with a general
      -- 'Stanza'. There is, however, a more general Traversable that works with
      -- all stanzas (including 'Stanza'): 'payloadT'
      payload :: Lens s p
  
  instance HasStanzaPayload IQRequest Element where
      payload inj m@IQRequest{iqRequestPayload = i} =
          (\i' -> m{iqRequestPayload = i'}) <$> inj i
  
  instance HasStanzaPayload IQResult (Maybe Element) where
      payload inj m@IQResult{iqResultPayload = i} =
          (\i' -> m{iqResultPayload = i'}) <$> inj i
  
  instance HasStanzaPayload IQError (Maybe Element) where
      payload inj m@IQError{iqErrorPayload = i} =
          (\i' -> m{iqErrorPayload = i'}) <$> inj i
  
  instance HasStanzaPayload Message [Element] where
      payload inj m@Message{messagePayload = i} =
          (\i' -> m{messagePayload = i'}) <$> inj i
  
  instance HasStanzaPayload MessageError [Element] where
      payload inj m@MessageError{messageErrorPayload = i} =
          (\i' -> m{messageErrorPayload = i'}) <$> inj i
  
  instance HasStanzaPayload Presence [Element] where
      payload inj m@Presence{presencePayload = i} =
          (\i' -> m{presencePayload = i'}) <$> inj i
  
  instance HasStanzaPayload PresenceError [Element] where
      payload inj m@PresenceError{presenceErrorPayload = i} =
          (\i' -> m{presenceErrorPayload = i'}) <$> inj i
  
  iqRequestTypeL :: Lens IQRequest IQRequestType
  iqRequestTypeL inj p@IQRequest{iqRequestType = tp} =
      (\tp' -> p{iqRequestType = tp'}) <$> inj tp
  
  
  messageTypeL :: Lens Message MessageType
  messageTypeL inj p@Message{messageType = tp} =
      (\tp' -> p{messageType = tp'}) <$> inj tp
  
  presenceTypeL :: Lens Presence PresenceType
  presenceTypeL inj p@Presence{presenceType = tp} =
      (\tp' -> p{presenceType = tp'}) <$> inj tp
  
  
  -- StanzaError
  -----------------------
  
  stanzaErrorTypeL :: Lens StanzaError StanzaErrorType
  stanzaErrorTypeL inj se@StanzaError{stanzaErrorType = x} =
      (\x' -> se{stanzaErrorType = x'}) <$> inj x
  
  stanzaErrorConditionL :: Lens StanzaError StanzaErrorCondition
  stanzaErrorConditionL inj se@StanzaError{stanzaErrorCondition = x} =
      (\x' -> se{stanzaErrorCondition = x'}) <$> inj x
  
  stanzaErrorTextL :: Lens StanzaError (Maybe (Maybe LangTag, NonemptyText))
  stanzaErrorTextL inj se@StanzaError{stanzaErrorText = x} =
      (\x' -> se{stanzaErrorText = x'}) <$> inj x
  
  stanzaErrorApplL  :: Lens StanzaError (Maybe Element)
  stanzaErrorApplL inj se@StanzaError{stanzaErrorApplicationSpecificCondition = x} =
      (\x' -> se{stanzaErrorApplicationSpecificCondition = x'}) <$> inj x
  
  
  -- StreamConfiguration
  -----------------------
  
  preferredLangL :: Lens StreamConfiguration (Maybe LangTag)
  preferredLangL inj sc@StreamConfiguration{preferredLang = x}
      = (\x' -> sc{preferredLang = x'}) <$> inj x
  
  toJidL :: Lens StreamConfiguration (Maybe (Jid, Bool))
  toJidL inj sc@StreamConfiguration{toJid = x}
      = (\x' -> sc{toJid = x'}) <$> inj x
  
  connectionDetailsL :: Lens StreamConfiguration ConnectionDetails
  connectionDetailsL inj sc@StreamConfiguration{connectionDetails = x}
      = (\x' -> sc{connectionDetails = x'}) <$> inj x
  
  resolvConfL :: Lens StreamConfiguration ResolvConf
  resolvConfL inj sc@StreamConfiguration{resolvConf = x}
      = (\x' -> sc{resolvConf = x'}) <$> inj x
  
  tlsBehaviourL :: Lens StreamConfiguration TlsBehaviour
  tlsBehaviourL inj sc@StreamConfiguration{tlsBehaviour = x}
      = (\x' -> sc{tlsBehaviour = x'}) <$> inj x
  
  
  tlsParamsL :: Lens StreamConfiguration ClientParams
  tlsParamsL inj sc@StreamConfiguration{tlsParams = x}
      = (\x' -> sc{tlsParams = x'}) <$> inj x
  
  -- TLS parameters
  -----------------
  
  clientServerIdentificationL  :: Lens ClientParams (String, BS.ByteString)
  clientServerIdentificationL inj cp@ClientParams{clientServerIdentification = x}
      = (\x' -> cp{clientServerIdentification = x'}) <$> inj x
  
  clientSupportedL  :: Lens ClientParams Supported
  clientSupportedL inj cp@ClientParams{clientSupported = x}
      = (\x' -> cp{clientSupported = x'}) <$> inj x
  
  clientUseServerNameIndicationL  :: Lens ClientParams Bool
  clientUseServerNameIndicationL inj
      cp@ClientParams{clientUseServerNameIndication = x}
      = (\x' -> cp{clientUseServerNameIndication = x'}) <$> inj x
  
  supportedCiphersL :: Lens Supported [Cipher]
  supportedCiphersL inj s@Supported{supportedCiphers = x}
      = (\x' -> s{supportedCiphers = x'}) <$> inj x
  
  supportedVersionsL :: Lens Supported [TLS.Version]
  supportedVersionsL inj s@Supported{supportedVersions = x}
      = (\x' -> s{supportedVersions = x'}) <$> inj x
  
  -- SessionConfiguration
  -----------------------
  streamConfigurationL :: Lens SessionConfiguration StreamConfiguration
  streamConfigurationL inj sc@SessionConfiguration{sessionStreamConfiguration = x}
      = (\x' -> sc{sessionStreamConfiguration = x'}) <$> inj x
  
  onConnectionClosedL :: Lens SessionConfiguration (Session -> XmppFailure -> IO ())
  onConnectionClosedL inj sc@SessionConfiguration{onConnectionClosed = x}
      = (\x' -> sc{onConnectionClosed = x'}) <$> inj x
  
  sessionStanzaIDsL :: Lens SessionConfiguration (IO (IO Text))
  sessionStanzaIDsL inj sc@SessionConfiguration{sessionStanzaIDs = x}
      = (\x' -> sc{sessionStanzaIDs = x'}) <$> inj x
  
  ensableRosterL :: Lens SessionConfiguration Bool
  ensableRosterL inj sc@SessionConfiguration{enableRoster = x}
      = (\x' -> sc{enableRoster = x'}) <$> inj x
  
  onRosterPushL :: Lens SessionConfiguration (Maybe RosterPushCallback)
  onRosterPushL = mkLens onRosterPush (\orp x -> x{onRosterPush = orp})
  
  pluginsL :: Lens SessionConfiguration [Plugin]
  pluginsL inj sc@SessionConfiguration{plugins = x}
      = (\x' -> sc{plugins = x'}) <$> inj x
  
  onPresenceChangeL :: Lens SessionConfiguration (Maybe ( Jid -> PeerStatus
                                                          -> PeerStatus -> IO ()))
  onPresenceChangeL inj sc@SessionConfiguration{onPresenceChange = x}
      = (\x' -> sc{onPresenceChange = x'}) <$> inj x
  
  -- | Access clientServerIdentification inside tlsParams inside streamConfiguration
  tlsServerIdentificationL  :: Lens SessionConfiguration (String, BS.ByteString)
  tlsServerIdentificationL = streamConfigurationL
                           . tlsParamsL
                           . clientServerIdentificationL
  
  -- | Access clientUseServerNameIndication inside tlsParams
  tlsUseNameIndicationL :: Lens SessionConfiguration Bool
  tlsUseNameIndicationL = streamConfigurationL
                        . tlsParamsL
                        . clientUseServerNameIndicationL
  
  -- | Access supportedCiphers inside clientSupported inside tlsParams
  tlsSupportedCiphersL :: Lens SessionConfiguration [Cipher]
  tlsSupportedCiphersL =  streamConfigurationL
                       .  tlsParamsL . clientSupportedL . supportedCiphersL
  
  -- | Access supportedVersions inside clientSupported inside tlsParams
  tlsSupportedVersionsL :: Lens SessionConfiguration [TLS.Version]
  tlsSupportedVersionsL = streamConfigurationL
                        . tlsParamsL . clientSupportedL . supportedVersionsL
  
  
  -- Roster
  ------------------
  
  verL :: Lens Roster (Maybe Text)
  verL inj r@Roster{ver = x} = (\x' -> r{ver = x'}) <$> inj x
  
  itemsL :: Lens Roster (Map.Map Jid Item)
  itemsL inj r@Roster{items = x} = (\x' -> r{items = x'}) <$> inj x
  
  -- Item
  ------------------
  
  riApprovedL :: Lens Item Bool
  riApprovedL inj i@Item{riApproved = x} = (\x' -> i{riApproved = x'}) <$> inj x
  
  riAskL :: Lens Item Bool
  riAskL inj i@Item{riAsk = x} = (\x' -> i{riAsk = x'}) <$> inj x
  
  riJidL :: Lens Item Jid
  riJidL inj i@Item{riJid = x} = (\x' -> i{riJid = x'}) <$> inj x
  
  riNameL :: Lens Item (Maybe Text)
  riNameL inj i@Item{riName = x} = (\x' -> i{riName = x'}) <$> inj x
  
  riSubscriptionL :: Lens Item Subscription
  riSubscriptionL inj i@Item{riSubscription = x} =
      (\x' -> i{riSubscription = x'}) <$> inj x
  
  riGroupsL :: Lens Item [Text]
  riGroupsL inj i@Item{riGroups = x} = (\x' -> i{riGroups = x'}) <$> inj x
  
  -- Roster Update
  -------------------
  
  _RosterUpdateRemove :: Prism RosterUpdate Jid
  _RosterUpdateRemove = prism' RosterUpdateRemove fromRosterUpdateRemove
    where
      fromRosterUpdateRemove (RosterUpdateRemove jid) = Just jid
      fromRosterUpdateRemove RosterUpdateAdd{} = Nothing
  
  _RosterUpdateAdd :: Prism RosterUpdate Item
  _RosterUpdateAdd = prism' RosterUpdateAdd fromRosterUpdateAdd
    where
      fromRosterUpdateAdd RosterUpdateRemove{} = Nothing
      fromRosterUpdateAdd (RosterUpdateAdd item) = Just item
  
  
  -- QueryItem
  -------------------
  qiApprovedL :: Lens QueryItem (Maybe Bool)
  qiApprovedL inj i@QueryItem{qiApproved = x} =
      (\x' -> i{qiApproved = x'}) <$> inj x
  
  qiAskL :: Lens QueryItem Bool
  qiAskL inj i@QueryItem{qiAsk = x} = (\x' -> i{qiAsk = x'}) <$> inj x
  
  qiJidL :: Lens QueryItem Jid
  qiJidL inj i@QueryItem{qiJid = x} = (\x' -> i{qiJid = x'}) <$> inj x
  
  qiNameL :: Lens QueryItem (Maybe Text)
  qiNameL inj i@QueryItem{qiName = x} = (\x' -> i{qiName = x'}) <$> inj x
  
  qiSubscriptionL :: Lens QueryItem (Maybe Subscription)
  qiSubscriptionL inj i@QueryItem{qiSubscription = x} =
      (\x' -> i{qiSubscription = x'}) <$> inj x
  
  qiGroupsL :: Lens QueryItem [Text]
  qiGroupsL inj i@QueryItem{qiGroups = x} = (\x' -> i{qiGroups = x'}) <$> inj x
  
  queryVerL :: Lens Query (Maybe Text)
  queryVerL inj i@Query{queryVer = x} = (\x' -> i{queryVer = x'}) <$> inj x
  
  queryItemsL :: Lens Query [QueryItem]
  queryItemsL inj i@Query{queryItems = x} = (\x' -> i{queryItems = x'}) <$> inj x
  
  
  -- IM
  -------------------
  
  
  bodyLangL :: Lens MessageBody (Maybe LangTag)
  bodyLangL inj m@MessageBody{bodyLang = bl} = (\bl' -> m{bodyLang = bl'}) <$> inj bl
  
  bodyContentL :: Lens MessageBody Text
  bodyContentL inj m@MessageBody{bodyContent = bc} =
      (\bc' -> m{bodyContent = bc'}) <$> inj bc
  
  threadIdL :: Lens MessageThread Text
  threadIdL inj m@MessageThread{threadID = bc} =
      (\bc' -> m{threadID = bc'}) <$> inj bc
  
  threadParentL :: Lens MessageThread (Maybe Text)
  threadParentL inj m@MessageThread{threadParent = bc} =
      (\bc' -> m{threadParent = bc'}) <$> inj bc
  
  subjectLangL :: Lens MessageSubject (Maybe LangTag)
  subjectLangL inj m@MessageSubject{subjectLang = bc} =
      (\bc' -> m{subjectLang = bc'}) <$> inj bc
  
  subjectContentL :: Lens MessageSubject Text
  subjectContentL inj m@MessageSubject{subjectContent = bc} =
      (\bc' -> m{subjectContent = bc'}) <$> inj bc
  
  imThreadL :: Lens InstantMessage (Maybe MessageThread)
  imThreadL inj m@InstantMessage{imThread = bc} =
      (\bc' -> m{imThread = bc'}) <$> inj bc
  
  imSubjectL :: Lens InstantMessage [MessageSubject]
  imSubjectL inj m@InstantMessage{imSubject = bc} =
      (\bc' -> m{imSubject = bc'}) <$> inj bc
  
  imBodyL :: Lens InstantMessage [MessageBody]
  imBodyL inj m@InstantMessage{imBody = bc} =
      (\bc' -> m{imBody = bc'}) <$> inj bc
  
  -- IM Presence
  ------------------
  
  showStatusL :: Lens IMPresence (Maybe ShowStatus)
  showStatusL inj m@IMP{showStatus = bc} =
      (\bc' -> m{showStatus = bc'}) <$> inj bc
  
  statusL :: Lens IMPresence (Maybe Text)
  statusL inj m@IMP{status = bc} =
      (\bc' -> m{status = bc'}) <$> inj bc
  
  priorityL :: Lens IMPresence (Maybe Int)
  priorityL inj m@IMP{priority = bc} =
      (\bc' -> m{priority = bc'}) <$> inj bc
  
  -- StreamFeatures
  -------------------
  
  featureTlsL :: Lens StreamFeatures (Maybe Bool)
  featureTlsL = mkLens streamFeaturesTls (\x sf -> sf{streamFeaturesTls = x})
  
  featureMechanismsL :: Lens StreamFeatures [Text]
  featureMechanismsL =
      mkLens streamFeaturesMechanisms (\x sf -> sf{streamFeaturesMechanisms = x})
  
  featureRosterVerL :: Lens StreamFeatures (Maybe Bool)
  featureRosterVerL =
      mkLens streamFeaturesRosterVer (\x sf -> sf{streamFeaturesRosterVer = x})
  
  featurePreApprovalL :: Lens StreamFeatures Bool
  featurePreApprovalL =
      mkLens streamFeaturesPreApproval (\x sf -> sf{streamFeaturesPreApproval = x})
  
  featuresOtherL :: Lens StreamFeatures [Element]
  featuresOtherL =
      mkLens streamFeaturesOther (\x sf -> sf{streamFeaturesOther = x})
  