/*
 * 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;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.morilib.sh.ShTreeExpressionMachine.Builder;
import net.morilib.sh.builtin.ShBuiltInCommands;
import net.morilib.sh.misc.IOs;
import net.morilib.sh.misc.XtraceStream;
import net.morilib.unix.misc.OptionIterator;

public class ShTreeSh implements ShTree {

	private List<ShToken> args;

	//
	ShTreeSh(List<ShToken> args) {
		this.args = args;
	}

	public void compileInternally(Builder b, Object brk, Object cnt) {
		b.add(this);
	}

	private void _setarg(ShEnvironment n, Iterator<String> a) {
		for(int i = 1; a.hasNext(); i++) {
			n.put(i + "", a.next());
		}
	}

	public int eval(ShEnvironment env, ShFileSystem fs,
			ShBuiltInCommands cmds, ShRuntime run,
			InputStream in, PrintStream out, PrintStream err,
			XtraceStream pr) throws IOException, ShSyntaxException {
		List<String> l = new ArrayList<String>();
		InputStream ins = null;
		Iterator<String> a;
		OptionIterator o;
		ShEnvironment n;
		String s;

		n = new ShRootShellEnvironment(env.getEnvironment());
		for(ShToken t : args) {
			l.add(ShTrees.substitute(env, run, fs, err, pr, t));
		}

		try {
			o = new OptionIterator("Cfnuvxo:c:s", true, l);
			while(o.hasNext()) {
				switch(o.nextChar()) {
				case 'C':  n.set("noclobber", !o.isPlus());  break;
				case 'f':  n.set("noglob", !o.isPlus());  break;
				case 'n':  n.set("noexec", !o.isPlus());  break;
				case 'u':  n.set("nounset", !o.isPlus());  break;
				case 'v':  n.set("verbose", !o.isPlus());  break;
				case 'x':  n.set("xtrace", !o.isPlus());  break;
				case 'c':
					s = o.getArgument();
					a = o.filenameIterator();
					_setarg(n, a);
					return run.eval(n, fs, in, out, err, pr, s);
				case 's':
					s = o.getArgument();
					a = o.filenameIterator();
					_setarg(n, a);
					return Sh.interactive(n, fs, cmds, run, in, out,
							err, pr, new ShPromptReader(in, env, pr));
				}
			}

			// execute .jshrc file
			Sh.execute(n, fs, cmds, run, fs.getRc(), ins, out, err,
					pr);

			// execute
			a = o.filenameIterator();
			if(a.hasNext()) {
				try {
					s   = a.next();
					ins = fs.getFile(s).getInputStream();
					s   = IOs.toString(new InputStreamReader(ins));
					_setarg(n, a);
					return run.eval(n, fs, in, out, err, pr, s);
				} finally {
					if(ins != null)  ins.close();
				}
			} else {
				return Sh.interactive(
						env, fs, cmds, run, in, out, err, pr);
			}
		} catch(IOException e) {
			if((s = env.getTrap(ShSignal.IO)) != null) {
				try {
					ShRuntime.getInstance().eval(env, fs, in,
							out, err, pr, s);
				} catch(ShCommandNotFoundException e1) {
					err.print(Sh.NAME);
					err.print(": command not found: ");
					err.println(e1.getName());
				}
				return 72;
			} else {
				throw e;
			}
		} finally {
			if((s = env.getTrap(ShSignal.EXIT)) != null) {
				run.eval(env, fs, in, out, err, pr, s);
			}
		}
	}

}
