package ij.plugin;
import ij.IJ;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.applet.Applet;

/**
 * This plugin implements the File/Import/URL command and the commands in the Help menu that 
 * open web pages. It is based on Eric Albert's cross-platform (Windows, Mac OS X and Unix) 
 * BrowserLauncher class.
 * <p>
 * BrowserLauncher is a class that provides one static method, openURL, which opens the default
 * web browser for the current user of the system to the given URL.  It may support other
 * protocols depending on the system -- mailto, ftp, etc. -- but that has not been rigorously
 * tested and is not guaranteed to work.
 * <p>
 * Yes, this is platform-specific code, and yes, it may rely on classes on certain platforms
 * that are not part of the standard JDK.  What we're trying to do, though, is to take something
 * that's frequently desirable but inherently platform-specific -- opening a default browser --
 * and allow programmers (you, for example) to do so without worrying about dropping into native
 * code or doing anything else similarly evil.
 * <p>
 * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant systems without
 * modification or a need for additional libraries.  All classes that are required on certain
 * platforms to allow this to run are dynamically loaded at runtime via reflection and, if not
 * found, will not cause this to do anything other than returning an error when opening the
 * browser.
 * <p>
 * This code is Copyright 1999-2001 by Eric Albert (ejalbert@cs.stanford.edu) and may be
 * redistributed or modified in any form without restrictions as long as the portion of this
 * comment from this paragraph through the end of the comment is not removed.  The author
 * requests that he be notified of any application, applet, or other binary that makes use of
 * this code, but that's more out of curiosity than anything and is not required.  This software
 * includes no warranty.  The author is not repsonsible for any loss of data or functionality
 * or any adverse or unexpected effects of using this software.
 * <p>
 * Credits:
 * <br>Steven Spencer, JavaWorld magazine (<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java Tip 66</a>)
 * <br>Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea Cantatore,
 * Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk
 *
 * @author Eric Albert (<a href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
 * @version 1.4b1 (Released June 20, 2001)
 */
public class BrowserLauncher implements PlugIn {
	/** The com.apple.mrj.MRJFileUtils class */
	private static Class mrjFileUtilsClass;
	/** The openURL method of com.apple.mrj.MRJFileUtils */
	private static Method openURL;
	private static boolean error;
	static {loadClasses();}


	/** Opens the specified URL (default is the ImageJ home page). */
	public void run(String theURL) {
		if (error) return;
		if (theURL==null || theURL.equals(""))
			theURL = IJ.URL;
		Applet applet = IJ.getApplet();
		if (applet!=null) {
			try {
				applet.getAppletContext().showDocument(new URL(theURL), "_blank" );
			} catch (Exception e) {}
			return;
		}
		try {openURL(theURL);}
		catch (IOException e) {}
	}

	/**
	 * Attempts to open the default web browser to the given URL.
	 * @param url The URL to open
	 * @throws IOException If the web browser could not be located or does not run
	 */
	public static void openURL(String url) throws IOException {
		String errorMessage = "";
		if (IJ.isMacOSX()) {
			if (IJ.isJava16())
				IJ.runMacro("exec('open', '"+url+"')");
			else {
				try {
					Method aMethod = mrjFileUtilsClass.getDeclaredMethod("sharedWorkspace", new Class[] {});
					Object aTarget = aMethod.invoke( mrjFileUtilsClass, new Object[] {});
					openURL.invoke(aTarget, new Object[] { new java.net.URL( url )}); 
				} catch (Exception e) {
					errorMessage = ""+e;
				}
			}
		} else if (IJ.isWindows()) {
			String cmd = "rundll32 url.dll,FileProtocolHandler " + url;
			if (System.getProperty("os.name").startsWith("Windows 2000"))
				cmd = "rundll32 shell32.dll,ShellExec_RunDLL " + url;
			Process process = Runtime.getRuntime().exec(cmd);
			// This avoids a memory leak on some versions of Java on Windows.
			// That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
			try {
				process.waitFor();
				process.exitValue();
			} catch (InterruptedException ie) {
				throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
			}
		} else {
				// Assume Linux or Unix
				// Based on BareBonesBrowserLaunch (http://www.centerkey.com/java/browser/)
				// The utility 'xdg-open' launches the URL in the user's preferred browser,
				// therefore we try to use it first, before trying to discover other browsers.
				String[] browsers = {"xdg-open", "netscape", "firefox", "konqueror", "mozilla", "opera", "epiphany", "lynx" };
				String browserName = null;
				try {
					for (int count=0; count<browsers.length && browserName==null; count++) {
						String[] c = new String[] {"which", browsers[count]};
						if (Runtime.getRuntime().exec(c).waitFor()==0)
							browserName = browsers[count];
					}
					if (browserName==null)
						ij.IJ.error("BrowserLauncher", "Could not find a browser");
					else
						Runtime.getRuntime().exec(new String[] {browserName, url});
				} catch (Exception e) {
					throw new IOException("Exception while launching browser: " + e.getMessage());
				}
		}
	}
	
	/**
	 * Called by a static initializer to load any classes, fields, and methods 
	 * required at runtime to locate the user's web browser.
	 */
	private static void loadClasses() {
		if (IJ.isMacOSX() && !IJ.isJava16() && IJ.getApplet()==null) {
			try {
				if (new File("/System/Library/Java/com/apple/cocoa/application/NSWorkspace.class").exists()) {
					ClassLoader classLoader = new URLClassLoader(new URL[]{new File("/System/Library/Java").toURL()});
					mrjFileUtilsClass = Class.forName("com.apple.cocoa.application.NSWorkspace", true, classLoader);
				} else
					mrjFileUtilsClass = Class.forName("com.apple.cocoa.application.NSWorkspace");
				openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { java.net.URL.class });
			} catch (Exception e) {
				IJ.log("BrowserLauncher"+e);
				error = true;
			}
		}
	}

}

