package railo.commons.cli;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import railo.commons.io.IOUtil;
import railo.commons.io.SystemUtil;
import railo.commons.lang.StringUtil;

public class Command {
    
    public static Process createProcess(String cmdline,boolean translate) throws IOException {
    	if(!translate)return Runtime.getRuntime().exec(cmdline);
    	return Runtime.getRuntime().exec(toArray(cmdline));
    }
	
    /**
     * @param cmdline command line
     * @param translate translate the command line or not
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    public static CommandResult execute(String cmdline,boolean translate) throws IOException, InterruptedException {
    	if(!translate)return execute(Runtime.getRuntime().exec(cmdline));
    	return execute(Runtime.getRuntime().exec(toArray(cmdline)));
    }
    
	public static CommandResult execute(String[] cmdline) throws IOException, InterruptedException {
		return execute(Runtime.getRuntime().exec(cmdline));
    }
    public static CommandResult execute(String cmd,String[] args) throws IOException, InterruptedException {
    	return execute(StringUtil.merge(cmd,args));
    }

    public static CommandResult execute(Process p) throws IOException, InterruptedException {
    	InputStream is=null;
    	InputStream es=null;
    	IOException ioe;
	    try {
	    	StreamGobbler in=new StreamGobbler(is=p.getInputStream());
	    	StreamGobbler err=new StreamGobbler(es=p.getErrorStream());
	    	in.start();
	    	err.start();
    		if(p.waitFor()!=0){
    			err.join();
    			if((ioe=err.getException())!=null) throw ioe;
    			String str=err.getString();
    			if(!StringUtil.isEmpty(str))
    				throw new CommandException(str);
	        }
    		in.join();
    		if((ioe=in.getException())!=null) throw ioe;

			return new CommandResult( in.getString(), err.getString() );
    	}
    	finally {
    		IOUtil.closeEL(is);
    		IOUtil.closeEL(es);
    	}
    }
    
    


    private static String[] toArray(String str) {
    	if(StringUtil.isEmpty(str)) return new String[]{""};
    	str=str.trim();
    	StringBuilder sb=new StringBuilder();
    	ArrayList<String> list=new ArrayList<String>();
		char[] carr = str.toCharArray();
		char c;//,last=0;
		char inside=0;
		for(int i=0;i<carr.length;i++){
			c=carr[i];
			//if(i>0)last=carr[i-1];
			switch(c){
		// DELIMITER
			/*case '\\':	
				if(i+1<carr.length){
					sb.append(carr[++i]);
				}
				else sb.append(c);
				break;*/
		// QUOTE
			case '\'':
			case '"':
				if(inside==0){
					if(str.lastIndexOf(c)>i)
						inside=c;
					else
						sb.append(c);
				}
				else if(inside==c) {
					inside=0;
				}
				else sb.append(c);
			break;
		// WHITE SPACE
			case ' ':
			case '\b':
			case '\t':
			case '\n':
			case '\r':
			case '\f':
				//if(last=='\\')sb.setCharAt(sb.length()-1,c);
				if(inside==0) {
					populateList(sb,list);
				}
				else sb.append(c);
				break;
		// OTHERS
			default:
					sb.append(c);
			}
		}
		populateList(sb, list);
		
		
    	return  list.toArray(new String[list.size()]);
	}
    
    private static void populateList(StringBuilder sb, ArrayList<String> list) {

		String tmp = sb.toString();
		tmp=tmp.trim();
		if(tmp.length()>0)list.add(tmp);
		sb.delete(0, sb.length());
	}
}


class StreamGobbler extends Thread {
  

	InputStream is;
	private String str;
	private IOException ioe;
    
    StreamGobbler(InputStream is)	{
        this.is = is;
    }
    
    @Override
    public void run() {
        try {
			str=IOUtil.toString(is,SystemUtil.getCharset());
		} catch (IOException ioe) {
			this.ioe=ioe;
		}  
    }
    
    /**
	 * @return the str
	 */
	public String getString() {
		return str;
	}

	/**
	 * @return the ioe
	 */
	public IOException getException() {
		return ioe;
	}
	
}