    --------------------------------------------------------------------
    -- |
    -- Module    : Text.RSS.Syntax
    -- Copyright : (c) Galois, Inc. 2008,
    --             (c) Sigbjorn Finne 2009-
    -- License   : BSD3
    --
    -- Maintainer: Sigbjorn Finne <sof@forkIO.com>
    -- Stability : provisional
    --
    -- The basic syntax for putting together feeds.
    --
    -- For instance, to create a feed with a single item item:
    --  (nullRSS \"rss title\" \"link\") {rssChannel=(nullChannel \"channel title\" \"link\") {rssItems=[(nullItem \"item title\")]}}

    --------------------------------------------------------------------

    module Text.RSS.Syntax where

    import Text.XML.Light as XML

    -- * Core Types

    -- ^The Radio Userland version of RSS documents\/feeds.
    -- (versions 0.9x, 2.x)
    data RSS
     = RSS
         { rssVersion :: String
         , rssAttrs   :: [XML.Attr]
         , rssChannel :: RSSChannel
         , rssOther   :: [XML.Element]
         }
         deriving (Show)

    type URLString  = String
    -- | RFC 822 conforming.
    type DateString = String

    data RSSChannel
     = RSSChannel
         { rssTitle        :: String
         , rssLink         :: URLString
         , rssDescription  :: String
         , rssItems        :: [RSSItem]
         , rssLanguage     :: Maybe String
         , rssCopyright    :: Maybe String
         , rssEditor       :: Maybe String
         , rssWebMaster    :: Maybe String
         , rssPubDate      :: Maybe DateString  -- ^ rfc 822 conforming.
         , rssLastUpdate   :: Maybe DateString  -- ^ rfc 822 conforming.
         , rssCategories   :: [RSSCategory]
         , rssGenerator    :: Maybe String
         , rssDocs         :: Maybe URLString
         , rssCloud        :: Maybe RSSCloud
         , rssTTL          :: Maybe Integer
         , rssImage        :: Maybe RSSImage
         , rssRating       :: Maybe String
         , rssTextInput    :: Maybe RSSTextInput
         , rssSkipHours    :: Maybe [Integer]
         , rssSkipDays     :: Maybe [String]
         , rssChannelOther :: [XML.Element]
         }
         deriving (Show)

    data RSSItem
     = RSSItem
         { rssItemTitle        :: Maybe String
         , rssItemLink         :: Maybe URLString
         , rssItemDescription  :: Maybe String     -- ^if not present, the title is. (per spec, at least.)
         , rssItemAuthor       :: Maybe String
         , rssItemCategories   :: [RSSCategory]
         , rssItemComments     :: Maybe URLString
         , rssItemEnclosure    :: Maybe RSSEnclosure
         , rssItemGuid         :: Maybe RSSGuid
         , rssItemPubDate      :: Maybe DateString
         , rssItemSource       :: Maybe RSSSource
         , rssItemAttrs        :: [XML.Attr]
         , rssItemOther        :: [XML.Element]
         }
         deriving (Show)

    data RSSSource
     = RSSSource
         { rssSourceURL    :: URLString
         , rssSourceAttrs  :: [XML.Attr]
         , rssSourceTitle  :: String
         }
         deriving (Show)

    data RSSEnclosure
     = RSSEnclosure
         { rssEnclosureURL     :: URLString
         , rssEnclosureLength  :: Maybe Integer
         , rssEnclosureType    :: String
         , rssEnclosureAttrs   :: [XML.Attr]
         }
         deriving (Show)

    data RSSCategory
     = RSSCategory
         { rssCategoryDomain   :: Maybe String
         , rssCategoryAttrs    :: [XML.Attr]
         , rssCategoryValue    :: String
         }
         deriving (Show)

    data RSSGuid
     = RSSGuid
         { rssGuidPermanentURL :: Maybe Bool
         , rssGuidAttrs        :: [XML.Attr]
         , rssGuidValue        :: String
         }
         deriving (Show)

    data RSSImage
     = RSSImage
         { rssImageURL     :: URLString -- the URL to the image resource.
         , rssImageTitle   :: String
         , rssImageLink    :: URLString -- URL that the image resource should be an href to.
         , rssImageWidth   :: Maybe Integer
         , rssImageHeight  :: Maybe Integer
         , rssImageDesc    :: Maybe String
         , rssImageOther   :: [XML.Element]
         }
         deriving (Show)

    data RSSCloud
     = RSSCloud
         { rssCloudDomain   :: Maybe String
         , rssCloudPort     :: Maybe String -- on purpose (i.e., not an int)
         , rssCloudPath     :: Maybe String
         , rssCloudRegister :: Maybe String
         , rssCloudProtocol :: Maybe String
         , rssCloudAttrs    :: [XML.Attr]
         }
         deriving (Show)

    data RSSTextInput
     = RSSTextInput
         { rssTextInputTitle :: String
         , rssTextInputDesc  :: String
         , rssTextInputName  :: String
         , rssTextInputLink  :: URLString
         , rssTextInputAttrs :: [XML.Attr]
         , rssTextInputOther :: [XML.Element]
         }
         deriving (Show)

    -- * Default Constructors:

    nullRSS :: String -- ^channel title
            -> URLString -- ^channel link
            -> RSS
    nullRSS title link =
      RSS
        { rssVersion = "2.0"
        , rssAttrs   = []
        , rssChannel = nullChannel title link
        , rssOther   = []
        }

    nullChannel :: String -- ^rssTitle
                -> URLString -- ^rssLink
                -> RSSChannel
    nullChannel title link =
      RSSChannel
         { rssTitle        = title
         , rssLink         = link
         , rssDescription  = title
         , rssItems        = []
         , rssLanguage     = Nothing
         , rssCopyright    = Nothing
         , rssEditor       = Nothing
         , rssWebMaster    = Nothing
         , rssPubDate      = Nothing
         , rssLastUpdate   = Nothing
         , rssCategories   = []
         , rssGenerator    = Nothing
         , rssDocs         = Nothing
         , rssCloud        = Nothing
         , rssTTL          = Nothing
         , rssImage        = Nothing
         , rssRating       = Nothing
         , rssTextInput    = Nothing
         , rssSkipHours    = Nothing
         , rssSkipDays     = Nothing
         , rssChannelOther = []
         }

    nullItem :: String -- ^title
             -> RSSItem
    nullItem title =
       RSSItem
         { rssItemTitle        = Just title
         , rssItemLink         = Nothing
         , rssItemDescription  = Nothing
         , rssItemAuthor       = Nothing
         , rssItemCategories   = []
         , rssItemComments     = Nothing
         , rssItemEnclosure    = Nothing
         , rssItemGuid         = Nothing
         , rssItemPubDate      = Nothing
         , rssItemSource       = Nothing
         , rssItemAttrs        = []
         , rssItemOther        = []
         }

    nullSource :: URLString -- ^source URL
               -> String    -- ^title
               -> RSSSource
    nullSource url title =
      RSSSource
         { rssSourceURL    = url
         , rssSourceAttrs  = []
         , rssSourceTitle  = title
         }

    nullEnclosure :: URLString     -- ^enclosure URL
                  -> Maybe Integer -- ^enclosure length
                  -> String        -- ^enclosure type
                  -> RSSEnclosure
    nullEnclosure url mb_len ty =
      RSSEnclosure
         { rssEnclosureURL     = url
         , rssEnclosureLength  = mb_len
         , rssEnclosureType    = ty
         , rssEnclosureAttrs   = []
         }

    newCategory :: String  -- ^category Value
                -> RSSCategory
    newCategory nm =
      RSSCategory
         { rssCategoryDomain   = Nothing
         , rssCategoryAttrs    = []
         , rssCategoryValue    = nm
         }

    nullGuid :: String -- ^guid value
             -> RSSGuid
    nullGuid v =
      RSSGuid
         { rssGuidPermanentURL = Nothing
         , rssGuidAttrs        = []
         , rssGuidValue        = v
         }

    nullPermaGuid :: String -- ^guid value
                  -> RSSGuid
    nullPermaGuid v = (nullGuid v){rssGuidPermanentURL=Just True}

    nullImage :: URLString -- ^imageURL
              -> String    -- ^imageTitle
              -> URLString -- ^imageLink
              -> RSSImage
    nullImage url title link =
      RSSImage
         { rssImageURL     = url
         , rssImageTitle   = title
         , rssImageLink    = link
         , rssImageWidth   = Nothing
         , rssImageHeight  = Nothing
         , rssImageDesc    = Nothing
         , rssImageOther   = []
         }

    nullCloud :: RSSCloud
    nullCloud =
      RSSCloud
         { rssCloudDomain   = Nothing
         , rssCloudPort     = Nothing
         , rssCloudPath     = Nothing
         , rssCloudRegister = Nothing
         , rssCloudProtocol = Nothing
         , rssCloudAttrs    = []
         }

    nullTextInput :: String    -- ^inputTitle
                  -> String    -- ^inputName
                  -> URLString -- ^inputLink
                  -> RSSTextInput
    nullTextInput title nm link =
      RSSTextInput
         { rssTextInputTitle = title
         , rssTextInputDesc  = title
         , rssTextInputName  = nm
         , rssTextInputLink  = link
         , rssTextInputAttrs = []
         , rssTextInputOther = []
         }