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

import net.sourceforge.rssowl.controller.thread.StartupManager;
import net.sourceforge.rssowl.controller.thread.UpdateManager;
import net.sourceforge.rssowl.util.GlobalSettings;
import net.sourceforge.rssowl.util.shop.BrowserShop;
import net.sourceforge.rssowl.util.shop.FileShop;
import net.sourceforge.rssowl.util.shop.LayoutShop;
import net.sourceforge.rssowl.util.shop.PaintShop;
import net.sourceforge.rssowl.util.shop.RegExShop;
import net.sourceforge.rssowl.util.shop.StringShop;
import net.sourceforge.rssowl.util.shop.URLShop;
import net.sourceforge.rssowl.util.shop.WidgetShop;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

/**
 * Class that loads the RSSOwl-Application and displays a splashscreen while
 * loading.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class RSSOwlLoader {

  /** System Property: Allow more than one instance of RSSOwl */
  private static final String PROPERTY_ALLOW_MULTI_INSTANCES = "net.sourceforge.rssowl.allowMultiInstances";

  /** System Property: Run RSSOwl in Debug Mode */
  private static final String PROPERTY_DEBUG_MODE = "net.sourceforge.rssowl.debug";

  /** System Property: Do not show the Splashscreen at startup */
  private static final String PROPERTY_NO_SPLASH = "net.sourceforge.rssowl.noSplash";

  /** System Property: Sort Favorites over Categories in Favorites Tree */
  static final String PROPERTY_CLASSIC_SORT = "net.sourceforge.rssowl.oldSort";

  /** A valid (URL or Filepath) first Argument if provided */
  static String feedArgument;

  Display display;
  Shell invisibleShell;

  /** Load GUI and display a Splashscreen while loading */
  private RSSOwlLoader() {

    /** Apply application name to Display */
    Display.setAppName("RSSOwl " + UpdateManager.MAJOR_VERSION);

    /** Create a new Display */
    display = new Display();

    /** Shell should not be visible in the taskbar */
    invisibleShell = new Shell(display, SWT.NONE);

    /** Shell containing the splash */
    Shell shell = new Shell(invisibleShell, GlobalSettings.isWindows() ? SWT.TOOL : SWT.NONE);
    shell.setLayout(LayoutShop.createFillLayout(0, 0));

    /** Only show the Splash in case it was not disabled */
    if (!System.getProperties().containsKey(PROPERTY_NO_SPLASH)) {

      /** Label containing the Splashimage */
      Label label = new Label(shell, SWT.NONE);
      label.setImage(PaintShop.loadImage("/img/splash.gif"));
      label.addDisposeListener(DisposeListenerImpl.getInstance());

      /** Pack Shell */
      shell.pack();

      /** Problem on Linux: Shell is shown in Taskbar, so set title */
      shell.setText(WidgetShop.getShellTitle());

      /** Center the splashscreen */
      LayoutShop.centerShell(display, shell);

      /** Show the splash */
      shell.open();
    }

    /** Load the application */
    new GUI(display, invisibleShell).showGui();
  }

  /**
   * Start a new RSSOwl Application
   * 
   * @param args If an argument is passed to the application, it is interpreted
   * as URL and tryd to open as newsfeed
   */
  public static void main(String[] args) {

    /** Things to do before launching RSSOwl */
    startupProcess(args);

    /** Start loading of Maincontroller */
    new RSSOwlLoader();
  }

  /**
   * Create the Archive Directory
   */
  private static void createArchiveDir() {
    File archiveDir = new File(GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "archive");
    if (!archiveDir.exists()) {
      archiveDir.mkdir();
    }
  }

  /**
   * Create the Cache Directory
   */
  private static void createCacheDir() {
    File cacheDir = new File(GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "cache");
    if (!cacheDir.exists()) {
      cacheDir.mkdir();
    }
  }

  /**
   * Create the Log Directory
   */
  private static void createLogDir() {
    File logDir = new File(GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "logs");
    if (!logDir.exists()) {
      logDir.mkdir();
    }
  }

  /**
   * Create the Temp Directory
   */
  private static void createTempDir() {
    File tempDir = new File(GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "tmp");
    if (!tempDir.exists()) {
      tempDir.mkdir();
    }

    /** Clean Up the Temporary Directory */
    else {
      File files[] = tempDir.listFiles();
      for (int a = 0; a < files.length; a++)
        files[a].delete();
    }
  }

  /**
   * Create the Home Directory
   */
  private static void createWorkingDir() {

    /** On Mac, append "Library/Preferences" to the user.home directory */
    String homePath = (GlobalSettings.isMac() ? System.getProperty("user.home") + GlobalSettings.PATH_SEPARATOR + "Library/Preferences" : System.getProperty("user.home"));

    /** The home directory name. On Mac directories should not begin with a "." */
    String homeDirName = GlobalSettings.isMac() ? "rssowl" : ".rssowl";

    /** In case the Mac user still uses the older ".rssowl" folder, take that */
    if (GlobalSettings.isMac() && new File(homePath + GlobalSettings.PATH_SEPARATOR + ".rssowl").exists())
      homeDirName = ".rssowl";

    /** Create the homedirectory */
    File homeDir = new File(homePath + GlobalSettings.PATH_SEPARATOR + homeDirName);
    if (!homeDir.exists() && FileShop.isMediumWriteable(homeDir))
      homeDir.mkdir();

    /** Try user.home directory */
    File file = new File(homePath + GlobalSettings.PATH_SEPARATOR + homeDirName + GlobalSettings.PATH_SEPARATOR + "tempdir.tmp");
    if (FileShop.isMediumWriteable(file)) {
      GlobalSettings.WORKING_DIR = homePath + GlobalSettings.PATH_SEPARATOR + homeDirName;
      return;
    }

    /** Try user.dir directory */
    file = new File(System.getProperty("user.dir") + GlobalSettings.PATH_SEPARATOR + "tempdir.tmp");
    if (FileShop.isMediumWriteable(file)) {
      GlobalSettings.WORKING_DIR = System.getProperty("user.dir");
      return;
    }

    /** Try java.io.tmpdir directory */
    file = new File(System.getProperty("java.io.tmpdir") + GlobalSettings.PATH_SEPARATOR + "tempdir.tmp");
    if (FileShop.isMediumWriteable(file))
      GlobalSettings.WORKING_DIR = System.getProperty("java.io.tmpdir");
  }

  /**
   * Setup Debug Mode for HttpClient
   */
  private static void initDebugMode() {

    /** Redirect System.err into logging file */
    try {
      File debugLog = new File(GlobalSettings.LOGS_DIR + GlobalSettings.PATH_SEPARATOR + "debug.log");
      PrintStream out = new PrintStream(new FileOutputStream(debugLog));
      System.setErr(out);
    } catch (FileNotFoundException e) {
      /** Ignore and write out to console */
    }

    /** Set Logging to TRACE */
    System.setProperty("org.apache.commons.logging.simplelog.defaultlog", "trace");
    System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");

    /** Print User Agent into Log */
    System.err.println(BrowserShop.getOwlAgent());
  }

  /**
   * Check if the given argument is a valid URI or URL
   * 
   * @param arg The argument that has been passed to RSSOwl
   * @return TRUE if the argument is valid
   */
  public static boolean isValidArgument(String arg) {

    /** Valid file path and looks like Feed */
    if (arg.indexOf(".exe") < 0 && URLShop.looksLikeNewsfeed(arg, true) && new File(arg).exists())
      return true;

    /** Check for valid URL */
    return RegExShop.isValidURL(arg);
  }

  /**
   * Set the file pathes to the settings- and temp file.
   */
  private static void setFilePathes() {
    GlobalSettings.RSSOWL_SETTINGS_FILE = GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "user.xml";
    GlobalSettings.RSSOWL_SETTINGS_BACKUP_FILE = GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "user.bak";
    GlobalSettings.CRYPT_FILE = GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + ".user";
    GlobalSettings.TEMP_DIR = GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "tmp";
    GlobalSettings.TEMP_EXPORT_FILE = GlobalSettings.TEMP_DIR + GlobalSettings.PATH_SEPARATOR + "export.tmp";
    GlobalSettings.TEMP_FEED_FILE = GlobalSettings.TEMP_DIR + GlobalSettings.PATH_SEPARATOR + "rssfeed.tmp";
    GlobalSettings.ARCHIVE_DIR = GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "archive";
    GlobalSettings.CACHE_DIR = GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "cache";
    GlobalSettings.LOGS_DIR = GlobalSettings.WORKING_DIR + GlobalSettings.PATH_SEPARATOR + "logs";
  }

  /**
   * Write OS specific DWOrds into System properties
   */
  private static void setUpProperties() {

    /** Mac: Disable the blue focus ring on most Widgets */
    if (GlobalSettings.isMac())
      System.setProperty("org.eclipse.swt.internal.carbon.noFocusRing", "true");

    /** Mac: Use small fonts */
    if (GlobalSettings.isMac())
      System.setProperty("org.eclipse.swt.internal.carbon.smallFonts", "true");

    /** Default Properties for the HttpClient logger */
    System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
    System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "false");
    System.setProperty("org.apache.commons.logging.simplelog.defaultlog", (GlobalSettings._IS_PRE_RELEASE == true) ? "error" : "fatal");
  }

  /**
   * Things to do before launching RSSOwl
   * 
   * @param args Arguments of RSSOwl
   */
  private static void startupProcess(String[] args) {

    /** See if supplied argument is a valid URL */
    for (int i = 0; i < args.length; i++) {
      if (!StringShop.isset(args[i]))
        continue;

      String arg = args[i].trim();

      /** Handle Feed Protocol (#1) */
      if (arg.startsWith(URLShop.FEED_PROTOCOL_LONG))
        arg = arg.substring(URLShop.FEED_PROTOCOL_LONG.length());

      /** Handle Feed Protocol (#2) */
      else if (arg.startsWith(URLShop.FEED_PROTOCOL_SHORT))
        arg = arg.substring(URLShop.FEED_PROTOCOL_SHORT.length());

      /** Check if valid */
      if (isValidArgument(arg)) {
        feedArgument = arg;
        break;
      }
    }

    /** In case RSSOwl is already running */
    if (!System.getProperties().containsKey(PROPERTY_ALLOW_MULTI_INSTANCES) && StartupManager.isRSSOwlRunning(feedArgument)) {

      /**
       * Send a message to the other running instance of RSSOwl and wait some
       * seconds, so that is has a chance to read the message. After that, the
       * other running instance will restore from taskbar or tray to show the
       * user.
       */
      try {
        Thread.sleep(2500);
      } catch (InterruptedException e) {
        System.exit(0);
      } finally {
        System.exit(0);
      }
    }

    /** Check if RSSOwl was started in Debug Mode */
    if (System.getProperties().containsKey(PROPERTY_DEBUG_MODE))
      GlobalSettings._IS_DEBUG = true;

    /** Create the Working Directory if it does not yet exist */
    createWorkingDir();

    /** Create the Archive Directory */
    createArchiveDir();

    /** Create the Cache Directory */
    createCacheDir();

    /** Create the Logs Directory */
    createLogDir();

    /** Create the Temp Directory */
    createTempDir();

    /** Set the file pathes */
    setFilePathes();

    /** Setup OS specific properties (DWords) */
    setUpProperties();

    /** Check for Debug Mode */
    if (GlobalSettings._IS_DEBUG)
      initDebugMode();
  }
}