Merge branch 'Jalview-JS/develop' into merge/Ben_trying_out_JSdevelop_with_develop
[jalview.git] / srcjar / fr / orsay / lri / varna / controlers / ControleurScriptParser.java
diff --git a/srcjar/fr/orsay/lri/varna/controlers/ControleurScriptParser.java b/srcjar/fr/orsay/lri/varna/controlers/ControleurScriptParser.java
new file mode 100644 (file)
index 0000000..4688f91
--- /dev/null
@@ -0,0 +1,551 @@
+package fr.orsay.lri.varna.controlers;
+
+import java.awt.Color;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.swing.JOptionPane;
+
+import fr.orsay.lri.varna.VARNAPanel;
+import fr.orsay.lri.varna.models.annotations.ChemProbAnnotation;
+import fr.orsay.lri.varna.models.annotations.ChemProbAnnotation.ChemProbAnnotationType;
+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 BooleanArgument extends Argument{
+               boolean _val; 
+               public BooleanArgument(boolean val)
+               {
+                       super(ArgumentType.BOOLEAN_TYPE);
+                       _val = val;
+               }
+               public boolean getBoolean()
+               {
+                       return _val;
+               }
+               public String toString()
+               {
+                       return ""+_val;
+               }
+       }; 
+
+       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,
+               BOOLEAN_TYPE,
+               ARRAY_TYPE,
+               COLOR_TYPE
+       };
+    
+    
+    private enum Function{
+               ADD_CHEM_PROB("addchemprob",new ArgumentType[] {ArgumentType.NUMBER_TYPE,ArgumentType.NUMBER_TYPE,ArgumentType.STRING_TYPE,ArgumentType.NUMBER_TYPE,ArgumentType.COLOR_TYPE,ArgumentType.BOOLEAN_TYPE}),
+       ERASE_SEQ("eraseseq",new ArgumentType[] {}),
+               RESET_CHEM_PROB("resetchemprob",new ArgumentType[] {}),
+               SET_COLOR_MAP_MIN("setcolormapminvalue",new ArgumentType[]{ArgumentType.NUMBER_TYPE}),
+               SET_COLOR_MAP_MAX("setcolormapmaxvalue",new ArgumentType[]{ArgumentType.NUMBER_TYPE}),
+               SET_COLOR_MAP("setcolormap",new ArgumentType[]{ArgumentType.STRING_TYPE}),
+               SET_CUSTOM_COLOR_MAP("setcustomcolormap",new ArgumentType[]{ArgumentType.ARRAY_TYPE}),
+               SET_SEQ("setseq",new ArgumentType[]{ArgumentType.STRING_TYPE}),
+               SET_STRUCT("setstruct",new ArgumentType[]{ArgumentType.STRING_TYPE}),
+               SET_STRUCT_SMOOTH("setstructsmooth",new ArgumentType[] {ArgumentType.STRING_TYPE}),
+               SET_TITLE("settitle",new ArgumentType[] {ArgumentType.STRING_TYPE}),
+               SET_RNA("setrna",new ArgumentType[]{ArgumentType.STRING_TYPE,ArgumentType.STRING_TYPE}),
+               SET_RNA_SMOOTH("setrnasmooth",new ArgumentType[]{ArgumentType.STRING_TYPE,ArgumentType.STRING_TYPE}),
+               SET_SELECTION("setselection",new ArgumentType[]{ArgumentType.ARRAY_TYPE}),
+               SET_VALUES("setvalues",new ArgumentType[]{ArgumentType.ARRAY_TYPE}),
+               TOGGLE_SHOW_COLOR_MAP("toggleshowcolormap",new ArgumentType[]{}),
+               REDRAW("redraw",new ArgumentType[] {ArgumentType.STRING_TYPE}),
+               UNKNOWN("N/A",new ArgumentType[] {});
+               
+               String _funName;
+               ArgumentType[] _args;
+               Function(String funName, ArgumentType[] args)
+               {
+                       _funName = funName;
+                       _args = args;
+               }
+               ArgumentType[] getPrototype()
+               {
+                       return this._args;
+               }
+               String getFunName()
+               {
+                       return this._funName;
+               }
+               
+       };
+       
+       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; }
+               Function[] funs = Function.values();
+               for(int i=0;i<funs.length;i++)
+               {
+                       Function fun = funs[i];
+                       _name2Fun.put(fun.getFunName(),fun);
+                       _fun2Prot.put(fun,fun.getPrototype());
+               }                       
+       }
+       
+       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 ADD_CHEM_PROB:
+                       {
+                               int from = (int)((NumberArgument) cmd._argv.get(0)).getNumber().intValue();
+                               int to = (int)((NumberArgument) cmd._argv.get(1)).getNumber().intValue();
+                               ChemProbAnnotationType t = ChemProbAnnotation.annotTypeFromString(((StringArgument) cmd._argv.get(2)).toString());
+                               double intensity = ((NumberArgument) cmd._argv.get(3)).getNumber().doubleValue();
+                               Color c = ((ColorArgument) cmd._argv.get(4)).getColor();
+                               boolean out = ((BooleanArgument) cmd._argv.get(5)).getBoolean();
+                               vp.getRNA().addChemProbAnnotation(new ChemProbAnnotation(
+                                               vp.getRNA().getBaseAt(from),
+                                               vp.getRNA().getBaseAt(to),
+                                               t,
+                                               intensity,
+                                               c,
+                                               out));
+                       }
+                       break;
+                       case ERASE_SEQ:
+                       {
+                               vp.eraseSequence();
+                       }
+                       break;
+                       case RESET_CHEM_PROB:
+                       {
+                               vp.getRNA().clearChemProbAnnotations();
+                               vp.repaint();
+                       }
+                       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_RNA:
+                       {
+                               String seq = cmd._argv.get(0).toString();
+                               String str = cmd._argv.get(1).toString();
+                               vp.drawRNA(seq, str);
+                       }
+                       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_SELECTION:
+                       {
+                               ArrayArgument arg = (ArrayArgument) cmd._argv.get(0);
+                               ArrayList<Integer> vals = new ArrayList<Integer>();
+                               for (int j=0;j<arg.getSize();j++)
+                               {
+                                       Argument a = arg.getArgument(j);
+                                       if (a._t==ArgumentType.NUMBER_TYPE)
+                                       { 
+                                               NumberArgument narg = (NumberArgument) a; 
+                                               vals.add(narg.getNumber().intValue()); 
+                                       }
+                               }                               
+                               vp.setSelection(vals);
+                               vp.repaint();
+                       }
+                       break;  
+                       case SET_SEQ:
+                       {
+                               String seq = cmd._argv.get(0).toString();
+                               vp.setSequence(seq);
+                       }
+                       break;
+                       case SET_STRUCT:
+                       {
+                               String seq = vp.getRNA().getSeq();
+                               String str = cmd._argv.get(0).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_TITLE:
+                       {
+                               vp.setTitle(cmd._argv.get(0).toString());
+                       }
+                       break;
+                       case SET_VALUES:
+                       {
+                               ArrayArgument arg = (ArrayArgument) cmd._argv.get(0);
+                               Double[] vals = new Double[arg.getSize()];
+                               for (int j=0;j<arg.getSize();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 Boolean parseBoolean(String s)
+       {
+               Boolean result = null;
+               if (s.toLowerCase().equals("true"))
+                       result = new Boolean(true);
+               if (s.toLowerCase().equals("false"))
+                       result = new Boolean(false);
+               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 ColorArgument(c));
+                                 }
+                                 else
+                                 {
+                                         Boolean b = parseBoolean(st.sval);
+                                         if (b!=null)
+                                         {
+                                                result.add(new BooleanArgument(b));
+                                         }
+                                         else
+                                         {
+                                                result.add(new StringArgument(st.sval));                                         
+                                         }
+                                 }
+                         }
+                         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;
+       }
+       
+       
+}