/*   **********************************************************************  **
 **   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.controller.RSSOwlLoader;
import net.sourceforge.rssowl.util.shop.StringShop;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * Only allow one instance of RSSOwl running at the same time.
 * <p>
 * The StartupManager is a small server that is using Sockets to listen on a
 * port. Whenever an instance of RSSOwl is starting, the server is started. In
 * case another instance is already running the server, a message is passed to
 * it. The server will then restore the running RSSOwl from taskbar or tray.
 * </p>
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class StartupManager {
  private static final String LOCALHOST = "127.0.0.1";
  private static final int RSSOWL_SOCKET_PORT = 8794;
  private static ExtendedThread server;
  private static final String DEFAULT_MESSAGE = "RSSOwl Startup Attempt";
  static ServerSocket applLockSocket;

  /**
   * Check wether RSSOwl is already running by trying to start the Server. In
   * case RSSOwl is already running, a message is passed to the Server of that
   * instance.
   * 
   * @param message A message passed in from the starting application.
   * @return boolean TRUE if RSSOwl is already running, false otherwise.
   */
  public static boolean isRSSOwlRunning(String message) {

    /** Try to create the Server that is bound to LocalHost */
    try {
      applLockSocket = new ServerSocket(RSSOWL_SOCKET_PORT, 50, InetAddress.getByName(LOCALHOST));
      handleSocketUnBound();
      return false;
    }

    /** Another instance already running */
    catch (java.net.BindException e) {
      GUI.logger.log("StartupManager#run()", e);
      handleSocketBound(message);
      return true;
    }

    /** Other Error */
    catch (IOException e) {
      GUI.logger.log("StartupManager#run()", e);
      return false;
    }
  }

  /**
   * Stop the Server.
   */
  public static void stopServer() {
    if (server != null) {
      server.stopThread();
      server.interrupt();
      try {
        applLockSocket.close();
      } catch (IOException e) {
        GUI.logger.log("stopServer()", e);
      }
    }
  }

  /**
   * Server already running. Pass a message to the running Server.
   * 
   * @param message A message passed in from the starting application.
   */
  private static void handleSocketBound(String message) {
    Socket socket;
    try {
      socket = new Socket(InetAddress.getByName(LOCALHOST), RSSOWL_SOCKET_PORT);
      PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
      writer.println(StringShop.isset(message) ? message : DEFAULT_MESSAGE);
      writer.flush();
    } catch (UnknownHostException e) {
      GUI.logger.log("handleSocketBound()", e);
    } catch (IOException e) {
      GUI.logger.log("handleSocketBound()", e);
    }
  }

  /**
   * Server not yet running. Start it and listen for incoming messages.
   */
  private static void handleSocketUnBound() {
    listen();
  }

  /**
   * Listen for incoming messages.
   */
  private static void listen() {

    /** Run the Server inside a Thread */
    server = new ExtendedThread() {
      public void run() {
        while (!isStopped() && !isInterrupted()) {
          BufferedReader buffReader = null;
          try {

            /** Read a single line from the Socket */
            Socket socket = applLockSocket.accept();
            buffReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            final String message = buffReader.readLine();
            socket.close();

            /** Check the received message */
            if (StringShop.isset(message) && GUI.display != null && !GUI.display.isDisposed()) {
              GUI.display.asyncExec(new Runnable() {
                public void run() {

                  /** Restore the RSSOwl Window and handle Message */
                  if (GUI.isAlive()) {
                    GUI.rssOwlGui.restoreWindow();

                    /** Handle the message as Link if valid argument */
                    if (RSSOwlLoader.isValidArgument(message))
                      GUI.rssOwlGui.getEventManager().actionHandleSuppliedLink(message);
                  }
                }
              });
            }
          } catch (IOException e) {
            /** Ignore */
          } finally {
            try {
              if (buffReader != null)
                buffReader.close();
            } catch (Exception e) {
              /** Ignore */
            }
          }
        }
      }
    };
    server.setDaemon(true);
    server.setName("Startup Manager Thread");
    server.start();
  }
}