/*
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
 * or http://www.netbeans.org/cddl.txt.
 * 
 * When distributing Covered Code, include this CDDL Header Notice in each file
 * and include the License file at http://www.netbeans.org/cddl.txt.
 * If applicable, add the following below the CDDL Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.core;

import java.awt.Component;
import java.awt.TextComponent;
import javax.swing.text.JTextComponent;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.lang.reflect.*;
import java.text.MessageFormat;
import org.netbeans.core.startup.CLIOptions;
import org.netbeans.core.startup.TopLogging;

import org.openide.*;
import org.openide.explorer.*;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
import org.openide.windows.*;

import org.netbeans.TopSecurityManager;

/** This class is a TopManager for running without the GUI.
 *
 * @author Roger Blumer, David Strupl
 */
public class NonGuiMain extends NonGui {
    
    /** Success status for commands. */
    public static final int				CMD_OK			= 0;
    
    /** Failure status for commands. */
    public static final int				CMD_FAIL		= 1;
    
    /** If the TopManager is initialized. */
    public static boolean load = true;
    /** Interactive mode means reading input as individual lines.*/
    public static boolean interactiveMode = true;
    /** whether we should bring up the GUI windows before running scripts */
    public static boolean startGui = false;	
    
    /** PROMPT used for prompting the user.*/
    public static final String PROMPT = "[localhost]"; // NOI18N
    
    /** Class used to interpret the script.*/
    //private static ScriptType interpreter;
    
    /** It defaults to the BeanShell value. The value can be changed
     * from the command line arguments.
     */
    private static String interpName = "BeanShell"; // NOI18N
    
    /** */
    private static PrintStream out = System.out;
    /** */
    private static InputStream in = System.in;
    
    /** Status line is not shown during initialization before the
     * actual script is run.*/
    private static boolean showStatusLine = false;
    private static boolean showNotifyText = true;
    
        /** Test method to check whether some level of interactivity is enabled.
         * @param il mask composed of the constants of IL_XXXX
         * @return true if such level is enabled
         */
    // copied from Plain.java
    //
    //    public boolean isInteractive (int il) {
    //        return (IL_WINDOWS & il) == IL_WINDOWS;
    //    }
    
    /** Prints system info to the out. */
    public static void info() {
        ///		NonGui.showSystemInfo();
        String sysInfo;
        sysInfo = NbBundle.getBundle(org.netbeans.core.NonGui.class).getString ("CTL_System_info");	// NOI18N
        out.println("-- " + sysInfo + " ----------------------------------------------------------------"); // NOI18N
        TopLogging.printSystemInfo(out);
        out.println("-------------------------------------------------------------------------------"); // NOI18N
    }
    
    /** Prints help to the System.out. */
    public static void showHelp2() {
        // XXX how to implement? CLIOptions.showHelp();
        System.out.println(getStringX("CTL_INPUT_option")); // NOI18N
        System.out.println(getStringX("CTL_OUTPUT_option"));
        System.out.println(getStringX("CTL_INFO_option"));
        System.out.println(getStringX("CTL_NOLOAD_option"));
        System.out.println(getStringX("CTL_FP_option"));
        System.out.println(getStringX("CTL_ENV_option"));
    }
    
