/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2003-2006 RSSOwl Development Team                                  **
 **   http://www.rssowl.org/                                                 **
 **                                                                          **
 **   All rights reserved                                                    **
 **                                                                          **
 **   This program and the accompanying materials are made available under   **
 **   the terms of the Eclipse Public License 1.0 which accompanies this     **
 **   distribution, and is available at:                                     **
 **   http://www.rssowl.org/legal/epl-v10.html                               **
 **                                                                          **
 **   A copy is found in the file epl-v10.html and important notices to the  **
 **   license from the team is found in the textfile LICENSE.txt distributed **
 **   in this package.                                                       **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Contributors:                                                          **
 **     RSSOwl - initial API and implementation (bpasero@rssowl.org)         **
 **                                                                          **
 **  **********************************************************************  */

package net.sourceforge.rssowl.util.archive;

import net.sourceforge.rssowl.model.NewsItem;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * The Archive stores all archive items in a Hashtable. Each archive item can be
 * found through the feedurl in the Hashtable.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class Archive {
  private ArchiveManager archiveManager;
  private Hashtable items;

  /**
   * Instantiate a new Archive
   * 
   * @param archiveManager The archive manager
   */
  public Archive(ArchiveManager archiveManager) {
    this.archiveManager = archiveManager;
    items = new Hashtable();
  }

  /**
   * Add an entry to the ArchiveItem that is connected to the feedurl of the
   * given NewsItem.
   * 
   * @param rssNewsItem Get feedurl, newsurl, newstitle and newsdate from this
   * object to add a new entry.
   */
  public void addEntry(NewsItem rssNewsItem) {

    /** Newsitem must not be null */
    if (rssNewsItem == null)
      return;

    /** Feed URL */
    String feedurl = rssNewsItem.getSafeXMLFeedUrl();
    if (feedurl == null)
      feedurl = "NULL";

    /** News Title */
    String newstitle = "NULL";
    if (rssNewsItem.getTitle() != null)
      newstitle = rssNewsItem.getTitle();

    /** News URL */
    String newsurl = "NULL";
    if (rssNewsItem.getLink() != null)
      newsurl = rssNewsItem.getLink();
    else if (rssNewsItem.getGuid() != null)
      newsurl = rssNewsItem.getGuid();

    /** News Date */
    String newsdate = "NULL";
    if (rssNewsItem.getPubDate() != null)
      newsdate = rssNewsItem.getPubDate();

    /** Add this entry */
    addEntry(feedurl, newstitle, newsurl, newsdate);
  }

  /**
   * Add an entry to the ArchiveItem that is connected to the feedurl.
   * 
   * @param feedurl The url of the feed
   * @param newstitle The title of the news
   * @param newsurl The url of the news
   * @param newsdate The publish date of the news
   */
  public void addEntry(String feedurl, String newstitle, String newsurl, String newsdate) {
    ArchiveItem item;

    /** Get the archive item from the archiv if existing */
    if (items.containsKey(feedurl)) {
      item = getItem(feedurl);
    }

    /** Create a new archive item and add to the archive */
    else {
      item = new ArchiveItem(feedurl);
      addItem(item);
    }

    /** Add this archive entry to the archive item */
    item.addEntry(new ArchiveEntry(newsurl, newstitle, newsdate));
  }

  /**
   * Add an archive item to the archive
   * 
   * @param item An archive item
   */
  public void addItem(ArchiveItem item) {
    items.put(item.getFeedurl(), item);

    /** Sync unique file name with index */
    archiveManager.index.syncFileName(item);
  }

  /**
   * Remove any archive entries from the archive item, that are not part of the
   * given news items. This is a simple clean up, which prevents the files of
   * the archive from getting big.
   * 
   * @param feedurl The URL of the feed
   * @param newsItems A Hashtable with all newsitems
   */
  public void cleanUpItem(String feedurl, Hashtable newsItems) {

    /** Return if there is no archive item for the feedurl */
    if (!items.containsKey(feedurl))
      return;

    /** Get the item to clean it up */
    ArchiveItem item = (ArchiveItem) items.get(feedurl);

    ArrayList newsItemsIDs = new ArrayList();
    ArrayList toDelete = new ArrayList();

    /** Add each news from the newsitems to the "newsItemsIDs" Vector */
    Enumeration elements = newsItems.elements();
    while (elements.hasMoreElements()) {
      NewsItem newsItem = (NewsItem) elements.nextElement();
      String newsTitle = newsItem.getTitle();
      String newsUrl = (newsItem.getLink() != null) ? newsItem.getLink() : newsItem.getGuid();
      String newsPubDate = newsItem.getPubDate();

      /** Add to newsitems IDs */
      newsItemsIDs.add(ArchiveEntry.toID(newsTitle, newsUrl, newsPubDate));
    }

    /** Add each news that is not part of the newsitems to the "toDelete" Vector */
    Enumeration entries = item.getEntries().elements();
    while (entries.hasMoreElements()) {
      ArchiveEntry entry = (ArchiveEntry) entries.nextElement();
      if (!newsItemsIDs.contains(entry.toID()))
        toDelete.add(entry);
    }

    /** Delete all entries that are stored in the "toDelete" Vector */
    for (int a = 0; a < toDelete.size(); a++)
      item.removeEntry((ArchiveEntry) toDelete.get(a));
  }

  /**
   * Get an archive item from the archive
   * 
   * @param feedurl The url of the feed
   * @return ArchiveItem The archive item
   */
  public ArchiveItem getItem(String feedurl) {
    return (ArchiveItem) items.get(feedurl);
  }

  /**
   * Get the Archiveitems of this Archive.
   * 
   * @return Hashtable The Archiveitems of this Archive.
   */
  public Hashtable getItems() {
    return items;
  }

  /**
   * Check if the given newsitem is read or not. This is simply done by
   * checking, if the newsitem exists as entry in the connected archive item.
   * 
   * @param rssNewsItem The selected news
   * @return TRUE if the news was read
   */
  public boolean isNewsRead(NewsItem rssNewsItem) {

    /** Feed URL */
    String feedurl = rssNewsItem.getSafeXMLFeedUrl();
    if (feedurl == null)
      feedurl = "NULL";

    /** News Title */
    String newstitle = "NULL";
    if (rssNewsItem.getTitle() != null)
      newstitle = rssNewsItem.getTitle();

    /** News URL */
    String newsurl = "NULL";
    if (rssNewsItem.getLink() != null)
      newsurl = rssNewsItem.getLink();
    else if (rssNewsItem.getGuid() != null)
      newsurl = rssNewsItem.getGuid();

    /** News Date */
    String newsdate = "NULL";
    if (rssNewsItem.getPubDate() != null)
      newsdate = rssNewsItem.getPubDate();

    return isNewsRead(feedurl, newstitle, newsurl, newsdate);
  }

  /**
   * Check if the given newsitem is read or not. This is simply done by
   * checking, if the newsitem exists as entry in the connected archive item.
   * 
   * @param feedurl URL of the feed
   * @param newstitle Title of the news
   * @param newsurl URL of the news
   * @param newsdate The publish date of the news
   * @return TRUE if the news was read
   */
  public boolean isNewsRead(String feedurl, String newstitle, String newsurl, String newsdate) {

    /** If no archive item exists for the URL, return "unread" */
    if (!items.containsKey(feedurl))
      return false;

    /** Get the item that is connected to the feedurl */
    ArchiveItem item = getItem(feedurl);

    /** Ask the item if news is read */
    return item.isNewsRead(newstitle, newsurl, newsdate);
  }

  /**
   * Remove an archive entry from an archive item.
   * 
   * @param rssNewsItem The selected newsitem
   */
  public void removeEntry(NewsItem rssNewsItem) {

    /** Something went wrong, return */
    if (rssNewsItem == null)
      return;

    /** Feed URL */
    String feedurl = rssNewsItem.getSafeXMLFeedUrl();
    if (feedurl == null)
      feedurl = "NULL";

    /** News Title */
    String newstitle = "NULL";
    if (rssNewsItem.getTitle() != null)
      newstitle = rssNewsItem.getTitle();

    /** News URL */
    String newsurl = "NULL";
    if (rssNewsItem.getLink() != null)
      newsurl = rssNewsItem.getLink();
    else if (rssNewsItem.getGuid() != null)
      newsurl = rssNewsItem.getGuid();

    /** News Date */
    String newsdate = "NULL";
    if (rssNewsItem.getPubDate() != null)
      newsdate = rssNewsItem.getPubDate();

    removeEntry(feedurl, newstitle, newsurl, newsdate);
  }

  /**
   * Remove an archive entry from an archive item.
   * 
   * @param feedurl URL of the feed
   * @param newstitle Title of the news
   * @param newsurl URL of the news
   * @param newsdate The publish date of the news
   */
  public void removeEntry(String feedurl, String newstitle, String newsurl, String newsdate) {

    /** Remove entry if the item exists */
    if (items.containsKey(feedurl)) {
      ArchiveItem item = (ArchiveItem) items.get(feedurl);
      item.removeEntry(newstitle, newsurl, newsdate);
    }
  }

  /**
   * @see java.lang.Object#toString()
   */
  public String toString() {
    StringBuffer strBuf = new StringBuffer("");
    Enumeration keys = items.keys();
    while (keys.hasMoreElements()) {
      strBuf.append(items.get(keys.nextElement()));
    }
    return new String(strBuf);
  }
}