/*
LaunchBrowser.java - Launches a url in the OS default web browser
Copyright  (C) 2000-2004 Hugues Johnson
 
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package com.huguesjohnson;

import java.io.IOException;
import java.lang.Class;
import java.lang.ClassNotFoundException;
import java.lang.Exception;
import java.lang.IllegalAccessException;
import java.lang.InstantiationException;
import java.lang.InterruptedException;
import java.lang.Object;
import java.lang.Process;
import java.lang.Runtime;
import java.lang.String;
import java.lang.StringBuffer;

/** class LaunchBrowser
 * usage: String result=(new LaunchBrowser()).launch("http://www.wherever.com");
 * alternate usage: String verboseResult=(new LaunchBrowser()).launch("http://www.wherever.com",true);
 * alternate usage: String verboseResult=(new LaunchBrowser()).launch("file://c:\\some-folder\\some-file.html",true);
 * alternate usage: String verboseResult=(new LaunchBrowser()).launch("file:///some-dir/some-file.html",true);
 * This has only been tested on Windows 2000, if it doesn't work on another OS please set verbose to true to debug.
 * I can just about guarantee this will not work with OS/2, the algorithm to lookup the operating system explicitly checks for Windows and MacOS with the default being UNIX/Linux.
 * UNIX/Linux is considered the default because each "flavor" of UNIX/Linux returns a different name to the System.getProperty("os.name") call.. there is no standard name. For example, HP-UX returns "HP-UX" while Solaris returns "Solaris".
 * This also assumes that if UNIX/Linux is the OS, then netscape is installed. As far as I know there is no way to pass UNIX/Linux an URL and have it figure out the default browser.
 * Should this implement runnable?
 * @author Hugues Johnson
 */
public class LaunchBrowser extends Object{
    private final static int OS_WINDOWS=0;
    private final static int OS_MAC=1;
    private final static int OS_UNIX=2;
    
    private final static String WINDOWS_START="win";
    private final static String MAC_START="mac";
    
    private final static String WINDOWS_COMMAND="rundll32";
    private final static String WINDOWS_PARAMETERS="url.dll,FileProtocolHandler";
    private final static String UNIX_COMMAND="netscape";
    private final static String UNIX_PARAMETERS="-remote openURL";
    
    /** acts like a header for MRJFileUtils, used to trick out javac
     */
    private interface MRJFileUtilsInterface{
        void openURL(String url);
    }
    
    /**  constructor
     */
    public LaunchBrowser(){
        super();
    }
    
    /** Launches a web browser with the specified url.
     * First tries to use current browser session, if no browser is loaded it starts a new session.
     * See comments for the class for proper usage and known issues.
     * @param url the address to open
     */
    public String launch(String url){
        return(this.launch(url,false));
    }
    
    /** Launches a web browser with the specified url.
     * First tries to use current browser session, if no browser is loaded it starts a new session.
     * See comments for the class for proper usage and known issues.
     * @param url the address to open
     * @param verbose whether or not to return verbose output, useful for debugging. This is false if launch(url) is used.
     */
    public String launch(String url,boolean verbose){
        StringBuffer result=new StringBuffer();
        if(verbose){ result.append("received url parameter: ").append(url); }
        int osValue=LaunchBrowser.lookupOperatingSystem();
        if(verbose){ result.append("\nlookupOperatingSystem() returned osValue: ").append(osValue); }
        switch(osValue){
            case OS_WINDOWS:{
                if(verbose){ result.append("\nOperating system is Windows"); }
                StringBuffer commandLine=new StringBuffer(WINDOWS_COMMAND).append(" ").append(WINDOWS_PARAMETERS).append(" ").append(url);
                if(verbose){ result.append("\nTrying to execute command line: ").append(commandLine); }
                try{
                    Process process=Runtime.getRuntime().exec(commandLine.toString());
                } catch(IOException iox){
                    if(verbose){ result.append("\n"); }
                    result.append("IOException occurred executing Windows command: ").append(iox.toString());
                }
                break;
            }
            case OS_UNIX:{
                if(verbose){ result.append("\nOperating system is UNIX or Linux"); }
                /* try to open url in current browser session first */
                StringBuffer commandLine=new StringBuffer(UNIX_COMMAND).append(" ").append(UNIX_PARAMETERS).append(" (").append(url).append(")");
                try{
                    Process process=Runtime.getRuntime().exec(commandLine.toString());
                    /* checking to see if browser is already running */
                    int returnCode=process.waitFor();
                    if(returnCode!=0){
                        /* browser is not running, start a new session */
                        commandLine=new StringBuffer(UNIX_COMMAND).append(" ").append(url);
                        process=Runtime.getRuntime().exec(commandLine.toString());
                    }
                } catch(IOException iox){
                    if(verbose){ result.append("\n"); }
                    result.append("IOException occurred executing UNIX command: ").append(iox.toString());
                } catch(InterruptedException ix){
                    if(verbose){ result.append("\n"); }
                    result.append("UNIX process interrupted: ").append(ix.toString());
                }
                break;
            }
            case OS_MAC:{
                if(verbose){ result.append("\nOperating system is MacOS"); }
                try{
                    Class mrjFileUtilsClass=Class.forName("com.apple.mrj.MRJFileUtils");
                    Object mrjFileUtilsInstance=mrjFileUtilsClass.newInstance();
                    ((MRJFileUtilsInterface)mrjFileUtilsInstance).openURL(url);
                } catch(ClassNotFoundException cnfx){
                    if(verbose){ result.append("\n"); }
                    result.append("Unable to find com.apple.mrj.MRJFileUtils class: ").append(cnfx.toString());
                } catch(IllegalAccessException iax){
                    if(verbose){ result.append("\n"); }
                    result.append("Unable to access com.apple.mrj.MRJFileUtils class: ").append(iax.toString());
                } catch(InstantiationException ix){
                    if(verbose){ result.append("\n"); }
                    result.append("Unable to instantiate com.apple.mrj.MRJFileUtils class: ").append(ix.toString());
                } catch(Exception x){
                    if(verbose){ result.append("\n"); }
                    result.append("Exception thrown from MRJFileUtils: ").append(x.toString());
                }
                break;
            }
        }
        return(result.toString());
    }
    
    /** Looks up the operating system and returns one of the OS_ constants declared in this class
     * Explicitly looks for Windows and MacOS, if the OS is neither than UNIX is considered the default.
     * See comments for class declaration for more details on the OS lookup.
     * @return a constant (defined in this class) representing the operating system
     */
    private final static int lookupOperatingSystem(){
        String osName=System.getProperty("os.name").toLowerCase();
        int osValue=OS_UNIX;
        if(osName.startsWith(WINDOWS_START)){
            osValue=OS_WINDOWS;
        } else if(osName.startsWith(MAC_START)){
            osValue=OS_MAC;
        }
        return(osValue);
    }
}