    /** Parses the command line arguments. */
    public static int processArgs(String[] args) throws Exception {
        final String _methodName = "processArgs"; // NOI18N
        String		argv;
        String		argvOrig;
        int			argNo;
        
        boolean showInfo = false;
        ArrayList newArgs = new ArrayList(2);
        
        argNo = 0;
        while (argNo < args.length)
        {
            argvOrig = args[argNo];
            
            if (argvOrig.startsWith("-"))	// NOI18N
            {
                argv = argvOrig.substring(1);
                if (argv.equals("info")) {	// NOI18N
                    showInfo = true;
                    argNo++;
                }
                else if (argv.equals("gui")) {  // NOI18N
                    startGui = true;
                    argNo++;
                }
                else if (argv.startsWith("t"))	// NOI18N
                {
                    // There is an optional space
                    if (argv.length() == 1)
                    {
                        argNo++;
                        if (argNo >= args.length)
                        {
                            out.println(
                            getStringX("MSG_NoInputFile"));
                            return CMD_FAIL;
                        }
                        interpName = args[argNo];
                    }
                    else
                    {
                        interpName = argv.substring(1);
                    }
                    argNo++;
                }
                else if (argv.startsWith("i"))	// NOI18N
                {
                    String inFile;
                    // There is an optional space
                    if (argv.length() == 1)
                    {
                        argNo++;
                        if (argNo >= args.length)
                        {
                            out.println(
                            getStringX("MSG_NoInputFile"));
                            return CMD_FAIL;
                        }
                        inFile = args[argNo];
                    }
                    else
                    {
                        inFile = argv.substring(1);
                    }
                    
                    if (inFile.compareTo("%stdin") == 0) {	// NOI18N
                        in = System.in;
                        interactiveMode = true;
                    }
                    else {
                        interactiveMode = false;
                        try {
                            in = new FileInputStream(inFile);
                        }
                        catch (FileNotFoundException fnf) {
                            out.println(
                            getStringX("MSG_NoInputScript", inFile));
                            printException(_methodName, fnf);
                        }
                    }
                    argNo++;
                }
                else if (argv.startsWith("o"))	// NOI18N
                {
                    String	fname;
                    
                    // There is an optional space
                    if (argv.length() == 1)
                    {
                        argNo++;
                        if (argNo >= args.length)
                        {
                            out.println(
                            getStringX("MSG_NoOutputFile"));
                            return CMD_FAIL;
                        }
                        fname = args[argNo];
                    }
                    else
                    {
                        fname = argv.substring(1);
                    }
                    
                    argNo++;
                    
                    // Open output file to record results
                    if (fname != null) {
                        if (fname.compareTo("%stdout") == 0) {	// NOI18N
                            out = System.out;
                        }
                        else {
                            try {
                                out = new PrintStream(new FileOutputStream(fname));
                                // NOTE: we don't also do System.setOut
                                // here so that stdOut trace messages go
                                // to this stream because there are
                                // currently many modules that print stuff
                                // to stdOut that can vary from
                                // run-to-run, and we don't want that
                                // showing up in test reference files.
                                // Instead we'll add outStrm as a logger stream
                                // in the main() program.
                                //
                                // This also follows the SynerJ model,
                                // where stdOut doesn't go to the -o file.
                                // If you want output to go to that file,
                                // use the logger or out
                                // directly.
                                // (roger blumer 10-may-2000)
                            }
                            catch (FileNotFoundException fnf) {
                                out.println(getStringX("MSG_NoInputScript", fname));
                                printException(_methodName, fnf);
                            }
                        }
                    }
                }
                else if (argv.startsWith("D"))	// NOI18N
                {
                    // argument should be -Daaaa.bbb.ccc=value
                    String propName;
                    String propValue;
                    
                    int eqSign = argv.indexOf('=');
                    if (eqSign <= 0) {
                        out.println(
                        getStringX("MSG_InvalidProperty", argv));
                    }
                    else {
                        propName  = argv.substring(1, eqSign);
                        propValue = argv.substring(eqSign+1);
                        System.setProperty (propName, propValue);
                    }
                    argNo++;
                }
                else if (argv.startsWith("fp"))	// NOI18N
                {
                    String	fname;
                    
                    // There is an optional space
                    if (argv.length() == 2)
                    {
                        argNo++;
                        if (argNo >= args.length)
                        {
                            out.println(
                            getStringX("MSG_NoPropFile"));
                            return CMD_FAIL;
                        }
                        fname = args[argNo];
                    }
                    else
                    {
                        fname = argv.substring(2);
                    }
                    
                    argNo++;
                    
                    loadPropertyFile(fname);
                }
                else if (argv.equals("e"))	// NOI18N
                {
                    // load environment variables from the file
		    // specified by netbeans.osenv
                    //
                    String  fname;
                    fname = System.getProperty("netbeans.osenv");    //NOI18N
                    /* XXX will not work until \0-parsing supported
		    if (fname != null)
			loadPropertyFile(fname);
                    */
                    argNo++;
                }
                else if (argv.equals("noload")) 	// NOI18N
                {
                    load = false;	// don't auto-load TopManager & modules
                    argNo++;
                }
                else
                {
                    //
                    // The meaning of this argument is unknown to this class,
                    // but our superclass may know about it. Add it to the array
                    // to be passed to the superclass.
                    //
                    newArgs.add(argvOrig);
                    argNo++;
                }
            }
            else
            {
                //
                // The meaning of this argument is unknown to this class,
                // but our superclass may know about it. Add it to the array
                // to be passed to the superclass.
                //
                newArgs.add(argvOrig);
                argNo++;
            }
        }
        
        // if any extra args were found, have NonGui superclass handle them.
        // Call its method in any case, since we want it to dump Info.
        //
        int size = newArgs.size();
        String[] tmpArgs = new String[size];
        
        if (size > 0) {
            for (int i = 0; i < newArgs.size(); i++) {
                tmpArgs[i] = (String) newArgs.get(i);
            }
        }
	// if we are starting the GUI (e.g. for running Jemmy tests),
	// pass the args to Main.main, rather than NonGui.main.
	//
	if (startGui) {
	    startGui(tmpArgs);
        } else {
            new CLIOptions().cli(tmpArgs);
            CLIOptions.initialize();
        }
        
        if (showInfo) {
            info();
        }
        return CMD_OK;
    }
    
