--------------------------------------------------------------------
-- |
-- 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
  ( RSS(..)
  , URLString
  , DateString
  , RSSChannel(..)
  , RSSItem(..)
  , RSSSource(..)
  , RSSEnclosure(..)
  , RSSCategory(..)
  , RSSGuid(..)
  , RSSImage(..)
  , RSSCloud(..)
  , RSSTextInput(..)
  , nullRSS
  , nullChannel
  , nullItem
  , nullSource
  , nullEnclosure
  , newCategory
  , nullGuid
  , nullPermaGuid
  , nullImage
  , nullCloud
  , nullTextInput
  ) where

import Prelude.Compat

import Data.Text (Text)
import Data.XML.Compat
import Data.XML.Types as XML

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

type URLString = Text

-- | RFC 822 conforming.
type DateString = Text

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

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

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

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

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

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

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

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

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

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

nullChannel ::
     Text -- ^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 ::
     Text -- ^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
  -> Text -- ^title
  -> RSSSource
nullSource url title = RSSSource {rssSourceURL = url, rssSourceAttrs = [], rssSourceTitle = title}

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

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

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

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

nullImage ::
     URLString -- ^imageURL
  -> Text -- ^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
    , rssCloudRegisterProcedure = Nothing
    , rssCloudProtocol = Nothing
    , rssCloudAttrs = []
    }

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