/*
 * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
 *
 * This software is distributable under the BSD license. See the terms of the
 * BSD license in the documentation provided with this software.
 */

package jline.internal;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.StringTokenizer;

/**
 * Provides access to terminal line settings via <tt>stty</tt>.
 *
 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
 * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
 * @since 2.0
 */
public final class TerminalLineSettings
{
    public static final String JLINE_STTY = "jline.stty";

    public static final String DEFAULT_STTY = "stty";

    public static final String JLINE_SH = "jline.sh";

    public static final String DEFAULT_SH = "sh";

    private static String sttyCommand = System.getProperty(JLINE_STTY, DEFAULT_STTY);

    private static String shCommand = System.getProperty(JLINE_SH, DEFAULT_SH);

    private String config;

    public TerminalLineSettings() throws IOException, InterruptedException {
        config = get("-g");

        Log.debug("Config: ", config);

        // sanity check
        if (config.length() == 0 || (!config.contains("=") && !config.contains(":"))) {
            throw new IOException(MessageFormat.format("Unrecognized stty code: {0}", config));
        }
    }

    public String getConfig() {
        return config;
    }

    public void restore() throws IOException, InterruptedException {
        set("sane");
    }

    public String get(final String args) throws IOException, InterruptedException {
        return stty(args);
    }

    public void set(final String args) throws IOException, InterruptedException {
        stty(args);
    }

    public int getProperty(final String name) {
        assert name != null;

        try {
            // need to be able handle both output formats:
            // speed 9600 baud; 24 rows; 140 columns;
            // and:
            // speed 38400 baud; rows = 49; columns = 111; ypixels = 0; xpixels = 0;
            String props = get("-a");

            for (StringTokenizer tok = new StringTokenizer(props, ";\n"); tok.hasMoreTokens();) {
                String str = tok.nextToken().trim();

                if (str.startsWith(name)) {
                    int index = str.lastIndexOf(" ");
                    return Integer.parseInt(str.substring(index).trim());
                }
                else if (str.endsWith(name)) {
                    int index = str.indexOf(" ");
                    return Integer.parseInt(str.substring(0, index).trim());
                }
            }
        }
        catch (Exception e) {
            Log.warn("Failed to query stty ", name, e);
        }

        return -1;
    }

    private static String stty(final String args) throws IOException, InterruptedException {
        assert args != null;
        return exec(String.format("%s %s < /dev/tty", sttyCommand, args));
    }

    private static String exec(final String cmd) throws IOException, InterruptedException {
        assert cmd != null;
        return exec(shCommand, "-c", cmd);
    }

    private static String exec(final String... cmd) throws IOException, InterruptedException {
        assert cmd != null;

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        Log.trace("Running: ", cmd);

        Process p = Runtime.getRuntime().exec(cmd);
        int c;

        InputStream in = p.getInputStream();

        while ((c = in.read()) != -1) {
            out.write(c);
        }

        in = p.getErrorStream();

        while ((c = in.read()) != -1) {
            out.write(c);
        }

        p.waitFor();

        String result = new String(out.toByteArray());

        Log.trace("Result: ", result);

        return result;
    }
}
@@ -3581,24 +3581,25 @@
 c(cmd);%0A
+%0A
         
 int c;%0A%0A
@@ -3594,35 +3594,107 @@
     
-int c;%0A%0A        InputStream
+InputStream in = null;%0A        InputStream err = null;%0A        try %7B%0A            int c;%0A           
  in 
@@ -3707,33 +3707,36 @@
 tInputStream();%0A
-%0A
+    
         while ((
@@ -3751,32 +3751,36 @@
 ead()) != -1) %7B%0A
+    
             out.
@@ -3789,34 +3789,37 @@
 ite(c);%0A        
+    
 %7D
-%0A
 %0A        in = p.
@@ -3803,34 +3803,39 @@
       %7D%0A        
-in
+    err
  = p.getErrorStr
@@ -3833,33 +3833,36 @@
 tErrorStream();%0A
-%0A
+    
         while ((
@@ -3857,34 +3857,35 @@
     while ((c = 
-in
+err
 .read()) != -1) 
@@ -3890,32 +3890,36 @@
 ) %7B%0A            
+ 
+   
 out.write(c);%0A  
@@ -3916,35 +3916,42 @@
 ite(c);%0A        
-%7D%0A%0A
+    %7D%0A    
         p.waitFo
@@ -3954,16 +3954,291 @@
 itFor();
+%0A        %7D finally %7B%0A            try %7B%0A                in.close();%0A            %7D catch (Exception e) %7B%0A                // Ignore%0A            %7D%0A            try %7B%0A                err.close();%0A            %7D catch (Exception e) %7B%0A                // Ignore%0A            %7D%0A        %7D
 %0A%0A      

Fix lazy "leak" of streams during stty/exec logic for UnixTerminal.