/*
 * Copyright (C) 2003-2009 eXo Platform SAS.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see<http://www.gnu.org/licenses/>.
 */
package org.exoplatform.forum.rss;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.exoplatform.container.PortalContainer;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.w3c.dom.Document;

import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.SyndFeedOutput;

public class RSS {
  private static final Log LOG = ExoLogger.getLogger(RSS.class);
  protected static final String CONTENT_PROPERTY = "exo:content".intern();
  protected static final String RSS_NODE_NAME = "ks.rss".intern();  
  protected static final String RSS_2_0 = "rss_2.0".intern();
  public static final String PLAIN_TEXT = "text/plain".intern();
  public static final String DEFAULT_FEED_LINK = "http://www.exoplatform.com".intern();

  
  private String fileName ;
  private Node itemNode;
  
  public RSS(Node node) {
    itemNode = node;
  }
  
  public static String getRSSLink(String appType, String portalName, String objectId){
    return "/" + PortalContainer.getInstance().getRestContextName() + "/ks/" + appType + "/rss/" + objectId;   
  }
  
  
  public static String getUserRSSLink(String apptype, String userId) {
    return "/" + PortalContainer.getInstance().getRestContextName() +  "/ks/" + apptype + "/rss/user/"+userId;
  }
  
  public String getFileName() {
    return fileName;
  }
  public void setFileName(String fileName) {
    this.fileName = fileName;
  }
  
  public InputStream getContent() {
    try {
      return getFeedNode().getProperty(CONTENT_PROPERTY).getValue().getStream();
    } catch (Exception e) {
      throw new RuntimeException("Failed to get feed content ", e);
    }

  }
  
  public void setContent(InputStream is) {
    try {
      getFeedNode().setProperty(CONTENT_PROPERTY, is);
    } catch (Exception e) {
      throw new RuntimeException("Failed to get feed content ", e);
    }

  }

  private Node getFeedNode() throws Exception {
//    System.out.println("\n\n itemNode: " + itemNode.getPath());
    try {
      return itemNode.getNode(RSS_NODE_NAME);
    } catch (Exception e) {
      return itemNode.addNode(RSS_NODE_NAME, "exo:forumRSS");
//      throw new RuntimeException("Failed to get feed node", e);
    }
  }

  /**
   * Read a SyndFeed from the
   * @return
   */
  public SyndFeed read() {
    try {
    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
    InputStream inputStream = getContent();
    Document doc = docBuilder.parse(inputStream);
    doc.getDocumentElement().normalize();

//    SyndFeedInput input = new SyndFeedInput();
//    SyndFeed feed = input.build(doc);
    return null;
    }
    catch (Exception e) {
      LOG.error("Failed to read RSS feed");
      throw new RuntimeException(e);
    }
  }
  
  /**
   * Remove an item for the feed
   * @param uri
   * @return
   */
  @SuppressWarnings("unchecked")
  public SyndFeed removeEntry(String uri) {
    SyndFeed feed = read();
    List<SyndEntry> entries = feed.getEntries();
    if(uri != null && uri.trim().length() > 0){
      for(SyndEntry syndEntry : entries){
        if(syndEntry.getUri().equals(uri)){
          entries.remove(syndEntry);
          break;
        }
      }
    }
    feed.setEntries(entries);
    return feed;
  }
  
  /**
   * Adds an entry to the feed
   * @param newEntry
   * @return
   */
  @SuppressWarnings("unchecked")
  public SyndFeed addEntry(SyndEntry newEntry) {
    SyndFeed feed = read();
    List<SyndEntry> entries = feed.getEntries();
    if (newEntry != null)
      entries.add(0, newEntry);
    feed.setEntries(entries);
    return feed;
  }
  

  public void saveFeed(SyndFeed feed, String rssNodeType) {
    try {
      boolean isNew = false;
      try {
        itemNode.getNode(RSS_NODE_NAME);
      } catch (PathNotFoundException pnfe) {
        LOG.debug("Feed node not found for " + itemNode.getName() + " creating...");
        itemNode.addNode(RSS_NODE_NAME, rssNodeType);
        isNew = true;
      }
      
      SyndFeedOutput output = new SyndFeedOutput();
      setContent(new ByteArrayInputStream(output.outputString(feed).getBytes()));

      if (isNew)
        itemNode.getSession().save();
      else
        itemNode.save();
    } catch (Exception e) {
      LOG.error("Failed to save feed content", e);
    }
  }



  public boolean feedExists() {
    try {
      return itemNode.hasNode(RSS_NODE_NAME);
    } catch (Exception e) {
      return false;
    }
  }
  
  
  /**
   * Create a new feed with some default content: link is the link to eXo web site
   * and feed type is <code>rss_2.0</code>
   * @return
   */
  public static SyndFeed createNewFeed(String title, Date pubDate){
    SyndFeed feed = new SyndFeedImpl();
    feed.setLink(DEFAULT_FEED_LINK);
    feed.setFeedType(RSS_2_0);
    feed.setTitle(title);
    feed.setPublishedDate(pubDate);
    feed.setDescription(" ");
    return feed;
  }
  
  /**
   * Create new entry
   * @param uri         uri of item
   * @param title       title of item
   * @param link        link to this item 
   * @param listContent the content of item
   * @param description the description for this item
   * @return  SyndEntry
   */
  public static SyndEntry createNewEntry(String uri, String title, String link, List<String> listContent, SyndContent description, Date pubDate, String author){
    SyndEntry entry = new SyndEntryImpl();
    entry.setUri(uri);
    entry.setTitle(title);
    entry.setLink(link + uri);
    entry.setContributors(listContent);
    entry.setDescription(description);
    entry.setPublishedDate(pubDate);
    entry.setAuthor(author);
    return entry;
  }

  public Node getItemNode() {
    return itemNode;
  }

  public void setItemNode(Node itemNode) {
    try {
      Node rssNode = itemNode.getNode(RSS_NODE_NAME);
      if (rssNode.hasProperty(CONTENT_PROPERTY)) {
        setContent(rssNode.getProperty(CONTENT_PROPERTY).getValue().getStream());
      } else {
        throw new IllegalArgumentException("Node does not have an RSS feed child");
      }
    } catch (Exception e) {
      throw new RuntimeException("Failed to set item node for RSS", e);
    }
    this.itemNode = itemNode;
  }
  
}