    /** Starts the GUI TopManager */
    static void startGui( String [] args ) throws Exception {
	//
        // set the TopManager implementation to the GUI main
	// 
        System.getProperties().put (
            "org.openide.TopManager", // NOI18N
            "org.netbeans.core.Main" // NOI18N
            );
	//
	// set the property to skip the Welcome screen & auto-update checks.
	// These are modal & will stop batch scripts from running.
	// 
	System.getProperties().put("netbeans.full.hack", "true");  // NOI18N
	    
        org.netbeans.core.startup.Main.main(args);	
    }


    /** Parses command line arguments and calls runInterpreter. */
    public static void main( String [] args ) throws Exception {
        // set the default TopManager implementation to ME
        System.getProperties().put(
        "org.openide.TopManager", // NOI18N
        "org.netbeans.core.NonGuiMain" // NOI18N
        );
        
        if (processArgs(args) == CMD_FAIL) {
            showHelp2();
            TopSecurityManager.exit(0);
        }
        
        // FIX ME: this Font line (from Main.java) seems to prime Swing on Solaris
        // just enough to get around a NullPointerException during startup
        //
        new java.awt.Font ("Dialog", java.awt.Font.PLAIN, CLIOptions.getFontSize ()); // NOI18N
        
        if (load) {
//            org.openide.TopManager.getDefault();
            NbTopManager.get();
        }
        
        /*
        try {
            // try to load the interpreter
            if (load) {
                interpreter = ScriptType.find(interpName);
            }
            if (interpreter == null) {
                out.println(interpName + " cannot be loaded."); // NOI18N
                myExit(1);
            }
            
            showStatusLine = true;
            showNotifyText = true;
            
            runInterpreter(new InputStreamReader(in));
        }
        catch (Exception e  /* e.g. bsh.EvalError * / ) {
            printException(_methodName, e);
            myExit(1);
        }
        showStatusLine = false;
         */
        myExit(0);
    }
    
    /** Runs the interpreter - it behaves according to
     * interactive mode: interactive == true means reads every lines of input
     * and processing them separately. If interactive == false it reads the
     * whole input in one big shot.
     * /
    public static void runInterpreter(Reader in) {
        try {
            if (interactiveMode) {
                // read each line and execute it
                BufferedReader br = new BufferedReader(in);
                String line = null;
                out.print(PROMPT + "(" + interpName + ") > "); // NOI18N
                while ( ((line = br.readLine()) != null) && (!line.equals("exit"))) { // NOI18N
                    try { // in this case we try to recover
                        interpreter.exec(line);
                        out.print("\n" + PROMPT + "(" + interpName + ") > "); // NOI18N
                    } catch (InvocationTargetException ite) {
                        printException("target exception: ", ite.getTargetException()); // NOI18N
                    }
                }
            } else {
                try {
                    // in non interactive mode the whole stream is evaluated at once
                    interpreter.exec(in);
                } catch (InvocationTargetException ite) {
                    // here just print and exit
                    printException("target exception: ", ite.getTargetException()); // NOI18N
                }
            }
        } catch (java.io.IOException e) {
            printException("runInterpreter exception: ", e); // NOI18N
        }
    }
     */
    
