package net.morilib.sh;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

import net.morilib.sh.misc.IOs;
import net.morilib.sh.misc.XtraceStream;

import junit.framework.TestCase;

public class ShCommandExecuteTest extends TestCase {

	protected PipedOutputStream pow, pew, qiw;
	protected PipedInputStream pir, qor;
	protected PrintWriter piw;
	protected BufferedReader por, per;
	protected ShEnvironment env;
	protected ShFileSystem fs;
	protected ShRootEnvStub rev;

	protected PrintWriter i0w;
	protected BufferedReader o1r, o2r;

	protected void setUp() {
		try {
			pir = new PipedInputStream();
			pow = new PipedOutputStream();
			pew = new PipedOutputStream();
			piw = new PrintWriter(qiw = new PipedOutputStream(pir));
			por = new BufferedReader(new InputStreamReader(
					qor = new PipedInputStream(pow)));
			per = new BufferedReader(new InputStreamReader(
					new PipedInputStream(pew)));
			fs  = new ShFileSystemStub();

			ShFileSystemStub.in   = new PipedInputStream();
			ShFileSystemStub.out1 = new PipedOutputStream();
			ShFileSystemStub.out2 = new PipedOutputStream();
			ShFileSystemStub.pout1 = new PrintStream(ShFileSystemStub.out1);
			ShFileSystemStub.pout2 = new PrintStream(ShFileSystemStub.out2);
			i0w = new PrintWriter(new PipedOutputStream(
					ShFileSystemStub.in));
			o1r = new BufferedReader(new InputStreamReader(
					new PipedInputStream(ShFileSystemStub.out1)));
			o2r = new BufferedReader(new InputStreamReader(
					new PipedInputStream(ShFileSystemStub.out2)));

			rev = new ShRootEnvStub();
			env = new ShRootShellEnvironment(rev);
			env.put("IFS", " ");
			env.put("0", "sh-test");
		} catch(IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected void eot(String s) {
		try {
			if(!por.ready())  fail();
			assertEquals(s, por.readLine());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected void eet(String s) {
		try {
			if(!per.ready())  fail();
			assertEquals(per.readLine(), s);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected void eot() {
		try {
			if(por.ready())  assertNull(por.readLine());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected void eet() {
		try {
			if(per.ready())  assertNull(per.readLine());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected void eot(BufferedReader por, String s) {
		try {
			if(!por.ready())  fail();
			assertEquals(por.readLine(), s);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected void eot(BufferedReader por) {
		try {
			if(por.ready())  assertNull(por.readLine());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected void exe(String s, int r) {
		String t;

		try {
			assertEquals(r, ShRuntime.getInstance().eval(
					env,
					fs,
					pir,
					new PrintStream(pow, true, env.getCharset().toString()),
					new PrintStream(pew, true, env.getCharset().toString()),
					new XtraceStream(IOs.NULL_OUTPUT),
					s));
		} catch(IOException e) {
			if((t = env.getTrap(ShSignal.IO)) == null) {
				throw new RuntimeException(e);
			}

			try {
				ShRuntime.getInstance().eval(
						env,
						fs,
						pir,
						new PrintStream(pow, true, env.getCharset().toString()),
						new PrintStream(pew, true, env.getCharset().toString()),
						new XtraceStream(IOs.NULL_OUTPUT),
						t);
			} catch (IOException e1) {
				throw new RuntimeException(e);
			} catch (ShSyntaxException e1) {
				throw new RuntimeException(e);
			}
		} catch(ShSyntaxException e) {
			throw new RuntimeException(e);
		} catch(ShExitException e) {
			assertEquals(r, e.getCode());
		} finally {
			try {
				ShFileSystemStub.out1.flush();
				ShFileSystemStub.out2.flush();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	protected void exc(String s, int r) {
		String t;

		try {
			assertEquals(r, ShRuntime.getInstance().eval(
					env,
					fs,
					pir,
					new PrintStream(pow, true, env.getCharset().toString()),
					new PrintStream(pew, true, env.getCharset().toString()),
					new XtraceStream(IOs.NULL_OUTPUT),
					s));
		} catch(IOException e) {
			if((t = env.getTrap(ShSignal.IO)) == null) {
				throw new RuntimeException(e);
			}

			try {
				ShRuntime.getInstance().eval(
						env,
						fs,
						pir,
						new PrintStream(pow, true, env.getCharset().toString()),
						new PrintStream(pew, true, env.getCharset().toString()),
						new XtraceStream(IOs.NULL_OUTPUT),
						t);
			} catch (IOException e1) {
				throw new RuntimeException(e);
			} catch (ShSyntaxException e1) {
				throw new RuntimeException(e);
			}
		} catch(ShSyntaxException e) {
			throw new RuntimeException(e);
		} catch(ShExitException e) {
			assertEquals(r, e.getCode());
		} finally {
			try {
				pow.close();
				pew.close();
				ShFileSystemStub.out1.flush();
				ShFileSystemStub.out2.flush();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	protected void err(String s, int r) {
		String t;

		try {
			ShRuntime.getInstance().eval(
					env,
					fs,
					pir,
					new PrintStream(pow, true, env.getCharset().toString()),
					new PrintStream(pew, true, env.getCharset().toString()),
					new XtraceStream(IOs.NULL_OUTPUT),
					s);
			fail();
		} catch(IOException e) {
			if((t = env.getTrap(ShSignal.IO)) == null) {
				throw new RuntimeException(e);
			}

			try {
				ShRuntime.getInstance().eval(
						env,
						fs,
						pir,
						new PrintStream(pow, true, env.getCharset().toString()),
						new PrintStream(pew, true, env.getCharset().toString()),
						new XtraceStream(IOs.NULL_OUTPUT),
						t);
			} catch (IOException e1) {
				throw new RuntimeException(e);
			} catch (ShSyntaxException e1) {
				throw new RuntimeException(e);
			}
		} catch(ShSyntaxException e) {
			throw new RuntimeException(e);
		} catch(ShRuntimeException e) {
			// OK
		} catch(ShExitException e) {
			assertEquals(r, e.getCode());
		} finally {
			try {
				ShFileSystemStub.out1.flush();
				ShFileSystemStub.out2.flush();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	protected void ers(String s, int r) {
		String t;

		try {
			ShRuntime.getInstance().eval(
					env,
					fs,
					pir,
					new PrintStream(pow, true, env.getCharset().toString()),
					new PrintStream(pew, true, env.getCharset().toString()),
					new XtraceStream(IOs.NULL_OUTPUT),
					s);
			fail();
		} catch(IOException e) {
			if((t = env.getTrap(ShSignal.IO)) == null) {
				throw new RuntimeException(e);
			}

			try {
				ShRuntime.getInstance().eval(
						env,
						fs,
						pir,
						new PrintStream(pow, true, env.getCharset().toString()),
						new PrintStream(pew, true, env.getCharset().toString()),
						new XtraceStream(IOs.NULL_OUTPUT),
						t);
			} catch (IOException e1) {
				throw new RuntimeException(e);
			} catch (ShSyntaxException e1) {
				throw new RuntimeException(e);
			}
		} catch(ShSyntaxException e) {
			// OK
		} catch(ShExitException e) {
			assertEquals(r, e.getCode());
		} finally {
			try {
				ShFileSystemStub.out1.flush();
				ShFileSystemStub.out2.flush();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	protected void redef(PipedOutputStream qiw, String cd) {
		try {
			piw = new PrintWriter(new OutputStreamWriter(qiw, cd));
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	protected void redef(PipedInputStream qor, String cd) {
		try {
			por = new BufferedReader(new InputStreamReader(
					qor, cd));
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

}
