--------------------------------------------------------------------
-- |
-- Module    : Text.RSS1.Import
-- Copyright : (c) Galois, Inc. 2008,
--             (c) Sigbjorn Finne 2009-
-- License   : BSD3
--
-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
-- Stability : provisional
-- Portability: portable
--
--------------------------------------------------------------------

module Text.RSS1.Import (elementToFeed) where

import Text.RSS1.Syntax
import Text.RSS1.Utils
import Text.XML.Light      as XML
import Text.DublinCore.Types

import Data.Maybe (mapMaybe, fromMaybe)
import Control.Monad (guard,mplus)

---
elementToFeed :: XML.Element -> Maybe Feed
elementToFeed e = do
  guard (elName e == rdfName "RDF")
  ver <- pAttr (Nothing,Nothing) "xmlns" e `mplus` rss10NS
  ch  <- pNode "channel" e    >>= elementToChannel
  let mbImg = pNode "image" e >>= elementToImage
  let is  = fromMaybe [] $ fmap elementToItems $ pNode "items"   e
  let mbTI = pNode "textinput" e >>= elementToTextInput
  let ch1 = ch{channelItemURIs = is}
  let its = pMany (rss10NS,Nothing) "item" elementToItem e

  let es_rest = removeKnownElts e
  let as_rest = removeKnownAttrs e
  return Feed
    { feedVersion   = ver
    , feedChannel   = ch1
    , feedImage     = mbImg
    , feedItems     = its
    , feedTextInput = mbTI
    , feedTopics    = mapMaybe elementToTaxonomyTopic $ pQNodes (qualName (taxNS,taxPrefix) "topic") e
    , feedOther     = es_rest
    , feedAttrs     = as_rest
    }

elementToItems :: XML.Element -> [URIString]
elementToItems e = seqLeaves e

elementToTextInput :: XML.Element -> Maybe TextInputInfo
elementToTextInput e = do
  let es = children e
  uri <- pAttr (rdfNS,rdfPrefix) "about" e
  ti  <- pQLeaf (rss10NS,Nothing) "title" e
  desc <- pQLeaf (rss10NS,Nothing) "description" e
  na  <- pQLeaf (rss10NS,Nothing) "name" e
  li  <- pQLeaf (rss10NS,Nothing) "link" e
  let dcs = mapMaybe elementToDC es
  return $ TextInputInfo
    { textInputURI = uri
    , textInputTitle = ti
    , textInputDesc  = desc
    , textInputName  = na
    , textInputLink  = li
    , textInputDC    = dcs
    , textInputOther = es
    , textInputAttrs = elAttribs e
    }

elementToItem :: XML.Element -> Maybe Item
elementToItem e = do
  guard (elName e == qualName (rss10NS,Nothing) "item")
  let es = children e
  uri <- pAttr (rdfNS,rdfPrefix) "about" e
  ti  <- pQLeaf (rss10NS,Nothing) "title" e
  li  <- pQLeaf (rss10NS,Nothing) "link" e
  let desc= pQLeaf (rss10NS,Nothing) "description" e
  let dcs = mapMaybe elementToDC es
  let tos = fromMaybe [] (fmap bagLeaves $ pQNode (qualName (taxNS,taxPrefix) "topics") e)
  let cs  = mapMaybe elementToContent es
  let es_other = removeKnownElts e
  let as_other = removeKnownAttrs e
  return Item
    { itemURI     = uri
    , itemTitle   = ti
    , itemLink    = li
    , itemDesc    = desc
    , itemDC      = dcs
    , itemTopics  = tos
    , itemContent = cs
    , itemOther   = es_other
    , itemAttrs   = as_other
    }

elementToImage :: XML.Element -> Maybe Image
elementToImage e = do
  let es = children e
  let as = elAttribs e
  uri <- pAttr (rdfNS,rdfPrefix) "about" e
  ti  <- pLeaf "title" e
  ur  <- pLeaf "url" e
  li  <- pLeaf "link" e
  let dcs = mapMaybe elementToDC es
  return Image
    { imageURI   = uri
    , imageTitle = ti
    , imageURL   = ur
    , imageLink  = li
    , imageDC    = dcs
    , imageOther = es
    , imageAttrs = as
    }

