/*   **********************************************************************  **
 **   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.dao.feedparser;

import net.sourceforge.rssowl.dao.NewsfeedFactoryException;
import net.sourceforge.rssowl.model.Channel;
import net.sourceforge.rssowl.model.NewsItem;
import net.sourceforge.rssowl.util.shop.StringShop;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.Text;

import java.util.Iterator;
import java.util.List;

/**
 * Parser for the OPML 1.0 Format <br />
 * Specification: http://www.opml.org/spec
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class OPML_1_0_Parser extends AbstractFeedParser {

  /**
   * Instantiate a new Parser for this format.
   * 
   * @param document The document containing the data to parse
   * @param rssChannel The Channel to fill with data from the document
   * @param url The URL of the Newsfeed that is parsed
   * @param nameSpaces Possible Namespaces of the XML document
   * @throws NewsfeedFactoryException If any error occurs
   */
  protected OPML_1_0_Parser(Document document, Channel rssChannel, String url, Namespace[] nameSpaces) throws NewsfeedFactoryException {
    super(document, rssChannel, url, nameSpaces);
  }

  /**
   * Parse the Body element
   * 
   * @param body The Body element
   */
  private void parseBody(Element body) {

    /** Get the Channel Newsitems */
    List items = getChildren(body, "outline");

    Iterator itemsIt = items.iterator();

    /** For each outline */
    while (itemsIt.hasNext()) {
      Element item = (Element) itemsIt.next();
      parseOutline(item);
    }
  }

  /**
   * Parse the Head Element
   * 
   * @param head The Head element
   */
  private void parseHead(Element head) {

    /** Temp String */
    String str;

    /** Title of channel */
    str = getChildValue("title", head);
    if (StringShop.isset(str))
      rssChannel.setTitle(Text.normalizeString(str));

    /** Creation Date */
    str = getChildValue("dateCreated", head);
    if (StringShop.isset(str))
      rssChannel.setPubDate(str);

    /** Date Modified */
    str = getChildValue("dateModified", head);
    if (StringShop.isset(str))
      rssChannel.setLastBuildDate(str);

    /** Owner Name */
    str = getChildValue("ownerName", head);
    if (StringShop.isset(str))
      rssChannel.setManagingEditor(str);
  }

  /**
   * Recursivly parse Outline Elements
   * 
   * @param outline The Outline element to parse
   */
  private void parseOutline(Element outline) {

    /** Temp String */
    String str;

    /** Treat outline as Newsitem */
    NewsItem newsItem = new NewsItem();

    /** Title of NewsItem */
    str = getAttributeValue(outline, "title");
    if (StringShop.isset(str))
      newsItem.setTitle(str);

    /** Link of NewsItem (using url element) */
    str = getAttributeValue(outline, "url");
    if (StringShop.isset(str))
      newsItem.setLink(str);

    /** Link of NewsItem (using htmlUrl element) */
    if (!StringShop.isset(newsItem.getLink())) {
      str = getAttributeValue(outline, "htmlUrl");
      if (StringShop.isset(str))
        newsItem.setLink(str);
    }

    /** Link of Newsfeed */
    str = getAttributeValue(outline, "xmlUrl");
    if (StringShop.isset(str)) {
      newsItem.setOrigurl(str);
      newsItem.setSource(str);
    }

    /** Description of NewsItem (using text element) */
    str = getAttributeValue(outline, "text");
    if (StringShop.isset(str))
      newsItem.setDescription(str);

    /** Description of NewsItem (using description element) */
    str = getAttributeValue(outline, "description");
    if (StringShop.isset(str))
      newsItem.setDescription(str);

    /** Set part of description as title if title is not available */
    if (!StringShop.isset(newsItem.getTitle()) && newsItem.getDescription() != null)
      newsItem.setTitle(newsItem.getDescription(), true);

    /** Set part of Link as Title if Title is not set */
    if (!StringShop.isset(newsItem.getTitle()) && StringShop.isset(newsItem.getLink()))
      newsItem.setTitle(newsItem.getLink(), true);

    /** Add NewsItem to Channel if it got a Title */
    if (StringShop.isset(newsItem.getTitle()))
      rssChannel.insertItem(newsItem);

    /** Check for outlines as child element */
    List items = getChildren(outline, "outline");

    Iterator itemsIt = items.iterator();

    /** For each outline (recursivly parse) */
    while (itemsIt.hasNext()) {
      Element item = (Element) itemsIt.next();
      parseOutline(item);
    }
  }

  /**
   * @see net.sourceforge.rssowl.dao.feedparser.AbstractFeedParser#parse()
   */
  protected void parse() throws NewsfeedFactoryException {

    /** Get Head Element */
    Element head = getChildElement(root, "head");

    /** Parse Head Element */
    if (head != null)
      parseHead(head);

    /** Get the Body Element */
    Element body = getChildElement(root, "body");

    /** Parse Body Element */
    if (body != null)
      parseBody(body);

    /** Body Element is mandatory */
    else
      throw new NewsfeedFactoryException(url, null, null, NewsfeedFactoryException.ERROR_INVALID_NEWSFEED);
  }
}