package fr.orsay.lri.varna.controlers;
import java.awt.Color;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.JOptionPane;
import fr.orsay.lri.varna.VARNAPanel;
import fr.orsay.lri.varna.models.rna.ModeleColorMap;
import fr.orsay.lri.varna.models.rna.RNA;
public class ControleurScriptParser {
private static String SCRIPT_ERROR_PREFIX = "Error";
private static class Command{
Function _f;
Vector<Argument> _argv;
public Command(Function f, Vector<Argument> argv)
{
_f = f;
_argv = argv;
}
};
private static abstract class Argument{
ArgumentType _t;
public Argument(ArgumentType t)
{
_t = t;
}
public ArgumentType getType()
{
return _t;
}
public abstract String toString();
};
private static class NumberArgument extends Argument{
Number _val;
public NumberArgument(Number val)
{
super(ArgumentType.NUMBER_TYPE);
_val = val;
}
public Number getNumber()
{
return _val;
}
public String toString()
{
return _val.toString();
}
};
private static class ColorArgument extends Argument{
Color _val;
public ColorArgument(Color val)
{
super(ArgumentType.COLOR_TYPE);
_val = val;
}
public Color getColor()
{
return _val;
}
public String toString()
{
return _val.toString();
}
};
private static class StringArgument extends Argument{
String _val;
public StringArgument(String val)
{
super(ArgumentType.STRING_TYPE);
_val = val;
}
public String toString()
{
return _val.toString();
}
};
private static class ArrayArgument extends Argument{
Vector<Argument> _val;
public ArrayArgument(Vector<Argument> val)
{
super(ArgumentType.ARRAY_TYPE);
_val = val;
}
public int getSize()
{
return _val.size();
}
public Argument getArgument(int i)
{
return _val.get(i);
}
public String toString()
{
return _val.toString();
}
};
private enum ArgumentType{
STRING_TYPE,
NUMBER_TYPE,
ARRAY_TYPE,
COLOR_TYPE
};
private enum Function{
ERASE_SEQ,
SET_COLOR_MAP_MIN,
SET_COLOR_MAP_MAX,
SET_COLOR_MAP,
SET_CUSTOM_COLOR_MAP,
SET_SEQ,
SET_STRUCT,
SET_STRUCT_SMOOTH,
SET_TITLE,
SET_RNA,
SET_RNA_SMOOTH,
SET_VALUES,
TOGGLE_SHOW_COLOR_MAP,
REDRAW,
UNKNOWN,
};
private static Hashtable<String,Function> _name2Fun = new Hashtable<String,Function>();
private static Hashtable<Function,ArgumentType[]> _fun2Prot = new Hashtable<Function,ArgumentType[]>();
private static void initFunctions()
{
if (_name2Fun.size()>0)
{ return; }
{
String funtxt = "eraseseq";
Function fun = Function.ERASE_SEQ;
ArgumentType[] proto = {};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "settitle";
Function fun = Function.SET_TITLE;
ArgumentType[] proto = {ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "redraw";
Function fun = Function.REDRAW;
ArgumentType[] proto = {ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setstruct";
Function fun = Function.SET_STRUCT;
ArgumentType[] proto = {ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setseq";
Function fun = Function.SET_SEQ;
ArgumentType[] proto = {ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setrna";
Function fun = Function.SET_RNA;
ArgumentType[] proto = {ArgumentType.STRING_TYPE,ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setstructsmooth";
Function fun = Function.SET_STRUCT_SMOOTH;
ArgumentType[] proto = {ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setrnasmooth";
Function fun = Function.SET_RNA_SMOOTH;
ArgumentType[] proto = {ArgumentType.STRING_TYPE,ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setvalues";
Function fun = Function.SET_VALUES;
ArgumentType[] proto = {ArgumentType.ARRAY_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setcolormap";
Function fun = Function.SET_COLOR_MAP;
ArgumentType[] proto = {ArgumentType.STRING_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setcolormapminvalue";
Function fun = Function.SET_COLOR_MAP_MIN;
ArgumentType[] proto = {ArgumentType.NUMBER_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setcolormapmaxvalue";
Function fun = Function.SET_COLOR_MAP_MAX;
ArgumentType[] proto = {ArgumentType.NUMBER_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "setcustomcolormap";
Function fun = Function.SET_CUSTOM_COLOR_MAP;
ArgumentType[] proto = {ArgumentType.ARRAY_TYPE};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
{
String funtxt = "toggleshowcolormap";
Function fun = Function.TOGGLE_SHOW_COLOR_MAP;
ArgumentType[] proto = {};
_name2Fun.put(funtxt,fun);_fun2Prot.put(fun,proto);
}
}
private static Function getFunction(String f)
{
String s = f.trim().toLowerCase();
if (_name2Fun.containsKey(s))
return _name2Fun.get(s);
return Function.UNKNOWN;
}
private static ArgumentType[] getPrototype(Function f)
{
if (_fun2Prot.containsKey(f))
return _fun2Prot.get(f);
return new ArgumentType[0];
}
public static void executeScript(VARNAPanel vp, String cmdtxt) throws Exception
{
Vector<Command> cmds = parseScript(cmdtxt);
for(int i=0;i<cmds.size();i++)
{
Command cmd = cmds.get(i);
switch(cmd._f)
{
case ERASE_SEQ:
{
vp.eraseSequence();
}
break;
case SET_COLOR_MAP_MIN:
{
vp.setColorMapMinValue(((NumberArgument) cmd._argv.get(0)).getNumber().doubleValue());
}
break;
case SET_COLOR_MAP_MAX:
{
vp.setColorMapMaxValue(((NumberArgument) cmd._argv.get(0)).getNumber().doubleValue());
}
break;
case SET_COLOR_MAP:
{
vp.setColorMap(ModeleColorMap.parseColorMap(cmd._argv.get(0).toString()));
}
break;
case SET_CUSTOM_COLOR_MAP:
{
ModeleColorMap cm = new ModeleColorMap();
//System.out.println("a"+cmd._argv.get(0));
ArrayArgument arg = (ArrayArgument) cmd._argv.get(0);
for (int j=0;j<arg.getSize();j++)
{
Argument a = arg.getArgument(j);
if (a._t==ArgumentType.ARRAY_TYPE)
{
//System.out.println("%");
ArrayArgument aarg = (ArrayArgument) a;
if (aarg.getSize()==2)
{
Argument a1 = aarg.getArgument(0);
Argument a2 = aarg.getArgument(1);
//System.out.println("& |"+a1+"| ["+a1.getType()+"] |"+a2+"| ["+a2.getType()+"]");
if ((a1.getType()==ArgumentType.NUMBER_TYPE)&&(a2.getType()==ArgumentType.COLOR_TYPE))
{
//System.out.println("+");
cm.addColor(((NumberArgument)a1).getNumber().doubleValue(),((ColorArgument)a2).getColor());
}
}
}
}
vp.setColorMap(cm);
}
break;
case SET_TITLE:
{
vp.setTitle(cmd._argv.get(0).toString());
}
break;
case SET_STRUCT:
{
String seq = vp.getRNA().getSeq();
String str = cmd._argv.get(0).toString();
vp.drawRNA(seq, str);
}
break;
case SET_SEQ:
{
String seq = cmd._argv.get(0).toString();
vp.setSequence(seq);
}
break;
case SET_RNA:
{
String seq = cmd._argv.get(0).toString();
String str = cmd._argv.get(1).toString();
vp.drawRNA(seq, str);
}
break;
case SET_STRUCT_SMOOTH:
{
String seq = vp.getRNA().getSeq();
String str = cmd._argv.get(0).toString();
vp.drawRNAInterpolated(seq, str);
vp.repaint();
}
break;
case SET_RNA_SMOOTH:
{
String seq = cmd._argv.get(0).toString();
String str = cmd._argv.get(1).toString();
vp.drawRNAInterpolated(seq, str);
vp.repaint();
}
break;
case SET_VALUES:
{
ArrayArgument arg = (ArrayArgument) cmd._argv.get(0);
Double[] vals = new Double[arg.getSize()];
for (int j=0;j<vals.length;j++)
{
Argument a = arg.getArgument(j);
if (a._t==ArgumentType.NUMBER_TYPE)
{
NumberArgument narg = (NumberArgument) a;
vals[j] = narg.getNumber().doubleValue();
}
}
vp.setColorMapValues(vals);
vp.repaint();
}
break;
case REDRAW:
{
int mode = -1;
String modeStr = cmd._argv.get(0).toString().toLowerCase();
if (modeStr.equals("radiate"))
mode = RNA.DRAW_MODE_RADIATE;
else if (modeStr.equals("circular"))
mode = RNA.DRAW_MODE_CIRCULAR;
else if (modeStr.equals("naview"))
mode = RNA.DRAW_MODE_NAVIEW;
else if (modeStr.equals("linear"))
mode = RNA.DRAW_MODE_LINEAR;
if (mode != -1)
vp.drawRNA(vp.getRNA(), mode);
}
break;
case TOGGLE_SHOW_COLOR_MAP:
{
vp.setColorMapVisible(!vp.getColorMapVisible());
}
break;
default:
throw new Exception(SCRIPT_ERROR_PREFIX+": Method '"+cmd._f+"' unimplemented.");
}
vp.repaint();
}
}
private static Color parseColor(String s)
{
Color result = null;
try {result = Color.decode(s); }
catch (Exception e) {}
return result;
}
private static Vector<Argument> parseArguments(StreamTokenizer st, boolean parType) throws Exception
{
Vector<Argument> result = new Vector<Argument>();
while((st.ttype!=')' && parType) || (st.ttype!=']' && !parType))
{
st.nextToken();
//System.out.println(""+ (parType?"Par.":"Bra.")+" "+(char)st.ttype);
switch(st.ttype)
{
case(StreamTokenizer.TT_NUMBER):
{
result.add(new NumberArgument(st.nval));
}
break;
case(StreamTokenizer.TT_WORD):
{
Color c = parseColor(st.sval);
if (c==null)
result.add(new StringArgument(st.sval));
else
result.add(new ColorArgument(c));
}
break;
case('"'):
{
result.add(new StringArgument(st.sval));
}
break;
case('['):
{
result.add(new ArrayArgument(parseArguments(st, false)));
}
break;
case('('):
{
result.add(new ArrayArgument(parseArguments(st, true)));
}
break;
case(')'):
{
if (parType)
return result;
else
throw new Exception(SCRIPT_ERROR_PREFIX+": Opening "+(parType?"parenthesis":"bracket")+" matched with a closing "+(!parType?"parenthesis":"bracket"));
}
case(']'):
{
if (!parType)
return result;
else
throw new Exception(SCRIPT_ERROR_PREFIX+": Opening "+(parType?"parenthesis":"bracket")+" matched with a closing "+(!parType?"parenthesis":"bracket"));
}
case(','):
break;
case(StreamTokenizer.TT_EOF):
{
throw new Exception(SCRIPT_ERROR_PREFIX+": Unmatched opening "+(parType?"parenthesis":"bracket"));
}
}
}
return result;
}
private static Command parseCommand(String cmd) throws Exception
{
int cut = cmd.indexOf("(");
if (cut==-1)
{
throw new Exception(SCRIPT_ERROR_PREFIX+": Syntax error");
}
String fun = cmd.substring(0,cut);
Function f = getFunction(fun);
if (f==Function.UNKNOWN)
{ throw new Exception(SCRIPT_ERROR_PREFIX+": Unknown function \""+fun+"\""); }
StreamTokenizer st = new StreamTokenizer(new StringReader(cmd.substring(cut+1)));
st.eolIsSignificant(false);
st.parseNumbers();
st.quoteChar('\"');
st.ordinaryChar('=');
st.ordinaryChar(',');
st.ordinaryChar('[');
st.ordinaryChar(']');
st.ordinaryChar('(');
st.ordinaryChar(')');
st.wordChars('#', '#');
Vector<Argument> argv = parseArguments(st,true);
checkArgs(f,argv);
Command result = new Command(f,argv);
return result;
}
private static boolean checkArgs(Function f, Vector<Argument> argv) throws Exception
{
ArgumentType[] argtypes = getPrototype(f);
if (argtypes.length!=argv.size())
throw new Exception(SCRIPT_ERROR_PREFIX+": Wrong number of argument for function \""+f+"\".");
for (int i=0;i<argtypes.length;i++)
{
if (argtypes[i] != argv.get(i)._t)
{
throw new Exception(SCRIPT_ERROR_PREFIX+": Bad type ("+argtypes[i]+"!="+argv.get(i)._t+") for argument #"+(i+1)+" in function \""+f+"\".");
}
}
return true;
}
private static Vector<Command> parseScript(String cmd) throws Exception
{
initFunctions();
Vector<Command> cmds = new Vector<Command>();
String[] data = cmd.split(";");
for (int i=0;i<data.length;i++)
{
cmds.add(parseCommand(data[i].trim()));
}
return cmds;
}
}