{-# LANGUAGE
    DeriveDataTypeable
  , FlexibleInstances
  , MultiParamTypeClasses
  , OverloadedStrings
  , RecordWildCards
  , TemplateHaskell
  , TypeSynonymInstances
  , UnicodeSyntax
  #-}
-- |An internal module for entity tags.
module Network.HTTP.Lucu.ETag
    ( ETag(..)
    , strongETag
    , weakETag
    )
    where
import Control.Applicative
import Data.Ascii (Ascii, AsciiBuilder)
import Data.Attoparsec.Char8
import Data.Convertible.Base
import Data.Convertible.Instances.Ascii ()
import Data.Convertible.Utils
import Data.Data
import Data.Default
import Data.Monoid.Unicode
import Language.Haskell.TH.Syntax
import Network.HTTP.Lucu.OrphanInstances ()
import Network.HTTP.Lucu.Parser.Http hiding (token)
import Network.HTTP.Lucu.Utils
import Prelude.Unicode

-- |An entity tag consists of a weakness flag and an opaque string.
data ETag = ETag {
      -- |The weakness flag. Weak tags looks like @W\/\"blahblah\"@
      -- and strong tags are like @\"blahblah\"@. See:
      -- <http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.3>
      etagIsWeak  !Bool
      -- |An opaque string. Only characters from 0x20 (sp) to 0x7e (~)
      -- are allowed.
    , etagToken   !Ascii
    } deriving (Eq, Show, Data, Typeable)

instance Lift ETag where
    lift (ETag {..})
        = [| ETag {
               etagIsWeak = $(lift etagIsWeak)
             , etagToken  = $(lift etagToken )
             }
           |]

instance ConvertSuccess ETag Ascii where
    {-# INLINE convertSuccess #-}
    convertSuccess = convertSuccessVia (()  AsciiBuilder)

instance ConvertSuccess ETag AsciiBuilder where
    {-# INLINE convertSuccess #-}
    convertSuccess (ETag {..})
        = ( if etagIsWeak then
                cs ("W/"  Ascii)
            else
                ()
          )
          
          quoteStr etagToken

deriveAttempts [ ([t| ETag |], [t| Ascii        |])
               , ([t| ETag |], [t| AsciiBuilder |])
               ]

-- |This is equivalent to @'ETag' 'False'@. If you want to generate an
-- ETag from a file, try using
-- 'Network.HTTP.Lucu.StaticFile.generateETagFromFile'.
strongETag  Ascii  ETag
{-# INLINE strongETag #-}
strongETag = ETag False

-- |This is equivalent to @'ETag' 'True'@.
weakETag  Ascii  ETag
{-# INLINE weakETag #-}
weakETag = ETag True

instance Default (Parser ETag) where
    {-# INLINEABLE def #-}
    def = do isWeak  option False (string "W/" *> return True)
             str     quotedStr
             return $ ETag isWeak str

instance Default (Parser [ETag]) where
    {-# INLINE def #-}
    def = listOf def