elementToChannel :: XML.Element -> Maybe Channel
elementToChannel e = do
  let es = children e
  uri <- pAttr (rdfNS,rdfPrefix) "about" e
  ti  <- pLeaf "title" e
  li  <- pLeaf "link"  e
  de  <- pLeaf "description" e
  let mbImg = pLeaf "image" e
  let is =
       case fmap seqLeaves $ pNode "items" e of
         Nothing -> []
         Just ss -> ss
  let tinp     = pLeaf "textinput" e
  let dcs      = mapMaybe elementToDC es
  let tos = fromMaybe [] (fmap bagLeaves $ pQNode (qualName (taxNS,taxPrefix) "topics") e)
  let cs  = mapMaybe elementToContent es
  let es_other = removeKnownElts e
  let as_other = removeKnownAttrs e
  let def_chan =
        Channel
          { channelURI          = uri
          , channelTitle        = ti
          , channelLink         = li
          , channelDesc         = de
          , channelImageURI     = mbImg
          , channelItemURIs     = is
          , channelTextInputURI = tinp
          , channelDC           = dcs
          , channelUpdatePeriod = Nothing
          , channelUpdateFreq   = Nothing
          , channelUpdateBase   = Nothing
          , channelContent      = cs
          , channelTopics       = tos
          , channelOther        = es_other
          , channelAttrs        = as_other
          }
  return (addSyndication e def_chan)

addSyndication :: XML.Element -> Channel -> Channel
addSyndication e ch =
  ch{ channelUpdatePeriod = fmap toUpdatePeriod $ pQLeaf (synNS,synPrefix) "updatePeriod" e
    , channelUpdateFreq   = fmap read $ pQLeaf (synNS,synPrefix) "updateFrequency" e
    , channelUpdateBase   = pQLeaf (synNS,synPrefix) "updateBase" e
    }
 where
  toUpdatePeriod x =
    case x of
      "hourly"  -> Update_Hourly
      "daily"   -> Update_Daily
      "weekly"  -> Update_Weekly
      "monthly" -> Update_Monthly
      "yearly"  -> Update_Yearly
      _         -> Update_Hourly -- ToDo: whine


elementToDC :: XML.Element -> Maybe DCItem
elementToDC e = do
  guard (qURI (elName e) == dcNS)
  let dcItem x = DCItem{dcElt=x,dcText=strContent e}
  return $ dcItem $
   case qName $ elName e of
     "title"       -> DC_Title
     "creator"     -> DC_Creator
     "subject"     -> DC_Subject
     "description" -> DC_Description
     "publisher"   -> DC_Publisher
     "contributor" -> DC_Contributor
     "date"        -> DC_Date
     "type"        -> DC_Type
     "format"      -> DC_Format
     "identifier"  -> DC_Identifier
     "source"      -> DC_Source
     "language"    -> DC_Language
     "relation"    -> DC_Relation
     "coverage"    -> DC_Coverage
     "rights"      -> DC_Rights
     oth           -> DC_Other oth

elementToTaxonomyTopic :: XML.Element -> Maybe TaxonomyTopic
elementToTaxonomyTopic e = do
  guard (elName e == qualName (taxNS,taxPrefix) "topic")
  let es = children e
  uri <- pAttr (rdfNS,rdfPrefix) "about" e
  li <- pQLeaf (taxNS,taxPrefix) "link" e
  return TaxonomyTopic
    { taxonomyURI    = uri
    , taxonomyLink   = li
    , taxonomyTitle  = pLeaf "title" e
    , taxonomyDesc   = pLeaf "description" e
    , taxonomyTopics = fromMaybe [] (fmap bagLeaves $ pQNode (qualName (taxNS,taxPrefix) "topics") e)
    , taxonomyDC     = mapMaybe elementToDC es
    , taxonomyOther  = es
    }

elementToContent :: XML.Element -> Maybe ContentInfo
elementToContent e = do
  guard (elName e == qualName (conNS,conPrefix) "items")
  return ContentInfo
    { contentURI      = pAttr (rdfNS,rdfPrefix) "about" e
    , contentFormat   = pQLeaf (conNS,conPrefix) "format" e
    , contentEncoding = pQLeaf (conNS,conPrefix) "encoding" e
    , contentValue    = pQLeaf (rdfNS,rdfPrefix) "value" e
    }

bagLeaves :: XML.Element -> [URIString]
bagLeaves be =
  mapMaybe
    (\ e -> do
      guard (elName e == qualName (rdfNS,rdfPrefix) "li")
      pAttr (rdfNS,rdfPrefix) "resource" e `mplus`
        fmap strContent (pQNode (qualName (rdfNS,rdfPrefix) "li") e))
    (fromMaybe [] $ fmap children $ pQNode (qualName (rdfNS,rdfPrefix) "Bag") be)

{-
bagElements :: XML.Element -> [XML.Element]
bagElements be =
  mapMaybe
    (\ e -> do
      guard (elName e == rdfName "li")
      return e)
    (fromMaybe [] $ fmap children $ pQNode (rdfName "Bag") be)
-}

seqLeaves :: XML.Element -> [URIString]
seqLeaves se =
  mapMaybe
    (\ e -> do
      guard (elName e == rdfName "li")
      return (strContent e))
    (fromMaybe [] $ fmap children $ pQNode (rdfName "Seq") se)