package ch.wlkl.shell;

import java.util.ArrayList;

/**
 * 
 * the singleton in our environment {@link #envMan()}
 * <ul>
 * <li>keeps the current (top) environment: {@link #env()}, {@link #env(Object, Object)}
 * <li>maintains the stack of environments: {@link #push(Env)}, {@link #pop()}
 * <li>implements pipes: {@link #barBegin()}, {@link #bar()}, {@link #barLast()}, {@link #barEnd()}
 * <li>keeps the global loader {@link #loader()} and related utility functions {@link #compile(char)}, {@link #run(String)}
 * </ul>
 * @author walter keller
 *
 */
public class EnvMan extends Top {

	@SuppressWarnings("unchecked")
	public final static EnvMan envMan = new EnvMan(new Env<String, String>("<£", new Buf<String>(), ">" + Cat.eNoOpenClose + "£", new Say<String>("rootSay: ")));

	public final ArrayList<Env<?, ?>> envStack = new ArrayList<Env<?, ?>>();
	private Env<?, ?> topEnv = null;
	private JavaCmpLoad<Run> loader = new JavaCmpLoad<Run>(null, Run.class);

	public EnvMan(Env<?, ?> root) {
		push(root);
	}
	
	public static EnvMan envMan() {
		return  envMan;
	}

	@SuppressWarnings("unchecked")
	public static Env<String, String> env () {
		return (Env<String, String>)envMan.topEnv;
	}

	@SuppressWarnings("unchecked")
	public static <R, W> Env<R, W> env (R r, W w) {
		return (Env<R, W>)envMan.topEnv;
	}

	public Env<?, ?> top (int offs) {
		return envStack.get(envStack.size() - 1 - offs);
	}
	
	public <R, W> Env<R, W> push (Env<R, W> e) {
		envStack.add(e);
		e.link(topEnv);
		topEnv = e;
		return e;
	}
	
	public Read<?> pop () {
		Env<?, ?> old = envStack.remove(envStack.size() - 1);
		topEnv = envStack.get(envStack.size() - 1);
		return old.lazyOrClose();
	}
	
	public <W> Env<?, W> barBegin () {
		return push(Env.make((Env<?, W>) null, ">£", new Buf<W>()));
	}
	
	public <W> Env<?, W> bar() {
		return push(Env.make((Env<?, W>) null, "<£", pop(), ">£", new Buf<W>()));
	}

	public Env<?, ?> barLast() {
		return push(Env.make((Env<?, ?>) null, "<£", pop()));
	}
	
	public Env<?, ?> barEnd() {
		Read<?> old = pop();
		Env<?, ?> res = top(0);
		if (old != res.out)
			fail("barEnd but out != parent");
		return res;
	}
	
	public JavaCmpLoad<Run> loader() {
		return loader;
	}

	@SuppressWarnings("unchecked")
	public Run compile(char type) {
		return new Compiler(loader(), env((String) null, null).in()).compileInstance(type);
	}
	
	public void run(String name) {
		((Run) topEnv.get(name)).run();
	}
}

