package org.zkoss.zk.scripting.jython;

import org.python.core.Py;
import org.python.core.PyObject;
import org.python.core.PyStringMap;
import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;

import org.zkoss.zk.scripting.util.GenericInterpreter;
import org.zkoss.zk.ui.Page;

/**
 * The Python interpreter based on <a href="www.jython.org">jython</a>.
 * 
 * <p>Ludovic Drolez implemented the first Jython interpreter for ZK on May 2007:
 * http://zkforge.svn.sourceforge.net/viewvc/zkforge/trunk/scripting/jython/src/org/zkforge/scripting/jython/
 *
 * <p>Inspired by Drolez's job, Grace Lin wrote this class on March 2008
 * 
 * @author gracelin
 * @since 3.0.4
 */
public class JythonInterpreter extends GenericInterpreter {
	private PythonInterpreter _ip;

	public JythonInterpreter() {
	}

	//super//
	public void init(Page owner, String zslang) {
		super.init(owner, zslang);
		if (System.getProperty("python.home") == null)
			System.setProperty("python.home", System.getProperty("java.io.tmpdir"));

		PySystemState.initialize();
		PySystemState.add_extdir(owner.getDesktop().getWebApp().getRealPath("/WEB-INF/lib"), true);
		PySystemState.add_classdir(owner.getDesktop().getWebApp().getRealPath("/WEB-INF/classes"));
		_ip = new PythonInterpreter(new Variables());
	}

	protected void exec(String script) {
		_ip.exec(script);
	}

	public void destroy() {
		_ip.cleanup();
		_ip = null;
		super.destroy();
	}

	protected Object get(String name) {
		//Bug 2208873: Don't use _ip.get(String, Object) since it
		//doesn't handle null well
		PyObject val = _ip.get(name);
		return val != null ? Py.tojava(val, Object.class) : null;
	}

	protected void set(String name, Object value) {
		if (value == null)
			_ip.set(name, (PyObject) null);
		else
			_ip.set(name, value);
	}

	protected void unset(String name) {
		_ip.set(name, Py.None);
	}

	public Object getNativeInterpreter() {
		return _ip;
	}

	//helper classes//
	/** The global scope. */
	private class Variables extends PyStringMap {
		@SuppressWarnings("checkstyle:MethodName")
		public synchronized PyObject __finditem__(String key) {
			PyObject pyo = super.__finditem__(key);

			if (pyo == null) { // use "null" without "Py.None", because we override __finditem__
				Object val = getFromNamespace(key);
				if (val != UNDEFINED)
					return Py.java2py(val);
			}
			return pyo;
		}
	}
}
