package nxm.sys.lib;

import java.net.URL;

import nxm.sys.inc.InternalUseOnly;
import nxm.sys.inc.ShellParent;

/** ShellParent implementation that is used when running within a Java Web Start context. The
 *  methods provide the particulars of running from within this context such as getting the list
 *  of option trees and the directories.
 *  @author J. Czechowski IV
 */
public class Webstart implements ShellParent { // TODO: Class should be final
  private URL codebase = null; // The codebase where this information is served from.

  /** Command line interpreter for Java Web Start applications. Instantiates a new instance of a
   *  Webstart and invokes the run method with the command line arguments specified in args. <br>
   *  <br>
   *  NOTE: This calls <code>System.exit(0)</code> when done to make sure it exits JVM after it is
   *  done.
   *  @param args Any command-line arguments.
   */
  @InternalUseOnly("Since NeXtMidas 3.7.1 - This should never be called directly")
  @SuppressWarnings("CallToPrintStackTrace")
  public static void main (String... args) {
    int exitCode = 0;
    try {
      Shell.runNew (new Webstart(), StringUtil.join(args," "), false);
    }
    catch (Throwable t) {
      exitCode = 1; // Flag error exit status
      t.printStackTrace();
    }
    finally {
      System.exit(exitCode); // make sure to exit Web Start application even if stuff are backgrounded
    }
  }

  /** Initialize a default instance of the object. */
  @Deprecated
  @InternalUseOnly("Since NeXtMidas 3.7.1 - This should be private.")
  @SuppressWarnings("OverridableMethodCallInConstructor")
  public Webstart () {
    initCodebase();
  }

  /** Initialize the codebase attribute of the application.  In order to avoid
   *  having to have the jnlp.jar in the classpath while compiling we'll use
   *  dynamic method invocation to retrieve the values.  Upon returning from
   *  this method, the codebase member will be set.
   *  @deprecated Since NeXtMidas 3.7.1 - This should be private.
   */
  @Deprecated
  @InternalUseOnly("Since NeXtMidas 3.7.1 - This should be private.")
  @SuppressWarnings({"CallToPrintStackTrace", "UseOfSystemOutOrSystemErr", "UseSpecificCatch",
                     "BroadCatchBlock", "TooBroadCatch", "deprecation"})
  protected void initCodebase () {
    if (codebase != null) return; // since 3.3.4: already initialized, skip (BUG 2766)

    try {
      // TODO: Use normal reflection rather than deprecated KeyObject.invoke calls
      Object basicSvc = KeyObject.invokeStaticMethod(
          "javax.jnlp.ServiceManager", "lookup", new Object[] { "javax.jnlp.BasicService" }
        );

      codebase = (URL)KeyObject.invokeInstanceMethod(basicSvc, "getCodeBase", new Object[0]);
      if (codebase == null) { // since 3.3.4 (BUG 2766)
        System.err.println("WARN: Webstart.initCodebase() unable to get codebase for this application.");
      }
    }
    catch (Exception e) {
      e.printStackTrace(); // Can't use normal Midas exception handling since it is not initialized yet
    }
  }

  /** Return the arguments to the AUX command for configuring the application's aux path. The
   *  values returned by this method are retrieved from the AUX parameter specified in the JNLP
   *  file for the application. If that parameter does not exist then a default aux path is
   *  returned.
   *  @return The arguments to the AUX command for configuring the aux path.
   */
  @Override
  public String getAux () {
    final String defAux = "HOME HOME|RAM|DAT";
    String aux = System.getProperty("AUX");
    if (aux==null) aux = defAux;
    return aux;
  }

  /** Return the URL to the code-base that this application is served from.
   *  This is the full URL including the protocol, host name, and path.
   *  @return The URL that this web application was served from.
   */
  public URL getCodeBase () {
    return codebase;
  }

  /** Return the value of NMROOT for this application.
   *  @return This should return "jar:nxm-sys.jar" for Webstart deployed applications.
   */
  @Override
  public String getNmRoot () {
    return OptionTree.findOptRoot("SYS");
  }

  /** Return the option trees that are to be loaded by the Shell on startup. The list of these is
   *  taken from the OPTS JNLP property. The String is a list of comma separated option tree names.
   *  @return A comma separated list of option trees to configure on startup or null if none.
   */
  @Override
  public String getOpts () {
    String opts = Shell.getProperty("OPTS");
    return OptionTree.getOptsHelper(opts, this, true);
  }

  /** Return the current working directory. This is simply the full code-base minus any query
   *  string that may exist.
   *  @return The current working directory.
   */
  @Override
  public String getCWD () {
    if (codebase == null) return null; // since 3.3.4 (BUG 2766)
    String file = codebase.toString();
    int i = file.indexOf('?');
    if (i>=0) file = file.substring(0,i);
    return file;
  }

  @Override
  public String getNMS () {
    return Shell.getProperty("NMSTARTUP.USER"); // since 3.1.3 as part of BUG 1447
  }

  @Override
  public String getHome () {
    return null; // Tells Shell to set this the "normal" way.
  }

  /** Return the host name where the execution of this Shell originated. The host name is determined
   *  simply from the host property of the code-base.
   *  @return The name of the origin host where this code is served from.
   */
  @Override
  public String getServer () {
    if (codebase == null) return null; // since 3.3.4 (BUG 2766)
    return codebase.getHost();
  }

  /** Gets theme based on "ENV.THEME" system property, otherwise returns null to use system defaults.
   *  @since NeXtMidas 2.9.3
   */
  @Override
  public String getTheme () {
    return Shell.getProperty("ENV.THEME");
  }

  /** Gets style based on "ENV.STYLE" system property, otherwise returns null to use system defaults.
   *  @since NeXtMidas 2.9.3
   */
  @Override
  public String getStyle () {
    return Shell.getProperty("ENV.STYLE");
  }

  @Override
  public Terminal getTerminal () { // since NeXtMidas 3.3.0
    return null; // return null to let Shell determine terminal type
  }

  /** Return a string describing the object.
   *  @return A string describing the object.
   */
  @Override
  public String toString () {
    return "Webstart\n" +
           "\tcodebase : " + getCodeBase() + "\n" +
           "\tcwd      : " + getCWD();
  }
}