    /** Calls TopManager.getDefault().exit(); */
    public static void myExit(int status) {
	if (NbTopManager.isInitialized()) {
	    
//            TopManager.getDefault().exit();
            org.openide.LifecycleManager.getDefault().exit();
        }
        TopSecurityManager.exit(status);
    }
    
   /** Getter for a text from resource.
    * @param resName resource name
    * @return string with resource
    */
    static String getStringX (String resName) {
        return NbBundle.getBundle (NonGuiMain.class).getString (resName);
    }
    
   /** Getter for a text from resource with one argument.
    * @param resName resource name
    * @return string with resource
    * @param arg the argument
    */
    static String getStringX (String resName, Object arg) {
        MessageFormat mf = new MessageFormat (getStringX (resName));
        return mf.format (new Object[] { arg });
    }
    
    static String getStringX (String resName, Object arg1, Object arg2) {
        MessageFormat mf = new MessageFormat (getStringX (resName));
        return mf.format (new Object[] { arg1, arg2 });
    }
    
    private static void printException(String methodName, Throwable exc) {
        out.println(getStringX("MSG_ExceptionIn", methodName)); // NOI18N
        exc.printStackTrace(out);
    }
    
    /*
    public InputOutput getIO(String name, boolean newIO) {
        if (inout == null) {
            inout = new StandardStreamInputOutput(name, in, out); 
        }
        return inout;
    }
    
    public OutputWriter getStdOut () {
        return getIO("", true).getOut();	// NOI18N
    }
     */

    /** Prints the notification to the out.*/
    public Object notify(NotifyDescriptor n) {
	if (!showNotifyText)
	    return NotifyDescriptor.CLOSED_OPTION;

	Object msg = n.getMessage();
	String display = null;

	if (msg instanceof TextComponent) {
	    display = ((TextComponent)msg).getText();
	} else if (msg instanceof JTextComponent) {
	    display = ((JTextComponent)msg).getText();
	} else if (msg instanceof Component) {
	    try {
		Method getText = msg.getClass().getMethod("getText", null); // NOI18N
		Object rval;

		rval = getText.invoke(msg, null);
		if (rval instanceof String) {
		    display = (String) rval;
		} else if (rval instanceof String[]) {
		    String[] arr = (String[])rval;

		    //
		    // The EJB code returns this.
		    //
		    out.println("NOTIFICATION:"); // NOI18N
		    for (int i = 0; i < arr.length; i++) {
			out.println("\t" + arr[i]); // NOI18N
		    }
		    return NotifyDescriptor.CLOSED_OPTION;
		}
	    } catch (Exception e) {
		display = msg.toString();
	    }
	} else {
	    display = msg.toString();
	}
        out.println("NOTIFICATION: " + display); // NOI18N
        return NotifyDescriptor.CLOSED_OPTION;
    }
    
    /** Prints the text to the out.*/
    protected void setStatusTextImpl(String text) {
        if (showStatusLine)
            out.println("STATUS LINE : " + text); // NOI18N
    }
    
    /** Controls display of the status line text.*/
    public static boolean showStatusLine(boolean val) {
        boolean oldVal = showStatusLine;
        showStatusLine = val;
        return oldVal;
    }

    /** Controls display of the notify text.*/
    public static boolean showNotifyText(boolean val) {
        boolean oldVal = showNotifyText;
        showNotifyText = val;
        return oldVal;
    }

    /** Browse a document over HTTP.
     * @param url URL of WWW document to be shown
     */
    public void showUrl(URL url) {
        try {
            out.println("SHOW URL " + url.toString()+ " START: "); // NOI18N
            InputStream is = url.openStream();
            FileUtil.copy(is, out);
            out.println("SHOW URL - END"); // NOI18N
        } catch (IOException ex) {
            out.println("Exception in showUrl: " + ex.getMessage()); // NOI18N
        }
    }

