/*
 * Copyright 2009-2010 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.lisp.nano.java6;

import java.io.Reader;
import java.io.Writer;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.SimpleBindings;

import net.morilib.lisp.nano.Datum;
import net.morilib.lisp.nano.Environment;
import net.morilib.lisp.nano.LispUtils;
import net.morilib.lisp.nano.Symbol;
import net.morilib.lisp.nano.SymbolName;

/**
 *
 *
 * @author MORIGUCHI, Yuichiro 2014/02/17
 */
public class SchlushScriptContext implements ScriptContext {

	//
	private Reader reader;
	private Writer writer, errwriter;
	Environment env;

	//
	SchlushScriptContext(Environment e) {
		env = new Environment(e);
	}

	private Environment _scope(int scope) {
		switch(scope) {
		case ENGINE_SCOPE:  return env;
		case GLOBAL_SCOPE:  return env.getRootenv();
		default:
			throw new IllegalArgumentException();
		}
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#setBindings(javax.script.Bindings, int)
	 */
	@Override
	public void setBindings(Bindings bindings, int scope) {
		Environment e;

		e = _scope(scope);
		for(Map.Entry<String, Object> t : bindings.entrySet()) {
			e.bindDatum(t.getKey(),
					LispUtils.toDatum(t.getValue()));
		}
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getBindings(int)
	 */
	@Override
	public Bindings getBindings(int scope) {
		Bindings b = new SimpleBindings();
		Environment e;

		e = _scope(scope);
		for(Map.Entry<SymbolName, Datum> t : e.getBoundData().entrySet()) {
			b.put(t.getKey().getName(), t.getValue());
		}
		return b;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#setAttribute(java.lang.String, java.lang.Object, int)
	 */
	@Override
	public void setAttribute(String name, Object value, int scope) {
		Environment e;

		e = _scope(scope);
		e.bindDatum(name, LispUtils.toDatum(value));
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getAttribute(java.lang.String, int)
	 */
	@Override
	public Object getAttribute(String name, int scope) {
		Environment e;

		e = _scope(scope);
		return e.getDatum(Symbol.getSymbol(name));
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#removeAttribute(java.lang.String, int)
	 */
	@Override
	public Object removeAttribute(String name, int scope) {
		Environment e;

		e = _scope(scope);
		return e.removeDatum(Symbol.getSymbol(name));
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getAttribute(java.lang.String)
	 */
	@Override
	public Object getAttribute(String name) {
		return env.findDatum(Symbol.getSymbol(name));
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getAttributesScope(java.lang.String)
	 */
	@Override
	public int getAttributesScope(String name) {
		if(env.getDatum(Symbol.getSymbol(name)) != null) {
			return ENGINE_SCOPE;
		} else if(env.getRootenv().getDatum(
				Symbol.getSymbol(name)) != null) {
			return GLOBAL_SCOPE;
		} else {
			return -1;
		}
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getWriter()
	 */
	@Override
	public Writer getWriter() {
		return writer;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getErrorWriter()
	 */
	@Override
	public Writer getErrorWriter() {
		return errwriter;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#setWriter(java.io.Writer)
	 */
	@Override
	public void setWriter(Writer writer) {
		this.writer = writer;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#setErrorWriter(java.io.Writer)
	 */
	@Override
	public void setErrorWriter(Writer writer) {
		this.errwriter = writer;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getReader()
	 */
	@Override
	public Reader getReader() {
		return reader;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#setReader(java.io.Reader)
	 */
	@Override
	public void setReader(Reader reader) {
		this.reader = reader;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptContext#getScopes()
	 */
	@Override
	public List<Integer> getScopes() {
		return Arrays.asList(ENGINE_SCOPE, GLOBAL_SCOPE);
	}

}
