package ij.macro;
import ij.IJ;
import java.util.ArrayList;
public class ExtensionDescriptor {
public String name;
public int[] argTypes;
public MacroExtension handler;
public ExtensionDescriptor(String theName, int[] theArgTypes, MacroExtension theHandler) {
this.name = theName;
this.argTypes = theArgTypes;
this.handler = theHandler;
}
public static ExtensionDescriptor newDescriptor(String theName, MacroExtension theHandler, int[] types) {
int[] argTypes = new int[types.length];
for (int i=0; i < types.length; ++i) {
argTypes[i] = types[i];
}
return new ExtensionDescriptor(theName, argTypes, theHandler);
}
public static ExtensionDescriptor newDescriptor(String theName, MacroExtension theHandler) {
return newDescriptor(theName, theHandler, new int[0]);
}
public static ExtensionDescriptor newDescriptor(String theName, MacroExtension theHandler, int type) {
return newDescriptor(theName, theHandler, new int[] {type});
}
public static ExtensionDescriptor newDescriptor(String theName, MacroExtension theHandler, int t1, int t2) {
return newDescriptor(theName, theHandler, new int[] {t1, t2});
}
public static ExtensionDescriptor newDescriptor(String theName, MacroExtension theHandler, int t1, int t2, int t3) {
return newDescriptor(theName, theHandler, new int[] {t1, t2, t3});
}
public static ExtensionDescriptor newDescriptor(String theName, MacroExtension theHandler, int t1, int t2, int t3, int t4) {
return newDescriptor(theName, theHandler, new int[] {t1, t2, t3, t4});
}
public static ExtensionDescriptor newDescriptor(String theName, MacroExtension theHandler, Integer[] types) {
int[] argTypes = new int[types.length];
for (int i=0; i < types.length; ++i) {
argTypes[i] = types[i].intValue();
}
return new ExtensionDescriptor(theName, argTypes, theHandler);
}
public static boolean isOptionalArg(int argType) {
return (argType & MacroExtension.ARG_OPTIONAL) == MacroExtension.ARG_OPTIONAL;
}
public static boolean isOutputArg(int argType) {
return (argType & MacroExtension.ARG_OUTPUT) == MacroExtension.ARG_OUTPUT;
}
public static int getRawType(int argType) {
return argType & ~(MacroExtension.ARG_OUTPUT|MacroExtension.ARG_OPTIONAL);
}
public boolean checkArguments(Object[] args) {
for (int i=0; i < argTypes.length; ++i) {
boolean optional = isOptionalArg(argTypes[i]);
boolean output = isOutputArg(argTypes[i]);
int rawType = getRawType(argTypes[i]);
if (args.length < i)
return optional ? true : false;
switch(rawType) {
case MacroExtension.ARG_STRING:
if (output) {
if (! (args[i] instanceof String[])) return false;
} else {
if (! (args[i] instanceof String)) return false;
}
case MacroExtension.ARG_NUMBER:
if (output) {
if (! (args[i] instanceof Double[])) return false;
} else {
if (!(args[i] instanceof Double)) return false;
}
case MacroExtension.ARG_ARRAY:
if (!(args[i] instanceof Object[])) return false;
}
}
return true;
}
public static String getTypeName(int argType) {
switch(getRawType(argType)) {
case MacroExtension.ARG_STRING:
return "string";
case MacroExtension.ARG_NUMBER:
return "number";
case MacroExtension.ARG_ARRAY:
return "array";
default:
return "unknown";
}
}
private static String getVariableTypename(int type) {
switch (type) {
case Variable.STRING:
return "string";
case Variable.NUMBER:
return "number";
case Variable.ARRAY:
return "array";
default:
return "unknown";
}
}
private static Object[] convertArray(Variable[] array) {
Object[] oArray = new Object[ array.length ];
for(int i=0; i < array.length; ++i) {
switch(array[i].getType()) {
case Variable.STRING:
oArray[i] = array[i].getString();
break;
case Variable.VALUE:
oArray[i] = Double.valueOf( array[i].getValue() );
break;
case Variable.ARRAY:
oArray[i] = convertArray(array[i].getArray());
break;
default:
oArray[i] = null;
}
}
return oArray;
}
Variable[] parseArgumentList(Functions func) {
Interpreter interp = func.interp;
Variable[] vArray = new Variable[argTypes.length];
int i=0;
do {
if (i >= argTypes.length) {
interp.error("too many arguments (expected "+argTypes.length+")");
return null;
}
boolean output = isOutputArg(argTypes[i]);
Variable v;
if (output) {
v = func.getVariable();
} else {
v = new Variable();
switch (getRawType(argTypes[i])) {
case MacroExtension.ARG_STRING:
v.setString(func.getString());
break;
case MacroExtension.ARG_NUMBER:
v.setValue(interp.getExpression());
break;
case MacroExtension.ARG_ARRAY:
v.setArray(func.getArray());
break;
}
}
vArray[i] = v;
++i;
interp.getToken();
} while (interp.token == ',');
if (interp.token!=')')
interp.error("')' expected");
if (i < argTypes.length && !isOptionalArg(argTypes[i])) {
interp.error("too few arguments, expected "+argTypes.length+" but found "+i);
}
return vArray;
}
public static Object convertVariable(Interpreter interp, int rawType, Variable var) {
int type = getRawType(rawType);
boolean output = isOutputArg(rawType);
if (var == null)
return null;
switch (type) {
case MacroExtension.ARG_STRING:
if (!output && var.getType()!=Variable.STRING) {
interp.error("Expected string, but variable type is "+getVariableTypename(var.getType()));
return null;
}
if (output) {
String s = var.getString();
if (s==null) s = "";
return new String[] { s };
} else {
return var.getString();
}
case MacroExtension.ARG_NUMBER:
if (var.getType() != Variable.VALUE) {
interp.error("Expected number, but variable type is "+getVariableTypename(var.getType()));
return null;
}
if (output) {
return new Double[] { Double.valueOf(var.getValue()) };
} else {
return Double.valueOf( var.getValue() );
}
case MacroExtension.ARG_ARRAY:
if (var.getType() != Variable.ARRAY) {
interp.error("Expected array, but variable type is "+getVariableTypename(var.getType()));
return null;
}
return convertArray(var.getArray());
default:
interp.error("Unknown descriptor type "+type+" ("+rawType+")");
return null;
}
}
public static void convertOutputType(Variable variable, Object object) {
if (object instanceof String[]) {
String[] str = (String[]) object;
variable.setString(str[0]);
} else if (object instanceof Double[]) {
Double[] dbl = (Double[]) object;
variable.setValue(dbl[0].doubleValue());
} else if (object instanceof Object[]) {
Object[] arr = (Object[]) object;
Variable[] vArr = new Variable[arr.length];
for (int i=0; i < arr.length; ++i) {
vArr[i] = new Variable();
convertOutputType(vArr[i], arr[i]);
}
variable.setArray(vArr);
}
}
public String dispatch(Functions func) {
Interpreter interp = func.interp;
if (argTypes.length==0) {
interp.getParens();
return handler.handleExtension(name, null);
}
interp.getLeftParen();
Variable[] vArgs = null;
int next = interp.nextToken();
if (next != ')') {
vArgs = parseArgumentList(func);
}
Object[] args = new Object[ argTypes.length ];
if (vArgs==null && argTypes.length>0) {
interp.error("Argument expected");
return null;
}
for (int i=0; i < argTypes.length; ++i) {
if (i >= vArgs.length) {
if (!ExtensionDescriptor.isOptionalArg(argTypes[i])) {
interp.error("Expected argument "+(i+1)+" of type "+ExtensionDescriptor.getTypeName(argTypes[i]));
return null;
} else {
break;
}
}
args[i] = ExtensionDescriptor.convertVariable(interp, argTypes[i], vArgs[i]);
}
String retVal = handler.handleExtension(name, args);
for (int i=0; i < argTypes.length; ++i) {
if (i >= vArgs.length) break;
if (ExtensionDescriptor.isOutputArg(argTypes[i])) {
ExtensionDescriptor.convertOutputType(vArgs[i], args[i]);
}
}
return retVal;
}
}