{-# LANGUAGE DeriveDataTypeable, UnicodeSyntax, Trustworthy #-}

-- | Microformats 2 types for Haskell.
--
-- Notes:
--
-- 1. We don't duplicate sub-properties in parent types.
--    E.g. h-adr has both p-geo and p-latitude, p-longitude, p-altitude.
--    Adr only has a Geo.
--
-- 2. Lazy Text is used for storing texts, because it's the format used in Scotty, Hastache and other popular web libraries.
--
-- 3. Lists are used everywhere, because all properties might be multivalued, even though it doesn't always make sense.
--    Use 'headMay' from the safe package!
--
-- 4. SomethingReference sum types are used for, well, references.
--    The spec always makes embedded microformats optional, so these types include Text options.
--
module Data.Microformats2 where

import safe      Data.Typeable (Typeable)
import safe      Data.Text.Lazy (Text)
import safe      Data.Data (Data)
import           Data.Default.Class
import           Data.Time (UTCTime)
import           Text.Pandoc.Definition (Pandoc)

-- | A Geo reference.
data GeoReference = TextGeo Text | UrlGeo Text | GeoGeo Geo -- LOL
  deriving (Eq, Show, Data, Typeable)

-- | An Adr reference.
data AdrReference = TextAdr Text | AdrAdr Adr
  deriving (Eq, Show, Data, Typeable)

-- | A location (Card/Adr/Geo) reference.
data LocationReference = TextLoc Text | CardLoc Card | AdrLoc Adr | GeoLoc Geo
  deriving (Eq, Show, Data, Typeable)

-- | A Card reference.
data CardReference = TextCard Text | CardCard Card
  deriving (Eq, Show, Data, Typeable)

-- | An Entry/Cite reference.
data EntryReference = TextEntry Text | UrlEntry Text | CiteEntry Cite | EntryEntry Entry
  deriving (Eq, Show, Data, Typeable)

-- | A content reference.
data ContentReference = TextContent Text | PandocContent Pandoc
  deriving (Eq, Show, Data, Typeable)

-- | A Geo type, based on h-geo <http://microformats.org/wiki/h-geo>
data Geo = Geo
  { geoLatitude     [Double]
  , geoLongitude    [Double]
  , geoAltitude     [Double] }
  deriving (Eq, Show, Data, Typeable)

instance Default Geo where
  def = Geo
    { geoLatitude    = []
    , geoLongitude   = []
    , geoAltitude    = [] }

-- | An Adr type, based on h-adr <http://microformats.org/wiki/h-adr>
data Adr = Adr
  { adrStreetAddress     [Text]
  , adrExtendedAddress   [Text]
  , adrPostOfficeBox     [Text]
  , adrLocality          [Text]
  , adrRegion            [Text]
  , adrPostalCode        [Text]
  , adrCountryName       [Text]
  , adrLabel             [Text]
  , adrGeo               [GeoReference] }
  deriving (Eq, Show, Data, Typeable)

instance Default Adr where
  def = Adr
    { adrStreetAddress    = []
    , adrExtendedAddress  = []
    , adrPostOfficeBox    = []
    , adrLocality         = []
    , adrRegion           = []
    , adrPostalCode       = []
    , adrCountryName      = []
    , adrLabel            = []
    , adrGeo              = [] }

-- | A Card type, based on h-card <http://microformats.org/wiki/h-card>
data Card = Card
  { cardName               [Text]
  , cardHonorificPrefix    [Text]
  , cardGivenName          [Text]
  , cardAdditionalName     [Text]
  , cardFamilyName         [Text]
  , cardSortString         [Text]
  , cardHonorificSuffix    [Text]
  , cardNickname           [Text]
  , cardEmail              [Text]
  , cardLogo               [Text]
  , cardPhoto              [Text]
  , cardUrl                [Text]
  , cardUid                [Text]
  , cardCategory           [Text]
  , cardAdr                [AdrReference]
  , cardTel                [Text]
  , cardNote               [Text]
  , cardBday               [UTCTime]
  , cardKey                [Text]
  , cardOrg                [CardReference]
  , cardJobTitle           [Text]
  , cardRole               [Text]
  , cardImpp               [Text]
  , cardSex                [Text]
  , cardGenderIdentity     [Text]
  , cardAnniversary        [UTCTime] }
  deriving (Eq, Show, Data, Typeable)

instance Default Card where
  def = Card
    { cardName              = []
    , cardHonorificPrefix   = []
    , cardGivenName         = []
    , cardAdditionalName    = []
    , cardFamilyName        = []
    , cardSortString        = []
    , cardHonorificSuffix   = []
    , cardNickname          = []
    , cardEmail             = []
    , cardLogo              = []
    , cardPhoto             = []
    , cardUrl               = []
    , cardUid               = []
    , cardCategory          = []
    , cardAdr               = []
    , cardTel               = []
    , cardNote              = []
    , cardBday              = []
    , cardKey               = []
    , cardOrg               = []
    , cardJobTitle          = []
    , cardRole              = []
    , cardImpp              = []
    , cardSex               = []
    , cardGenderIdentity    = []
    , cardAnniversary       = [] }

-- | A Cite type, based on h-cite <http://microformats.org/wiki/h-cite>
data Cite = Cite
  { citeName         [Text]
  , citePublished    [UTCTime]
  , citeAuthor       [CardReference]
  , citeUrl          [Text]
  , citeUid          [Text]
  , citePublication  [Text]
  , citeAccessed     [UTCTime]
  , citeContent      [ContentReference] }
  deriving (Eq, Show, Data, Typeable)

instance Default Cite where
  def = Cite
    { citeName        = []
    , citePublished   = []
    , citeAuthor      = []
    , citeUrl         = []
    , citeUid         = []
    , citePublication = []
    , citeAccessed    = []
    , citeContent     = [] }

-- | An Entry type, based on h-entry <http://microformats.org/wiki/h-entry> with popular extensions.
data Entry = Entry
  { entryName            [Text]
  , entrySummary         [Text]
  , entryContent         [ContentReference]
  , entryPublished       [UTCTime]
  , entryUpdated         [UTCTime]
  , entryAuthor          [CardReference]
  , entryCategory        [Text]
  , entryUrl             [Text]
  , entryUid             [Text]
  , entryLocation        [LocationReference]
  , entryComments        [EntryReference]
  , entrySyndication     [Text]
  , entryInReplyTo       [EntryReference]
  , entryLikeOf          [EntryReference]
  , entryRepostOf        [EntryReference] }
  deriving (Eq, Show, Data, Typeable)

instance Default Entry where
  def = Entry
    { entryName           = []
    , entrySummary        = []
    , entryContent        = []
    , entryPublished      = []
    , entryUpdated        = []
    , entryAuthor         = []
    , entryCategory       = []
    , entryUrl            = []
    , entryUid            = []
    , entryLocation       = []
    , entryComments       = []
    , entrySyndication    = []
    , entryInReplyTo      = []
    , entryLikeOf         = []
    , entryRepostOf       = [] }

citeOfEntry  Entry  Cite
citeOfEntry e = Cite
  { citeName        = entryName e
  , citePublished   = entryPublished e
  , citeAuthor      = entryAuthor e
  , citeUrl         = entryUrl e
  , citeUid         = entryUid e
  , citePublication = []
  , citeAccessed    = []
  , citeContent     = entryContent e }