/*
 * 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.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.morilib.sh.misc.XtraceStream;
import net.morilib.unix.glob.Wildcard;

public final class ShFiles {

	private static final Pattern PT   = Pattern.compile("/+");

	/**
	 * 
	 * @param system
	 * @return
	 */
	public static List<ShFile> glob(String filename,
			ShFileSystem fs) {
		List<ShFile> s = new ArrayList<ShFile>(), r;
		Wildcard w;
		String[] a;
		Matcher m;
		int p = 0;

		if(filename.length() == 0) {
			return Collections.emptyList();
		} else if((m = PT.matcher(filename)).lookingAt()) {
			r = Collections.singletonList(fs.getRoot());
			p = m.end();
		} else {
			r = Collections.singletonList(fs.getCurrentDirectory());
		}

		a = filename.substring(p).replaceFirst("/+$", "").split("/+");
		for(String t : a) {
			w = Wildcard.compile(t);
			s = new ArrayList<ShFile>();
			for(ShFile f : r)  s.addAll(f.getFiles());
			r = new ArrayList<ShFile>();
			for(ShFile f : s) {
				if(!f.isHidden() && w.matches(f.getName()))  r.add(f);
			}
		}
		return r;
	}

	/**
	 * 
	 * @param env
	 * @param fs
	 * @param cmds
	 * @param name
	 * @return
	 */
	public static ShProcess findCommand(ShEnvironment env,
			ShFileSystem fs,
			ShBuiltInCommands cmds,
			String name) {
		ShProcess p;
		ShFile f;

		if((p = cmds.find(name)) != null) {
			// find a built-in command
			return p;
		} else if((f = fs.searchPath(env, name)) != null &&
				(p = f.getProcess()) != null) {
			// find an OS command
			return p;
		} else {
			// TODO find a jar file
			return null;
		}
	}

	/**
	 * 
	 * @param env
	 * @param fs
	 * @param run
	 * @param r
	 * @param file
	 * @param stdin
	 * @param out
	 * @return
	 * @throws IOException
	 * @throws ShSyntaxException
	 */
	public static InputStream redirect(ShEnvironment env,
			ShFileSystem fs, ShRuntime run, ShRedirector r,
			ShToken file, InputStream stdin,
			PrintStream[] out,
			XtraceStream p) throws IOException, ShSyntaxException {
		InputStream in = stdin;
		String v;

		if(r.isFileRedirector()) {
			v = ShTrees.substituteCase(env, run, fs, out[2], p, file);
			switch(r.getType()) {
			case IN:
				switch(r.getFDSource()) {
				case 0:
					in = fs.getFile(v).getInputStream();  break;
				default:  throw new ShSyntaxException();
				}
				break;
			case OUT:
				if(env.isSet("noclobber")) {
					throw new ShRuntimeException();
				}
				// go next
			case APPEND:
				switch(r.getFDSource()) {
				case 1:
				case 2:
					out[r.getFDSource()] =
						fs.getFile(v).getPrintStream(r.isAppend());
					break;
				default:  throw new ShSyntaxException();
				}
				break;
			}
		} else if(r.isDescriptorCopier()) {
			if(r.getFDDestination() < 1 && r.getFDDestination() > 2) {
				throw new ShSyntaxException();
			} else if(r.getFDSource() < 1 && r.getFDSource() > 2) {
				throw new ShSyntaxException();
			} else if(r.getFDSource() != r.getFDDestination()) {
				out[r.getFDSource()] = out[r.getFDDestination()];
			} else {
				throw new ShSyntaxException();
			}
		} else if(r.isHereDocument()) {
			switch(r.getFDSource()) {
			case 0:
				v  = r.getDocument();
				v  = ShTrees.substituteCase(env, run, fs, out[2], p,
						new ShString(v));
				in = new ByteArrayInputStream(v.getBytes());
				break;
			default:  throw new ShSyntaxException();
			}
		} else {
			throw new RuntimeException();
		}
		return in;
	}

}
