module Text.XML.ParentAttributes
  ( ToXmlParentAttributes(..)
  , ToXmlAttribute(..)
  , toXmlAttributeIntegral
  ) where

import Data.Text as T.S
import Data.Text.Lazy as T.L
import Data.Text.Lazy.Builder as T.L
import Data.Text.Lazy.Builder.Int as T.L
import Numeric.Natural
import Text.XML

class ToXmlParentAttributes a where
  toXmlParentAttributes :: a -> [(Name, T.S.Text)]

-- | A catch-all instance: by default objects don't have parent attributes.
-- The alternative solution is to write a default implementation in the class,
-- but it has a drawback that it requires numerous (boilerplate) empty
-- instances - one for each type that doesn't have parent attributes (most
-- types). This overlappable instance gets overriden for XML records
-- (described in "Data.THGen.XML") because they can store parent attributes
-- added via the @!%@ and @?%@ operators.
-- For example, `toXmlParentAttributes` applied to a `Text` or `Integer' value
-- returns @[]@ because of this instance. However, an XML record defined as
-- @"Foo" =:= record !% "bar"@ will have its own TH-generated
-- `ToXmlParentAttributes` instance that inspects the value of its @bar@ field
-- and returns it as an attribute.
-- This way the TH-generators can safely apply `toXmlParentAttributes` to any
-- value without worrying about missing instances.
instance {-# OVERLAPPABLE #-} ToXmlParentAttributes a where
  toXmlParentAttributes _ = []

class ToXmlAttribute a where
  toXmlAttribute :: a -> T.S.Text

instance ToXmlAttribute T.S.Text where
  toXmlAttribute = id

toXmlAttributeIntegral :: Integral a => a -> T.S.Text
toXmlAttributeIntegral = T.L.toStrict . T.L.toLazyText . T.L.decimal

instance ToXmlAttribute Int where
  toXmlAttribute = toXmlAttributeIntegral

instance ToXmlAttribute Word where
  toXmlAttribute = toXmlAttributeIntegral

instance ToXmlAttribute Integer where
  toXmlAttribute = toXmlAttributeIntegral

instance ToXmlAttribute Natural where
  toXmlAttribute = toXmlAttributeIntegral