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

import net.sourceforge.rssowl.controller.GUI;
import net.sourceforge.rssowl.controller.thread.UpdateManager;
import net.sourceforge.rssowl.dao.ConnectionManager;
import net.sourceforge.rssowl.util.DateParser;
import net.sourceforge.rssowl.util.GlobalSettings;

import org.apache.commons.httpclient.HttpException;
import org.eclipse.swt.SWT;

import com.lowagie.text.html.HtmlEncoder;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Vector;

/**
 * Factory class for some URL concerns in RSSOwl
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class URLShop {

  /** Empty Browser Page */
  public static final String ABOUT_BLANK = "about:blank";

  /** Following this URL a new AmphetaRate User ID is returned */
  public static String AMPHETARATE_REGISTRATION_URL;

  /** The Long Feed Protocol URI Syntax */
  public static final String FEED_PROTOCOL_LONG = "feed://";

  /** The Short Feed Protocol URI Syntax */
  public static final String FEED_PROTOCOL_SHORT = "feed:";

  /** URL for Validating Feeds on W3C */
  public static final String FEED_VALIDATOR_URL = "http://validator.w3.org/feed/check.cgi?url=";

  /** URL to receive newest version changelog */
  public static String RSSOWL_CHANGELOG_URL;

  /** RSSOwl eMail: Contact */
  public static String RSSOWL_CONTACT;

  /** RSSOwl Link: Donation */
  public static String RSSOWL_DONATE;

  /** RSSOwl Link: Download */
  public static String RSSOWL_DOWNLOAD;

  /** RSSOwl Link: FAQ (Newsfeed) */
  public static String RSSOWL_FAQ;

  /** RSSOwl Link: Newsfeed */
  public static String RSSOWL_FEED;

  /** RSSOwl Link: Discussion Forum */
  public static String RSSOWL_FORUM;

  /** RSSOwl Link: Mailinglist */
  public static String RSSOWL_LIST;

  /** RSSOwl Link: Promotion */
  public static String RSSOWL_PROMOTION;

  /** RSSOwl Link: Tutorial */
  public static String RSSOWL_TUTORIAL;

  /** URL to receive newest version information */
  public static String RSSOWL_UPDATE_URL;

  /** RSSOwl Link: Webpage */
  public static String RSSOWL_WEBPAGE;

  /** Common Binary file Extensions */
  private static final String[] BINARY_EXTENSIONS = new String[] { ".jpg", ".gif", ".png", ".bmp", ".pdf", ".doc", ".zip", ".tar", ".gz", ".rar", ".bz", ".ps", ".xls", ".ppt", ".rtf", ".midi", ".wav", ".mp3", ".mov", ".rm", ".swf", ".exe", ".dmg" };

  /** Mail alias of where to send the error report */
  private static final String ERROR_MAIL = "error-report@rssowl.org";

  /** Common Newsfeed Extensions */
  private static final String[] FEED_EXTENSIONS = new String[] { "rss", "rdf", "xml", "atom", "feed" };

  /** Common Newsfeed Extensions with leading Dot */
  private static final String[] FEED_EXTENSIONS_DOTTED = new String[] { ".rss", ".rdf", ".xml", ".atom", ".feed" };

  /** This utility class constructor is hidden */
  private URLShop() {
  // Protect default constructor
  }

  /**
   * Transform the given URL into canonical form.
   * 
   * @param simpleURL The URL to canonicalize
   * @return String canonicalized URL
   */
  public static String canonicalize(String simpleURL) {
    String resultURL = simpleURL;
    if (simpleURL.startsWith("ftp."))
      resultURL = "ftp://" + simpleURL;
    else if (simpleURL.startsWith("gopher."))
      resultURL = "gopher://" + simpleURL;
    else if (simpleURL.charAt(0) == '/')
      resultURL = "file:" + simpleURL;
    else if (!hasProtocolName(simpleURL)) {
      if (isSimpleHostName(simpleURL))
        simpleURL = "www." + simpleURL;
      resultURL = "http://" + simpleURL;
    }
    return resultURL;
  }

  /**
   * Try to crawl any URL from the given WebSite.
   * 
   * @param fromUrl The URL of the WebSite to crawl URLs from.
   * @return Vector A Collection containing all found URLs as Strings.
   * @throws HttpException In case of an error.
   * @throws IOException In case of an error.
   */
  public static Vector crawlUrls(String fromUrl) throws HttpException, IOException {

    /** Create a new ConnectionManager */
    ConnectionManager connectionManager = new ConnectionManager(fromUrl);
    connectionManager.setUserAgent(BrowserShop.getUserAgent());

    /** Connect */
    connectionManager.connect();

    /** Read entire content into a String */
    String result = FileShop.getContent(connectionManager.getInputStream());

    /** Close connection */
    connectionManager.closeConnection();

    /** Search for Links in the result */
    Vector linkList = new Vector();

    /** Grab all links from HTML Tags */
    RegExShop.extractLinksFromHTML(result, linkList);

    /** Grab all links from Text */
    RegExShop.extractLinksFromText(result, linkList);

    return linkList;
  }

  /**
   * Create an error report to be sent as mail
   * 
   * @return String The mailto link for the mail
   */
  public static String createErrorReport() {
    String errorReport = "mailto:" + URLShop.ERROR_MAIL;

    /** Subject */
    String subject = "RSSOwl Error Report (OS: " + SWT.getPlatform() + " RSSOwl " + UpdateManager.getPublicVersion() + " " + DateParser.formatDate() + ")";

    /** Body */
    String body = GUI.i18n.getTranslation("MAIL_ERROR_BODY") + "\nPS: Please use English or German if possible, thanks.";

    /** Create mailto link */
    errorReport += "?body=" + URLShop.mailToUrllEncode(body) + "&subject=" + URLShop.mailToUrllEncode(subject);

    return errorReport;
  }

  /**
   * Build the RSSOwl teaser in a "mailto:" link
   * 
   * @return String The mailto: Link
   */
  public static String createTellMyFriends() {
    String tellMyFriends = "mailto:";

    /** Subject */
    String subject = "RSSOwl - RSS / RDF / Atom Newsreader";

    /** Body */
    String body = GUI.i18n.getTranslation("RSSOWL_TEASER");

    /** Create mailto link */
    tellMyFriends += "?body=" + URLShop.mailToUrllEncode(body) + "&subject=" + URLShop.mailToUrllEncode(subject);

    return tellMyFriends;
  }

  /**
   * Try to get the File Name of the given URL.
   * 
   * @param url The URL to parse the File from.
   * @return String The File Name or the URL in external Form.
   */
  public static String getFile(URL url) {
    String file = url.getPath();
    if (StringShop.isset(file)) {
      String parts[] = file.split("/");
      if (parts.length > 0 && StringShop.isset(parts[parts.length - 1]))
        return urlDecode(parts[parts.length - 1]);
    }
    return url.toExternalForm();
  }

  /**
   * Check if the given URL contains a protocol name
   * 
   * @param url The URL to check
   * @return boolean TRUE if the URL has a protocol name
   */
  public static boolean hasProtocolName(String url) {
    int index = url.indexOf(':');
    if (index <= 0) {
      return false;
    }
    for (int i = 0; i < index; i++) {
      char c = url.charAt(i);
      if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '-')) {
        continue;
      }
      return false;
    }
    return true;
  }

  /**
   * Check if the given URL only has a simple host name.
   * 
   * @param url The URL to check
   * @return boolean TRUE if the URL is a simple host name
   */
  public static boolean isSimpleHostName(String url) {
    for (int i = 0; i < url.length(); i++) {
      char c = url.charAt(i);
      if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '-')) {
        continue;
      }
      return false;
    }
    return true;
  }

  /**
   * Return TRUE in case the given URL includes onr of the common binary
   * extensions.
   * 
   * @param str The URL to check
   * @return TRUE in case the URL looks like a binary
   */
  public static boolean looksLikeBinary(String str) {
    for (int a = 0; a < BINARY_EXTENSIONS.length; a++)
      if (str.indexOf(BINARY_EXTENSIONS[a]) >= 0)
        return true;
    return false;
  }

  /**
   * Return TRUE in case the given URL includes one of the common newsfeed
   * extensions.
   * 
   * @param str The URL to check
   * @param dotted If TRUE use extensions with leading dot
   * @return TRUE in case the URL looks like a newsfeed
   */
  public static boolean looksLikeNewsfeed(String str, boolean dotted) {
    for (int a = 0; a < ((dotted == true) ? FEED_EXTENSIONS_DOTTED.length : FEED_EXTENSIONS.length); a++)
      if (str.indexOf((dotted == true) ? FEED_EXTENSIONS_DOTTED[a] : FEED_EXTENSIONS[a]) >= 0)
        return true;
    return false;
  }

  /**
   * Return TRUE in case the given URL includes one of the common newsfeed
   * extensions.
   * 
   * @param url The URL to check
   * @param dotted If TRUE use extensions with leading dot
   * @return TRUE in case the URL looks like a newsfeed
   */
  public static boolean looksLikeNewsfeed(URL url, boolean dotted) {
    return looksLikeNewsfeed(url.getFile(), dotted);
  }

  /**
   * Return TRUE in case the given String looks like an URL.
   * 
   * @param str The String to check
   * @return TRUE in case the String looks like an URL
   */
  public static boolean looksLikeURL(String str) {

    /** Is empty or null? */
    if (!StringShop.isset(str))
      return false;

    /** Contains whitespaces ? */
    if (str.indexOf(' ') >= 0)
      return false;

    /** RegEx URL check */
    if (RegExShop.isValidURL(str))
      return true;

    /** Try creating an URL object */
    try {
      new URL(str);
    } catch (MalformedURLException e) {
      return false;
    }

    /** String is an URL */
    return true;
  }

  /**
   * URLEncode the given String. Note that URLEncoder uses "+" to display any
   * spaces. But we need "%20", so we'll replace all "+" with "%20". This method
   * is used to create a "mailto:" URL that is handled by a mail application.
   * The String is HTML Encoded if the user has set so.
   * 
   * @param str String to encode
   * @return String encoded String
   */
  public static String mailToUrllEncode(String str) {

    /** HTML Format mail */
    if (GlobalSettings.htmlFormatMail)
      return HtmlEncoder.encode(urlEncode(str.replaceAll("\\n", "<br />")).replaceAll("\\+", "%20"));

    /** Do not HTML Format mail */
    return urlEncode(str).replaceAll("\\+", "%20");
  }

  /**
   * This is a simple wrapper method for the decode() Method of the URLDecoder.
   * It uses RSSOwl's char encoding, which is UTF-8 by default, or any other
   * supported charset set by the user.
   * 
   * @param str String to decode
   * @return String URL Decoded String
   */
  public static String urlDecode(String str) {

    /** First attempt: Use GlobalSettings.charEncoding */
    try {
      return URLDecoder.decode(str, GlobalSettings.charEncoding);
    }

    /** Second attempt: Use OS default encoding */
    catch (UnsupportedEncodingException e) {
      try {
        return URLDecoder.decode(str, System.getProperty("file.encoding"));
      }

      /** Third solution: Use default encode() Method */
      catch (UnsupportedEncodingException e1) {
        return URLDecoder.decode(str);
      }
    }
  }

  /**
   * This is a simple wrapper method for the encode() Method of the URLEncoder.
   * It uses RSSOwl's char encoding, which is UTF-8 by default, or any other
   * supported charset set by the user.
   * 
   * @param str String to encode
   * @return String URL Encoded String
   */
  public static String urlEncode(String str) {

    /** First attempt: Use GlobalSettings.charEncoding */
    try {
      return URLEncoder.encode(str, GlobalSettings.charEncoding);
    }

    /** Second attempt: Use OS default encoding */
    catch (UnsupportedEncodingException e) {
      try {
        return URLEncoder.encode(str, System.getProperty("file.encoding"));
      }

      /** Third solution: Use default encode() Method */
      catch (UnsupportedEncodingException e1) {
        return URLEncoder.encode(str);
      }
    }
  }

  /**
   * Method to check wether JavaScript is allowed for the given Location.
   * <p>
   * Note: Only used on Windows!
   * </p>
   * 
   * @param location The location (URL) as String.
   * @return boolean TRUE in case JavaScript is allowed, FALSE otherwise.
   */
  public static boolean isScriptAllowed(String location) {

    /** Disallow JavaScript on local site */
    if (URLShop.ABOUT_BLANK.equals(location))
      return false;

    /** Allow JavaScript */
    return true;
  }

  /** Most of the URLs used in RSSOwl are defined here */
  static {
    AMPHETARATE_REGISTRATION_URL = "http://amphetarate.sourceforge.net/dinka-create-uid.php?appname=RSSOwl";
    RSSOWL_WEBPAGE = "http://www.rssowl.org";
    RSSOWL_FORUM = "http://sourceforge.net/forum/?group_id=86683";
    RSSOWL_PROMOTION = "http://www.rssowl.org/contribute";
    RSSOWL_FEED = "http://www.rssowl.org/newsfeed";
    RSSOWL_DOWNLOAD = "http://www.rssowl.org/download";
    RSSOWL_LIST = "http://lists.sourceforge.net/mailman/listinfo/rssowl-users";
    RSSOWL_DONATE = "http://sourceforge.net/donate/index.php?group_id=86683";
    RSSOWL_FAQ = "http://www.rssowl.org/faq.xml";
    RSSOWL_TUTORIAL = "http://tutorial.rssowl.org";
    RSSOWL_CHANGELOG_URL = "http://www.rssowl.org/update/rssowl.release";
    RSSOWL_UPDATE_URL = "http://www.rssowl.org/update/rssowl.version";
    RSSOWL_CONTACT = "mailto:contact@rssowl.org";
  }
}