/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.sh.file;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;

import net.morilib.sh.ShEnvironment;
import net.morilib.sh.ShFileSystem;
import net.morilib.sh.ShProcess;

public class ShOSProcess implements ShProcess {

	private static final int BUFSIZE = 1024;

	static class BException extends RuntimeException {

		IOException ioex;

		public BException(IOException t) {
			ioex = t;
		}

	}

	static class InThread extends Thread {

		private InputStream src;
		private OutputStream dest;

		InThread(InputStream src, OutputStream dest) {
			this.src  = src;
			this.dest = dest;
		}

		public void run() {
			byte[] b = new byte[BUFSIZE];
			int l;

			try {
				while((l = src.read(b)) >= 0) {
					dest.write(b, 0, l);
				}
			} catch (IOException e) {
				throw new BException(e);
			}
		}

	};

	private ProcessBuilder builder;

	public ShOSProcess(ProcessBuilder builder) {
		this.builder = builder;
	}

	public int main(ShEnvironment env,  ShFileSystem fs,
			InputStream stdin, PrintStream stdout,
			PrintStream stderr, String... args) throws IOException {
		InThread ot = null, er = null;

		try {
			Process p = builder.start();
			ot = new InThread(p.getInputStream(), stdout);
			er = new InThread(p.getInputStream(), stdout);

			ot.start();  er.start();
			return p.waitFor();
		} catch(BException ex) {
			throw ex.ioex;
		} catch (InterruptedException e) {
			return 255;
		} finally {
			try {
				if(ot != null)  ot.join();
				if(er != null)  er.join();
				stdout.flush();
				stderr.flush();
			} catch (InterruptedException e) {
				return 255;
			}
		}
	}

}
