/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.core.script;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;

/**
 * Wraps around the Rhino Script context
 * 
 * @version $Revision: 1.4 $ $Date: 2005/03/15 03:07:31 $
 */
public class ScriptContext
{

	/**
	 * for logging
	 */
	protected static Logger logger = Logger.getLogger( ScriptContext.class
			.getName( ) );

	/**
	 * the JavaScript Context
	 */
	protected Context context;

	/**
	 * The JavaScript scope used for script execution
	 */
	protected Scriptable scope;

	/**
	 * for BIRT globel varible "params"
	 */
	protected NativeObject params;

	/**
	 * constructor
	 */
	public ScriptContext( )
	{
		try
		{
			this.context = Context.enter( );
			this.scope = this.context.initStandardObjects( );

			//set the wrapper factory
			context.setWrapFactory( new BIRTWrapFactory( ) );

			//register BIRT defined static objects into script context
			NativeFinance.init( context, scope, true );
			NativeDateTimeSpan.init( context, scope, true );
		}
		catch ( Exception ex )
		{
			Context.exit( );
			this.scope = null;
			this.context = null;
			if ( logger.isLoggable( Level.WARNING ) )
			{
				logger.log( Level.WARNING, ex.getMessage( ), ex );
			}
		}
	}

	/**
	 * @param name
	 *            the name of a property
	 * @param value
	 *            the value of a property
	 */
	public void registerBean( String name, Object value )
	{
		assert ( this.context != null );
		Object sObj = Context.javaToJS( value, scope );
		scope.put( name, scope, sObj );
	}

	/**
	 * exit the scripting context
	 */
	public void exit( )
	{
		if ( context != null )
		{
			Context.exit( );
			context = null;
		}
	}

	/**
	 * creates a new scripting scope
	 */
	public void newScope( )
	{
		Scriptable newScope;
		try
		{
			newScope = context.newObject( scope );
			newScope.setParentScope( scope );
			scope = newScope;
		}
		catch ( EvaluatorException e )
		{
			if ( logger.isLoggable( Level.WARNING ) )
			{
				logger.log( Level.WARNING, e.getMessage( ), e );
			}
		}
		catch ( JavaScriptException e )
		{
			if ( logger.isLoggable( Level.WARNING ) )
			{
				logger.log( Level.WARNING, e.getMessage( ), e );
			}
		}
	}

	/**
	 * exits from the current scripting scope
	 */
	public void exitScope( )
	{
		Scriptable parentScope = scope.getParentScope( );
		if ( parentScope != null )
			scope = parentScope;
	}

	/**
	 * @return the current scope
	 */
	public Scriptable getCurrentScope( )
	{
		return scope;
	}

	/**
	 * checks if a property is available in the scope
	 * 
	 * @param name
	 * @return
	 */
	public Object lookupBean( String name )
	{
		assert ( context != null );
		return scope.get( name, scope );
	}

	/**
	 * evaluates a script
	 * 
	 * @param source
	 *            script to be evaluated
	 * @return the evaluated value
	 */
	public Object eval( String source )
	{
		return eval( source, "<inline>", 1 );
	}

	/**
	 * evaluates a script
	 */
	public Object eval( String source, String name, int lineNo )
	{
		assert ( this.context != null );
		try
		{
			Object value = context.evaluateString( scope, source, name, lineNo,
					null );
			return jsToJava( value );
		}
		catch ( Exception ex )
		{
			if (logger.isLoggable(Level.WARNING))
			{
				logger.log(Level.WARNING, ex.getMessage(), ex);
			}
			return null;
		}
	}

	/**
	 * converts a JS object to a Java object
	 * 
	 * @param jsValue
	 *            javascript object
	 * @return Java object
	 */
	public Object jsToJava( Object jsValue )
	{
		if ( jsValue instanceof Scriptable )
		{
			String className = ( (Scriptable) jsValue ).getClassName( );
			if ( "Date".equals( className ) )
			{
				return Context.toType( jsValue, java.util.Date.class );
			}
			else if ( "Boolean".equals( className ) )
			{
				return Boolean.valueOf( Context.toString( jsValue ) );
			}
			else if ( "String".equals( className ) )
			{
				return Context.toString( jsValue );
			}
		}
		return Context.toType( jsValue, Object.class );
	}
}
@@ -854,16 +854,64 @@
 iptable;
+%0Aimport org.mozilla.javascript.ScriptableObject;
 %0A%0A/**%0A *
@@ -978,17 +978,17 @@
 sion: 1.
-4
+5
  $ $Date
@@ -999,21 +999,21 @@
 05/0
-3/15
+4/12
  03:
-07:31
+16:23
  $%0A 
@@ -1705,101 +1705,129 @@
 %0A%09%09%09
-NativeFinance.init( context, scope, true );%0A%09%09%09NativeDateTimeSpan.init( context, scope, true 
+ScriptableObject.defineClass(scope, NativeFinance.class);%0A%09%09%09ScriptableObject.defineClass(scope, NativeDateTimeSpan.class
 );%0A%09

Update to the current release of Rhino (JS script engine)