/*
 * 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.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;

import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

import net.morilib.lisp.nano.LispException;
import net.morilib.lisp.nano.Scheme;

/**
 *
 *
 * @author MORIGUCHI, Yuichiro 2014/02/17
 */
public class SchlushScriptEngine extends AbstractScriptEngine
implements Invocable {

	//
	private SchlushEngineFactory factory;
	private Scheme scheme;

	//
	SchlushScriptEngine(SchlushEngineFactory f) {
		factory = f;
		scheme  = SchlushEngineFactory.SCHEME;
	}

	/* (non-Javadoc)
	 * @see javax.script.AbstractScriptEngine#getScriptContext(javax.script.Bindings)
	 */
	@Override
	protected ScriptContext getScriptContext(Bindings nn) {
		SchlushScriptContext c;

		c = new SchlushScriptContext(factory.environ);
		c.setReader(new InputStreamReader(System.in));
		c.setWriter(new OutputStreamWriter(System.out));
		c.setErrorWriter(new OutputStreamWriter(System.err));
		c.setBindings(nn, ScriptContext.ENGINE_SCOPE);
		return c;
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptEngine#eval(java.lang.String, javax.script.ScriptContext)
	 */
	@Override
	public Object eval(String script,
			ScriptContext context) throws ScriptException {
		return eval(new StringReader(script), context);
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptEngine#eval(java.io.Reader, javax.script.ScriptContext)
	 */
	@Override
	public Object eval(Reader reader,
			ScriptContext context) throws ScriptException {
		SchlushScriptContext c;

		try {
			if(context instanceof SchlushScriptContext) {
				c = (SchlushScriptContext)context;
				return scheme.read(c.env, context.getReader());
			} else {
				throw new IllegalArgumentException();
			}
		} catch (IOException e) {
			throw new ScriptException(e);
		}
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptEngine#createBindings()
	 */
	@Override
	public Bindings createBindings() {
		return new SimpleBindings();
	}

	/* (non-Javadoc)
	 * @see javax.script.ScriptEngine#getFactory()
	 */
	@Override
	public ScriptEngineFactory getFactory() {
		return factory;
	}

	/* (non-Javadoc)
	 * @see javax.script.Invocable#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object[])
	 */
	@Override
	public Object invokeMethod(Object dieser, String name,
			Object... args) throws ScriptException, NoSuchMethodException {
		throw new NoSuchMethodException();
	}

	/* (non-Javadoc)
	 * @see javax.script.Invocable#invokeFunction(java.lang.String, java.lang.Object[])
	 */
	@Override
	public Object invokeFunction(String name,
			Object... args) throws ScriptException, NoSuchMethodException {
		try {
			return scheme.call(name, args);
		} catch(LispException e) {
			throw new ScriptException(e);
		}
	}

	/* (non-Javadoc)
	 * @see javax.script.Invocable#getInterface(java.lang.Class)
	 */
	@Override
	public <T> T getInterface(Class<T> klasse) {
		throw new IllegalArgumentException();
	}

	/* (non-Javadoc)
	 * @see javax.script.Invocable#getInterface(java.lang.Object, java.lang.Class)
	 */
	@Override
	public <T> T getInterface(Object dieser, Class<T> klasse) {
		throw new IllegalArgumentException();
	}

}
