/*
 * Copyright 2007 Andrew Wills
 *
 * 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 org.danann.cernunnos.script;

import java.util.LinkedList;
import java.util.List;

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

import org.danann.cernunnos.AbstractContainerTask;
import org.danann.cernunnos.EntityConfig;
import org.danann.cernunnos.Formula;
import org.danann.cernunnos.Reagent;
import org.danann.cernunnos.Phrase;
import org.danann.cernunnos.ReagentType;
import org.danann.cernunnos.SimpleFormula;
import org.danann.cernunnos.SimpleReagent;
import org.danann.cernunnos.Task;
import org.danann.cernunnos.TaskRequest;
import org.danann.cernunnos.TaskResponse;

public class ScriptTask extends AbstractContainerTask {

	// Instance Members.
	private Phrase engine;
	private Phrase script;

	/*
	 * Public API.
	 */

	public static final Reagent ENGINE = new SimpleReagent("ENGINE", "@engine", ReagentType.PHRASE, ScriptEngine.class,
					"Optional instance of ScriptEngine that will be used to invoke SCRIPT.  If one is not provided, " +
					"a new one will be created.  The default is the value of the 'ScriptAttributes.ENGINE.{ENGINE_NAME}' " +
					"request attribute, if present.");

	public static final Reagent SCRIPT = new SimpleReagent("SCRIPT", "script/text()", ReagentType.PHRASE, String.class,
					"Script content to execute.  Must be placed within a child <script> element.");

	public static final Reagent SUBTASKS = new SimpleReagent("SUBTASKS", "subtasks/*", ReagentType.NODE_LIST, List.class,
					"The set of tasks that are children of this task.", new LinkedList<Task>());

	public Formula getFormula() {
		Reagent[] reagents = new Reagent[] {ENGINE, SCRIPT, SUBTASKS};
		final Formula rslt = new SimpleFormula(ScriptTask.class, reagents);
		return rslt;
	}

	public void init(EntityConfig config) {

		super.init(config);

		// Instance Members.
		this.engine = (Phrase) config.getValue(ENGINE);
		this.script = (Phrase) config.getValue(SCRIPT);

	}

	public void perform(TaskRequest req, TaskResponse res) {

		ScriptEngine eng = (ScriptEngine) engine.evaluate(req, res);
		String s = (String) script.evaluate(req, res);
		try {

			Bindings n = new SimpleBindings();
			n.putAll(req.getAttributes());

			eng.eval(s, n);

			// Add the engine to the request attributes and invoke subtasks...
			StringBuffer key = new StringBuffer();
			key.append(ScriptAttributes.ENGINE).append(".")
					.append(eng.getFactory().getEngineName());
			res.setAttribute(key.toString(), eng);
			super.performSubtasks(req, res);

		} catch (Throwable t) {
			String msg = "Error while executing the specified script.  " +
							"\n\t\tENGINE_NAME:  " + eng.getFactory().getEngineName() +
							"\n\t\tSCRIPT (follows):\n" + s + "\n";
			throw new RuntimeException(msg, t);
		}

	}
	
}

@@ -2914,28 +2914,540 @@
 );%0D%0A
-%0D%0A%09%09%09eng.eval(s, n);
+%09%09%09ScriptContext ctx = new javax.script.SimpleScriptContext();%0D%0A%09%09%09ctx.setBindings(n, ScriptContext.GLOBAL_SCOPE);%0D%0A%09%09%09ctx.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);%0D%0A%0D%0A%09%09%09eng.eval(s, ctx);%0D%0A%09%09%09%0D%0A%09%09%09// Add new items from the ScriptContext to the TaskResponse...%0D%0A%09%09%09// NOT YET:  This isn't working as expected, so let's not invite weird surprises!%0D%0A//%09%09%09for (Entry%3CString,Object%3E e : n.entrySet()) %7B%0D%0A//%09%09%09%09if (!req.hasAttribute(e.getKey())) %7B%0D%0A//%09%09%09%09%09res.setAttribute(e.getKey(), e.getValue());%0D%0A//%09%09%09%09%7D%0D%0A//%09%09%09%7D
 %0D%0A%0D%0A

Change to bind request attributes at GLOBAL_SCOPE instead of ENGINE_SCOPE