    public static int loadPropertyFile (String fileName) {
        final String methodName = "NonGuiMain.loadPropertyFile"; // NOI18N

	// If we want to keep the properties loaded here
	// SEPARATE from the system properties, we could
	// create our own Property object here OR use the
	// one in scripting/.../NavigationSupport. (Or we
	// could have the one in NavigationSupport use one
	// from here instead of its own, in order to share
	// the loaded properties & make them available for
	// NavigationSupport.expandVars().)
	//

        Exception exc = null;

        if (fileName != null) {
            try {
                FileInputStream fis = null;
                fis = new FileInputStream(fileName);
                System.getProperties().load(fis);
            }
            catch (FileNotFoundException e) {
                exc = e;
                out.println(
                    NbBundle.getMessage(NonGuiMain.class, "MSG_NoPropFile", fileName));
                printException(methodName, e);
            }
            catch (IOException e) {
                exc = e;
                out.println(
                    NbBundle.getMessage(NonGuiMain.class, "MSG_IOPropFile", fileName));
                printException(methodName, e);
            }
            catch (IllegalArgumentException e) {
                exc = e;
                out.println(
                    NbBundle.getMessage(NonGuiMain.class, "MSG_ErrPropFile", fileName));
                printException(methodName, e);
            }
            if (exc != null)
                return CMD_FAIL;
        }
        return CMD_OK;
    }

    // ---- COPIED FROM org.openidex.windows.StandardStreamInputOutput ----

/** Implementation of InputOutput that uses regular
 * InputStream and OutputStream to perform the IO operation.
 * @author David Strupl
 * /
private static class StandardStreamInputOutput implements InputOutput {
    /** Closing state. * /
    private boolean isClosed;
    /** Reader created from the InputStream in.* /
    private Reader  reader;
    /** OutputWriter created from out* /
    private MyOutputWriter myOut;
    /** Parameter * /
    private InputStream in;
    /** Parameter * /
    private OutputStream out;
    /** Name fo the tab - used for printing the messages.* /
    private String name;
    
    /** The only public constructor - all parameters are required.* /
    public StandardStreamInputOutput(String name,InputStream in,OutputStream out) {
        this.isClosed = false;
        this.in = in;
        this.out = out;
        this.name = name;
    }
    
    /** Lazy initialization of myOut.* /
    public OutputWriter getOut() {
        if (myOut == null) {
            myOut = new MyOutputWriter(new PrintWriter(out));
        }
        return myOut;
    }
    
    /** Lazy initiliazation of reader.* /
    public Reader getIn() {
        if (reader == null) {
            reader = new InputStreamReader(in);
        }
        return reader;
    }
    
    /** Does the same as getOut --- sets myOut if it was null.* /
    public OutputWriter getErr() {
        if (myOut == null) {
            myOut = new MyOutputWriter(new PrintWriter(out));
        }
        return myOut;
    }
    
    /** Just sets isClosed to true.* /
    public void closeInputOutput() {
        isClosed = true;
    }
    
    /** Returns the close state.* /
    public boolean isClosed() {
        return isClosed;
    }
    
    /** Does nothing. * /
    public void setOutputVisible(boolean value) {
    }
    
    /** Does nothing. * /
    public void setErrVisible(boolean value) {
    }
    
    /** Does nothing. * /
    public void setInputVisible(boolean value){
    }
    
    /** Does nothing. * /
    public void select () {
    }
    
    /** Returns true. * /
    public boolean isErrSeparated() {
        return true;
    }
    
    /** Does nothing. * /
    public void setErrSeparated(boolean value) {
    }
    
    public boolean isFocusTaken() {
        return true;
    }
    
    /** Does nothing. * /
    public void setFocusTaken(boolean value) {
    }
    
    /** Does nothing. * /
    public Reader flushReader() {
        return reader;
    }
    
    /** OutputWriter that overrides method println to print
     * name
     * /
    class MyOutputWriter extends OutputWriter {
        
        /** Just calls super(out);* /
        MyOutputWriter(PrintWriter out) {
            super(out);
        }
        
        /** Prints the oubput and calls flush. * /
        public void println(java.lang.String s, OutputListener l) {
            println(name + " OUTPUT : " + s); // NOI18N
            flush();
        }
        
        /** Does nothing.* /
        public void reset() {
        }
    }
}
*/

}
