package com.drawbridge.jsengine.jsobjects;
import java.awt.Dimension;
import java.awt.Point;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import com.drawbridge.dm.DMImageFactory.DMImage;
import com.drawbridge.dm.DMPanel;
import com.drawbridge.dm.DMSimplePanel;
import com.drawbridge.dm.ManipulationSource;
import com.drawbridge.dm.animation.NativeAnimationItem;
import com.drawbridge.dm.animation.NativeAnimationProcessor;
import com.drawbridge.dm.animation.NativeAnimationTween;
import com.drawbridge.jsengine.ast.Evaluator;
import com.drawbridge.utils.ASTModification;
import com.drawbridge.utils.Utils;
/**
* Allows specification of native functions that can used in the same way as
* JSFunctions
*
* @author Alistair Stead
*
*/
public class JSNativeFunction extends JSFunction
{
private String mMethodName;
private JSType mObject;
private Class<?>[] mParams;
private static Evaluator mLastNativeCaller = null;
public JSNativeFunction(JSType object, String methodName, Class<?>[] params) {
super(null);
mObject = object;
mMethodName = methodName;
mParams = params;
}
@Override
public JSType executeFunction(Evaluator caller, JSType[] methodParams) throws ExecutionException
{
mLastNativeCaller = caller;
mEvaluator = null;
Method mMethod = null;
try
{
if (mObject != null)
mMethod = JSNativeFunction.class.getDeclaredMethod(mMethodName, mParams);
else
{
// Try to use a static method
mMethod = JSNativeFunction.class.getMethod(mMethodName, mParams);
}
} catch (SecurityException e)
{
e.printStackTrace();
} catch (NoSuchMethodException e)
{
e.printStackTrace();
}
if (mMethod != null)
{
if (mParams != null && methodParams != null && mParams.length == methodParams.length)
{
// Check params are correct
for (int i = 0; i < mParams.length; i++)
{
if (!(mParams[i] == null || methodParams[i] == null || mParams[i].equals(methodParams[i].getClass())))
{
throw new ExecutionException("Cannot run native method, params are not equal: " + mParams[i] + ", " + methodParams[i] + mParams.length + " vs. " + methodParams.length);
}
}
}
else
{
throw new ExecutionException("Cannot run native method - incorrect number of paramaters");
}
}
JSType result = null;
try
{
result = (JSType) mMethod.invoke(this, (Object[]) methodParams);
// Remember all native functions need to be statically declared in
// this class
} catch (IllegalArgumentException e)
{
Utils.out.println(this.getClass(), "IllegalArgumentException: mMethod: " + mMethod.getName() + " + " + mMethodName + " methodParams:" + methodParams.toString());
throw new ExecutionException("Cannot run native method - illegal arguments!");
} catch (IllegalAccessException e)
{
Utils.out.println(this.getClass(), "IllegalAccessException: mMethod: " + mMethod.getName() + " + " + mMethodName);
throw new ExecutionException("Cannot run native method - illegal access!");
} catch (InvocationTargetException e)
{
Utils.out.println(this.getClass(), "InvocationTargetException: mMethod: " + mMethod.getName() + " + " + mMethodName);
throw new ExecutionException("Cannot run native method - illegal target!");
}
return result;
}
@Override
public String toString()
{
return "Native:" + mMethodName;
}
// DOCUMENT FUNCTIONS
// ************************************************************************************
// *******************************************************************************************************
public Canvas getElementById(JSString name)
{
if (name.mValue.equals("myCanvas"))
{
return new Canvas();
}
else
throw new RuntimeException("No element named:" + name.mValue);
}
public Context getContext(JSString name)
{
if (name.mValue.equals("2d"))
{
return new Context();
}
else
throw new RuntimeException("No context named:" + name.mValue);
}
// OBJECT FUNCTIONS
// **************************************************************************************
// *******************************************************************************************************
public static JSBoolean hasOwnProperty(JSObject jsObject, JSString name)
{
if (jsObject.getProperty(name.mValue) != null)
{
return new JSBoolean(true);
}
return new JSBoolean(false);
}
// JSString FUNCTIONS
// ************************************************************************************
// *******************************************************************************************************
public static JSNumber charAt(JSString jsString, JSNumber position)
{
return new JSNumber(jsString.mValue.charAt((int) java.lang.Math.round(position.mValue)));
}
public static JSString toUpperCase(JSString jsString)
{
return new JSString(jsString.mValue.toUpperCase());
}
// JSImage FUNCTIONS
// *************************************************************************************
// *******************************************************************************************************
public static void drawImage(JSImage image, JSNumber x, JSNumber y, JSNumber w, JSNumber h)
{
// Here we're assuming there's only one context (DMPanel).
DMPanel.getInstance().drawImage(image.mValue, (int) java.lang.Math.round(x.mValue), (int) java.lang.Math.round(y.mValue),
(int) java.lang.Math.round(w.mValue), (int) java.lang.Math.round(h.mValue));
}
// MATH FUNCTIONS
// ****************************************************************************************
// *******************************************************************************************************
public static JSNumber abs(Double x)
{
return new JSNumber(java.lang.Math.abs(x));
}
public static JSNumber acos(Double x)
{
return new JSNumber(java.lang.Math.acos(x));
}
public static JSNumber asin(Double x)
{
return new JSNumber(java.lang.Math.asin(x));
}
public static JSNumber atan(Double x)
{
return new JSNumber(java.lang.Math.atan(x));
}
public static JSNumber atan2(Double x, Double y)
{
return new JSNumber(java.lang.Math.atan2(x, y));
}
public static JSNumber ceil(Double x)
{
return new JSNumber(java.lang.Math.ceil(x));
}
public static JSNumber cos(Double x)
{
return new JSNumber(java.lang.Math.cos(x));
}
public static JSNumber exp(Double x)
{
return new JSNumber(java.lang.Math.exp(x));
}
public static JSNumber floor(Double x)
{
return new JSNumber(java.lang.Math.floor(x));
}
public static JSNumber log(Double x)
{
return new JSNumber(java.lang.Math.log(x));
}
public static JSNumber max(Double x, Double y)
{
return new JSNumber(java.lang.Math.max(x, y));
}
public static JSNumber min(Double x, Double y)
{
return new JSNumber(java.lang.Math.min(x, y));
}
public static JSNumber pow(Double x, Double y)
{
return new JSNumber(java.lang.Math.pow(x, y));
}
public static JSNumber random()
{
return new JSNumber(java.lang.Math.random());
}
public static JSNumber round(Double x)
{
return new JSNumber((double) java.lang.Math.round(x));
}
public static JSNumber sin(Double x)
{
return new JSNumber(java.lang.Math.sin(x));
}
public static JSNumber sqrt(Double x)
{
return new JSNumber(java.lang.Math.sqrt(x));
}
public static JSNumber tan(Double x)
{
return new JSNumber(java.lang.Math.tan(x));
}
// ANIMATION FUNCTIONS
// ***********************************************************************************
// *******************************************************************************************************
public static JSType loadImage(JSNumber index, JSNumber x, JSNumber y, JSNumber width, JSNumber height)
{
List<DMImage> list = DMPanel.getInstance().mModel.getModelObjects();
if (list.size() > index.mValue)
{
DMImage image = list.get(index.intValue());
if (image != null)
{
Dimension newSize = new Dimension(width.intValue(), height.intValue());
image.setPreferredSize(newSize);
image.setPreferredLocation(new Point(x.intValue(), y.intValue()), ManipulationSource.SOURCE_EXECUTION);
image.setEvaluatorNode(mLastNativeCaller, ASTModification.ASTModificationType.MOD_LOCATION);
image.setEvaluatorNode(mLastNativeCaller, ASTModification.ASTModificationType.MOD_SIZE);
if (!DMSimplePanel.getInstance().isPlaying())
{
image.setSize(newSize);
image.setLocation(image.getPreferredLocation());
}
return new JSImage(image);
}
}
try
{
throw new Exception("loadImage Index not valid (should be 0-" + list.size() + ")");
} catch (Exception e)
{
e.printStackTrace();
return new JSUndefined();
}
}
public static LinkedList<NativeAnimationItem> animationItems = new LinkedList<NativeAnimationItem>();
public static NativeAnimationProcessor processor = new NativeAnimationProcessor();
public static int tweensCalled = 0;
public static int tweensProcessed = -1;
public static void tweenProcessingCallback()
{
if (tweensProcessed == -1)
tweensProcessed = 1;
else
{
tweensProcessed++;
}
if (tweensProcessed == tweensCalled)
{
DMSimplePanel.getInstance().finishedProcessing();
}
Utils.out.println(JSNativeFunction.class, "tweenProcessingCallback ->" + tweensCalled + " called and " + tweensProcessed + " processed");
}
public void setTweenPosition(JSNumber x, JSNumber y)
{
// add the animation item to the list
if (mObject instanceof JSImage)
{
JSImage image = (JSImage) mObject;
animationItems.add(new NativeAnimationItem(image.mValue, x.intValue(), y.intValue(), null, null, null));
}
}
public void setTweenSize(JSNumber width, JSNumber height)
{
// add the animation item to the list
if (mObject instanceof JSImage)
{
JSImage image = (JSImage) mObject;
animationItems.add(new NativeAnimationItem(image.mValue, null, null, width.intValue(), height.intValue(), null));
}
}
public static void setTimeToDestination(JSNumber timeDelay)
{
Utils.out.println(JSNativeFunction.class, "setTimeToDestination");
tweensCalled++;
try
{
NativeAnimationItem[] items = new NativeAnimationItem[animationItems.size()];
for (int i = 0; i < animationItems.size(); i++)
items[i] = animationItems.get(i);
NativeAnimationTween tween = new NativeAnimationTween(items, timeDelay.intValue());
processor.add(tween);
if (!processor.isAlive())
processor.start();
animationItems = new LinkedList<NativeAnimationItem>();
} catch (Exception e)
{
e.printStackTrace();
}
}
// CONTEXT FUNCTIONS
// ************************************************************************************
// *******************************************************************************************************
public void setBackgroundColour(JSString string)
{
// Do nothing right now
try
{
// Utils.out.println(this.getClass(),"Running setBackgroundColor: "
// + string.mValue);
java.awt.Color color = java.awt.Color.decode(string.mValue);
DMPanel.getInstance().getCanvas().setBackground(color);
DMSimplePanel.getInstance().getCanvas().setBackground(color);
} catch (Exception e)
{
e.printStackTrace();
}
}
public JSString getRGB(JSNumber r, JSNumber g, JSNumber b)
{
// Utils.out.println(this.getClass(),"Running getRGB:" + r + ", " + g +
// ", " + b);
Utils.out.println(this.getClass(), "");
String result = String.format("#%02x%02x%02x", r.intValue(), g.intValue(), b.intValue());
// Utils.out.println(this.getClass(),"returning:" + result);
return new JSString(result);
}
}