/*   **********************************************************************  **
 **   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.controller.thread;

import net.sourceforge.rssowl.controller.GUI;
import net.sourceforge.rssowl.model.NewsItem;
import net.sourceforge.rssowl.util.GlobalSettings;
import net.sourceforge.rssowl.util.shop.FileShop;
import net.sourceforge.rssowl.util.shop.URLShop;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * This class is used to implement AmphetaRate functionality to RSSOwl. A
 * running thread submits ratings (connects to an URL for each rating) every 15
 * minutes. The ratings are stored in a Hashtable. The user may rate each news
 * from a newsfeed. Possible ratings are given throught the constants Wow!, Good
 * and Crap.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class AmphetaRateThread extends Thread {

  /** Rate-level: Bad */
  public static final int RATE_BAD = 2;

  /** Rate-level: Fantastic */
  public static final int RATE_FANTASTIC = 10;

  /** Rate-level: Good */
  public static final int RATE_GOOD = 8;

  /** Rate-level: Moderate */
  public static final int RATE_MODERATE = 5;

  /** Rate-level: Very Bad */
  public static final int RATE_VERY_BAD = 0;

  /** Store the news that have been rated in this session */
  public static Hashtable ratedNews = new Hashtable();

  /** Server status code for a successfull submission of a rating */
  public static final String STATUS_OK = "OK";

  /** Tell that RSSOwl querrys AmphetaRate */
  private static final String PARAM_CLIENT = "&client=rssowl";

  /** Tell that the recommendation articles should not be formatted with HTML */
  private static final String PARAM_HTML = "&html=0";

  /** Tell that we dont want the feed link in the description */
  private static final String PARAM_LINKINDESC = "&linkindesc=0";

  /** Tell that we need the origurl-tag in the recommendations */
  private static final String PARAM_ORIGURL = "&origurltag=1";

  /** Complete list of parameters as we want AmphetaRate to behave */
  public static final String PARAM_LIST = PARAM_CLIENT + PARAM_HTML + PARAM_ORIGURL + PARAM_LINKINDESC + "&appname=RSSOwl" + UpdateManager.MAJOR_VERSION;

  /** Holds all not yet submitted ratings */
  private static final Hashtable ratings = new Hashtable();

  /** Server status code for an erroneous submission of a rating */
  private static final String STATUS_ERROR = "error! abort!";

  /** Interval for the thread to submit the collected ratings */
  private static final int SUBMIT_INTERVAL = 15 * 60 * 1000;

  /** Flag indicates that the thread is currently submitting ratings */
  private boolean isSubmitting;

  /** Flag indicates that the thread was not stopped yet */
  private boolean keepRunning;

  /**
   * Instantiate a new AmphetaRateThread
   */
  public AmphetaRateThread() {
    setName("AmphetaRate Submission Thread");
    keepRunning = true;
    isSubmitting = false;
    setDaemon(true);
  }

  /**
   * Get all ratings
   * 
   * @return Hashtable holding the ratings
   */
  public static Hashtable getRatings() {
    return ratings;
  }

  /**
   * Get the translated rating level for the giving level
   * 
   * @param rateLevel The level of the rating
   * @return String The translated level for the given level
   */
  public static String getTranslatedRatingLevel(int rateLevel) {
    String rate = GUI.i18n.getTranslation("RATE_MODERATE");

    if (rateLevel == AmphetaRateThread.RATE_FANTASTIC)
      rate = GUI.i18n.getTranslation("RATE_FANTASTIC");
    else if (rateLevel == AmphetaRateThread.RATE_GOOD)
      rate = GUI.i18n.getTranslation("RATE_GOOD");
    else if (rateLevel == AmphetaRateThread.RATE_BAD)
      rate = GUI.i18n.getTranslation("RATE_BAD");
    else if (rateLevel == AmphetaRateThread.RATE_VERY_BAD)
      rate = GUI.i18n.getTranslation("RATE_VERY_BAD");

    return rate;
  }

  /**
   * Get if the user is an old one using the AmphetaRate user id and not the new
   * username alias and password
   * 
   * @return boolean TRUE if AmphetaRate user id is given
   */
  public static boolean isOldUser() {
    return !GlobalSettings.amphetaRateUserID.equals("");
  }

  /**
   * Rate a newsitem from a newschannel
   * 
   * @param rssNewsItem Selected newsitem
   * @param rating either fantastic, good, moderate, bad or very bad
   * @return boolean TRUE if newsitem is a valid item to rate
   */
  public static boolean rate(NewsItem rssNewsItem, int rating) {

    /** Dont rate null newsitems */
    if (rssNewsItem == null)
      return false;

    /** Retrieve AmphetarRate rating URL */
    String amphetaRateURL = rssNewsItem.toAmphetaRateURL();

    /** Informations might not be complete */
    if (amphetaRateURL == null)
      return false;

    /** Store this rating to the ratings hashtable */
    ratings.put(amphetaRateURL, amphetaRateURL + "&rating=" + rating + "&appname=RSSOwl" + UpdateManager.MAJOR_VERSION);

    /** Store this rating to the rated news hashtable */
    ratedNews.put(amphetaRateURL, new Integer(rating));

    /** Successfull rating */
    return true;
  }

  /**
   * Register to AmphetaRate
   * 
   * @param user Desired username
   * @param password Desired password
   * @param oldId Optional oldId
   * @return String An User ID that is 3 digits followed by 3 numbers or an
   * empty String if an warning occured
   * @throws IOException if an error occurs
   */
  public static String register(String user, String password, String oldId) throws IOException {
    return FileShop.getContent(new URL(URLShop.AMPHETARATE_REGISTRATION_URL + "&alias=" + user + "&password=" + password + "&prevuid=" + oldId));
  }

  /**
   * Submits a rating from with connecting to the given URL.
   * 
   * @param url The rating-URL consists of title, newsfeed XML URL, description,
   * newsitem link and the user id.
   * @return TRUE if submit was successfull or the rating URL is malformed.
   * FALSE if the connection could not be established.
   * @throws IOException If an error occurs
   */
  private static boolean submitRating(String url) throws IOException {

    /** Submit rating and retrieve status */
    String status = FileShop.getContent(new URL(url));

    /** Submit was successfull */
    if (status.indexOf(STATUS_OK) >= 0)
      return true;

    /** Malformed URL. Remove it from the submission list */
    else if (status.equalsIgnoreCase(STATUS_ERROR)) {
      GUI.logger.log("AmphetaRate Status: " + status + " (URL: " + url + " / User: " + GlobalSettings.amphetaRateUsername + " / User ID: " + GlobalSettings.amphetaRateUserID + ")");
      return true;
    }

    /** Server was not reachable. Keep rating in submission queue */
    return false;
  }

  /**
   * Will check the ratings Hashtable every 15 minutes and connect to all URLs
   * that are int (= perform the rating). All submitted ratings are deleted from
   * the Hashtable.
   */
  public void run() {
    while (keepRunning) {

      /** Lock this thread */
      isSubmitting = true;

      /** Submit each rating */
      Enumeration keys = ratings.keys();

      while (keys.hasMoreElements()) {
        String key = (String) keys.nextElement();

        try {

          /**
           * Remove rating if submit was successfull or the rating URL is
           * malformed and Thread not yet interrupted.
           */
          if (!isInterrupted() && submitRating((String) ratings.get(key)))
            ratings.remove(key);
        }

        /** Could not connect to the server, break enumeration */
        catch (IOException e) {
          break;
        }
      }

      /** Collect ratings for the next interval */
      try {

        /** Unlock this thread */
        isSubmitting = false;

        /** Sleep some time */
        sleep(SUBMIT_INTERVAL);
      }

      /** Wake up and submit ratings that have not been submitted yet */
      catch (InterruptedException e) {
        // Submit ratings
      }
    }
  }

  /**
   * Stop this Thread
   */
  public void stopThread() {
    keepRunning = false;
    interrupt();
  }

  /**
   * Wake up submit thread
   */
  public void wakeUp() {
    if (!isSubmitting)
      interrupt();
  }
}