4688f91acd1eb70724a482c54598cbf7722c8e48
[jalview.git] / src2 / fr / orsay / lri / varna / controlers / ControleurScriptParser.java
1 package fr.orsay.lri.varna.controlers;
2
3 import java.awt.Color;
4 import java.io.StreamTokenizer;
5 import java.io.StringReader;
6 import java.util.ArrayList;
7 import java.util.Hashtable;
8 import java.util.Vector;
9
10 import javax.swing.JOptionPane;
11
12 import fr.orsay.lri.varna.VARNAPanel;
13 import fr.orsay.lri.varna.models.annotations.ChemProbAnnotation;
14 import fr.orsay.lri.varna.models.annotations.ChemProbAnnotation.ChemProbAnnotationType;
15 import fr.orsay.lri.varna.models.rna.ModeleColorMap;
16 import fr.orsay.lri.varna.models.rna.RNA;
17
18 public class ControleurScriptParser {
19     private static String SCRIPT_ERROR_PREFIX = "Error";        
20
21
22         private static class Command{
23                 Function _f;
24                 Vector<Argument> _argv; 
25                 public Command(Function f, Vector<Argument> argv)
26                 {
27                         _f = f;
28                         _argv = argv;
29                 }
30         }; 
31
32         private static abstract class Argument{
33                 ArgumentType _t;
34                 
35                 public Argument(ArgumentType t)
36                 {
37                         _t = t;
38                 }
39                 
40                 public ArgumentType getType()
41                 {
42                         return _t;
43                 }
44                 
45                 public abstract String toString();
46                 
47         }; 
48         
49
50         private static class NumberArgument extends Argument{
51                 Number _val; 
52                 public NumberArgument(Number val)
53                 {
54                         super(ArgumentType.NUMBER_TYPE);
55                         _val = val;
56                 }
57                 public Number getNumber()
58                 {
59                         return _val;
60                 }
61                 public String toString()
62                 {
63                         return _val.toString();
64                 }
65         }; 
66         
67         private static class ColorArgument extends Argument{
68                 Color _val; 
69                 public ColorArgument(Color val)
70                 {
71                         super(ArgumentType.COLOR_TYPE);
72                         _val = val;
73                 }
74                 public Color getColor()
75                 {
76                         return _val;
77                 }
78                 public String toString()
79                 {
80                         return _val.toString();
81                 }
82         }; 
83
84         private static class BooleanArgument extends Argument{
85                 boolean _val; 
86                 public BooleanArgument(boolean val)
87                 {
88                         super(ArgumentType.BOOLEAN_TYPE);
89                         _val = val;
90                 }
91                 public boolean getBoolean()
92                 {
93                         return _val;
94                 }
95                 public String toString()
96                 {
97                         return ""+_val;
98                 }
99         }; 
100
101         private static class StringArgument extends Argument{
102                 String _val; 
103                 public StringArgument(String val)
104                 {
105                         super(ArgumentType.STRING_TYPE);
106                         _val = val;
107                 }
108                 public String toString()
109                 {
110                         return _val.toString();
111                 }
112         }; 
113
114         private static class ArrayArgument extends Argument{
115                 Vector<Argument> _val; 
116                 public ArrayArgument(Vector<Argument> val)
117                 {
118                         super(ArgumentType.ARRAY_TYPE);
119                         _val = val;
120                 }
121                 public int getSize()
122                 {
123                         return _val.size();
124                 }
125                 public Argument getArgument(int i)
126                 {
127                         return _val.get(i);
128                 }
129                 public String toString()
130                 {
131                         return _val.toString();
132                 }
133         }; 
134         
135         
136         private enum ArgumentType{
137                 STRING_TYPE,
138                 NUMBER_TYPE,
139                 BOOLEAN_TYPE,
140                 ARRAY_TYPE,
141                 COLOR_TYPE
142         };
143     
144     
145     private enum Function{
146                 ADD_CHEM_PROB("addchemprob",new ArgumentType[] {ArgumentType.NUMBER_TYPE,ArgumentType.NUMBER_TYPE,ArgumentType.STRING_TYPE,ArgumentType.NUMBER_TYPE,ArgumentType.COLOR_TYPE,ArgumentType.BOOLEAN_TYPE}),
147         ERASE_SEQ("eraseseq",new ArgumentType[] {}),
148                 RESET_CHEM_PROB("resetchemprob",new ArgumentType[] {}),
149                 SET_COLOR_MAP_MIN("setcolormapminvalue",new ArgumentType[]{ArgumentType.NUMBER_TYPE}),
150                 SET_COLOR_MAP_MAX("setcolormapmaxvalue",new ArgumentType[]{ArgumentType.NUMBER_TYPE}),
151                 SET_COLOR_MAP("setcolormap",new ArgumentType[]{ArgumentType.STRING_TYPE}),
152                 SET_CUSTOM_COLOR_MAP("setcustomcolormap",new ArgumentType[]{ArgumentType.ARRAY_TYPE}),
153                 SET_SEQ("setseq",new ArgumentType[]{ArgumentType.STRING_TYPE}),
154                 SET_STRUCT("setstruct",new ArgumentType[]{ArgumentType.STRING_TYPE}),
155                 SET_STRUCT_SMOOTH("setstructsmooth",new ArgumentType[] {ArgumentType.STRING_TYPE}),
156                 SET_TITLE("settitle",new ArgumentType[] {ArgumentType.STRING_TYPE}),
157                 SET_RNA("setrna",new ArgumentType[]{ArgumentType.STRING_TYPE,ArgumentType.STRING_TYPE}),
158                 SET_RNA_SMOOTH("setrnasmooth",new ArgumentType[]{ArgumentType.STRING_TYPE,ArgumentType.STRING_TYPE}),
159                 SET_SELECTION("setselection",new ArgumentType[]{ArgumentType.ARRAY_TYPE}),
160                 SET_VALUES("setvalues",new ArgumentType[]{ArgumentType.ARRAY_TYPE}),
161                 TOGGLE_SHOW_COLOR_MAP("toggleshowcolormap",new ArgumentType[]{}),
162                 REDRAW("redraw",new ArgumentType[] {ArgumentType.STRING_TYPE}),
163                 UNKNOWN("N/A",new ArgumentType[] {});
164                 
165                 String _funName;
166                 ArgumentType[] _args;
167                 Function(String funName, ArgumentType[] args)
168                 {
169                         _funName = funName;
170                         _args = args;
171                 }
172                 ArgumentType[] getPrototype()
173                 {
174                         return this._args;
175                 }
176                 String getFunName()
177                 {
178                         return this._funName;
179                 }
180                 
181         };
182         
183         private static Hashtable<String,Function> _name2Fun = new Hashtable<String,Function>();  
184         private static Hashtable<Function,ArgumentType[]> _fun2Prot = new Hashtable<Function,ArgumentType[]>();
185         
186         
187         private static void initFunctions()
188         {
189                 if (_name2Fun.size()>0)
190                 { return; }
191                 Function[] funs = Function.values();
192                 for(int i=0;i<funs.length;i++)
193                 {
194                         Function fun = funs[i];
195                         _name2Fun.put(fun.getFunName(),fun);
196                         _fun2Prot.put(fun,fun.getPrototype());
197                 }                       
198         }
199         
200         private static Function getFunction(String f)
201         {
202                 String s = f.trim().toLowerCase();
203                 if (_name2Fun.containsKey(s))
204                         return _name2Fun.get(s);
205                 return Function.UNKNOWN;
206         }
207
208         private static ArgumentType[] getPrototype(Function f)
209         {
210                 if (_fun2Prot.containsKey(f))
211                         return _fun2Prot.get(f);
212                 return new ArgumentType[0];
213         }       
214         
215     public static void executeScript(VARNAPanel vp, String cmdtxt) throws Exception
216     {
217         Vector<Command> cmds = parseScript(cmdtxt);
218         for(int i=0;i<cmds.size();i++)
219         {
220                 Command cmd = cmds.get(i);
221                 switch(cmd._f)
222                 {
223                         case ADD_CHEM_PROB:
224                         {
225                                 int from = (int)((NumberArgument) cmd._argv.get(0)).getNumber().intValue();
226                                 int to = (int)((NumberArgument) cmd._argv.get(1)).getNumber().intValue();
227                                 ChemProbAnnotationType t = ChemProbAnnotation.annotTypeFromString(((StringArgument) cmd._argv.get(2)).toString());
228                                 double intensity = ((NumberArgument) cmd._argv.get(3)).getNumber().doubleValue();
229                                 Color c = ((ColorArgument) cmd._argv.get(4)).getColor();
230                                 boolean out = ((BooleanArgument) cmd._argv.get(5)).getBoolean();
231                                 vp.getRNA().addChemProbAnnotation(new ChemProbAnnotation(
232                                                 vp.getRNA().getBaseAt(from),
233                                                 vp.getRNA().getBaseAt(to),
234                                                 t,
235                                                 intensity,
236                                                 c,
237                                                 out));
238                         }
239                         break;
240                         case ERASE_SEQ:
241                         {
242                                 vp.eraseSequence();
243                         }
244                         break;
245                         case RESET_CHEM_PROB:
246                         {
247                                 vp.getRNA().clearChemProbAnnotations();
248                                 vp.repaint();
249                         }
250                         break;
251                         case SET_COLOR_MAP_MIN:
252                         {
253                                 vp.setColorMapMinValue(((NumberArgument) cmd._argv.get(0)).getNumber().doubleValue());
254                         }
255                         break;
256                         case SET_COLOR_MAP_MAX:
257                         {
258                                 vp.setColorMapMaxValue(((NumberArgument) cmd._argv.get(0)).getNumber().doubleValue());
259                         }
260                         break;
261                         case SET_COLOR_MAP:
262                         {
263                                 vp.setColorMap(ModeleColorMap.parseColorMap(cmd._argv.get(0).toString()));
264                         }
265                         break;
266                         case SET_CUSTOM_COLOR_MAP:
267                         {
268                                 ModeleColorMap cm = new ModeleColorMap();
269                                 //System.out.println("a"+cmd._argv.get(0));
270                                 ArrayArgument arg = (ArrayArgument) cmd._argv.get(0);
271                                 for (int j=0;j<arg.getSize();j++)
272                                 {
273                                         Argument a = arg.getArgument(j);
274                                         if (a._t==ArgumentType.ARRAY_TYPE)
275                                         { 
276                                         //System.out.println("%");
277                                                 ArrayArgument aarg = (ArrayArgument) a; 
278                                                 if (aarg.getSize()==2)
279                                                 {
280                                                         Argument a1 = aarg.getArgument(0);
281                                                         Argument a2 = aarg.getArgument(1);
282                                                 //System.out.println("& |"+a1+"| ["+a1.getType()+"] |"+a2+"| ["+a2.getType()+"]");
283                                                         if ((a1.getType()==ArgumentType.NUMBER_TYPE)&&(a2.getType()==ArgumentType.COLOR_TYPE))
284                                                         {
285                                                 //System.out.println("+");
286                                                                 cm.addColor(((NumberArgument)a1).getNumber().doubleValue(),((ColorArgument)a2).getColor());
287                                                         }
288                                                 }
289                                         }
290                                 }                               
291                                 vp.setColorMap(cm);
292                         }
293                         break;
294                         case SET_RNA:
295                         {
296                                 String seq = cmd._argv.get(0).toString();
297                                 String str = cmd._argv.get(1).toString();
298                                 vp.drawRNA(seq, str);
299                         }
300                         break;
301                         case SET_RNA_SMOOTH:
302                         {
303                                 String seq = cmd._argv.get(0).toString();
304                                 String str = cmd._argv.get(1).toString();
305                                 vp.drawRNAInterpolated(seq, str);
306                                 vp.repaint();
307                         }
308                         break;
309                         case SET_SELECTION:
310                         {
311                                 ArrayArgument arg = (ArrayArgument) cmd._argv.get(0);
312                                 ArrayList<Integer> vals = new ArrayList<Integer>();
313                                 for (int j=0;j<arg.getSize();j++)
314                                 {
315                                         Argument a = arg.getArgument(j);
316                                         if (a._t==ArgumentType.NUMBER_TYPE)
317                                         { 
318                                                 NumberArgument narg = (NumberArgument) a; 
319                                                 vals.add(narg.getNumber().intValue()); 
320                                         }
321                                 }                               
322                                 vp.setSelection(vals);
323                                 vp.repaint();
324                         }
325                         break;  
326                         case SET_SEQ:
327                         {
328                                 String seq = cmd._argv.get(0).toString();
329                                 vp.setSequence(seq);
330                         }
331                         break;
332                         case SET_STRUCT:
333                         {
334                                 String seq = vp.getRNA().getSeq();
335                                 String str = cmd._argv.get(0).toString();
336                                 vp.drawRNA(seq, str);
337                         }
338                         break;
339                         case SET_STRUCT_SMOOTH:
340                         {
341                                 String seq = vp.getRNA().getSeq();
342                                 String str = cmd._argv.get(0).toString();
343                                 vp.drawRNAInterpolated(seq, str);
344                                 vp.repaint();
345                         }
346                         break;
347                         case SET_TITLE:
348                         {
349                                 vp.setTitle(cmd._argv.get(0).toString());
350                         }
351                         break;
352                         case SET_VALUES:
353                         {
354                                 ArrayArgument arg = (ArrayArgument) cmd._argv.get(0);
355                                 Double[] vals = new Double[arg.getSize()];
356                                 for (int j=0;j<arg.getSize();j++)
357                                 {
358                                         Argument a = arg.getArgument(j);
359                                         if (a._t==ArgumentType.NUMBER_TYPE)
360                                         { 
361                                                 NumberArgument narg = (NumberArgument) a; 
362                                                 vals[j] = narg.getNumber().doubleValue(); 
363                                         }
364                                 }                               
365                                 vp.setColorMapValues(vals);
366                                 vp.repaint();
367                         }
368                         break;
369                         case REDRAW:
370                         {
371                                 int mode = -1;
372                                 String modeStr = cmd._argv.get(0).toString().toLowerCase(); 
373                                 if (modeStr.equals("radiate"))
374                                         mode = RNA.DRAW_MODE_RADIATE;
375                                 else if (modeStr.equals("circular"))
376                                         mode = RNA.DRAW_MODE_CIRCULAR;
377                                 else if (modeStr.equals("naview"))
378                                         mode = RNA.DRAW_MODE_NAVIEW;
379                                 else if (modeStr.equals("linear"))
380                                         mode = RNA.DRAW_MODE_LINEAR;
381                                 if (mode != -1)
382                                   vp.drawRNA(vp.getRNA(), mode);
383                         }
384                         break;
385                         case TOGGLE_SHOW_COLOR_MAP:
386                         {
387                                 vp.setColorMapVisible(!vp.getColorMapVisible());
388                         }
389                         break;
390                         default:
391                                 throw new Exception(SCRIPT_ERROR_PREFIX+": Method '"+cmd._f+"' unimplemented.");
392                 }
393                 vp.repaint();
394         }
395     }
396
397         
398         
399         private static Color parseColor(String s)
400         {
401                 Color result = null;
402                 try {result = Color.decode(s); }
403                 catch (Exception e) {}
404                 return result;
405         }
406
407         private static Boolean parseBoolean(String s)
408         {
409                 Boolean result = null;
410                 if (s.toLowerCase().equals("true"))
411                         result = new Boolean(true);
412                 if (s.toLowerCase().equals("false"))
413                         result = new Boolean(false);
414                 return result;
415         }
416
417         
418         private static Vector<Argument> parseArguments(StreamTokenizer st, boolean parType) throws Exception
419         {
420                 Vector<Argument> result = new Vector<Argument>();
421                 while((st.ttype!=')' && parType) || (st.ttype!=']' && !parType))
422                 {
423                         st.nextToken();
424                           //System.out.println(""+ (parType?"Par.":"Bra.")+" "+(char)st.ttype);
425                         switch(st.ttype)
426                         {
427                           case(StreamTokenizer.TT_NUMBER):
428                           {
429                                   result.add(new NumberArgument(st.nval));
430                           }
431                           break;
432                           case(StreamTokenizer.TT_WORD):
433                           {
434                                   Color c = parseColor(st.sval);
435                                   if (c!=null)
436                                   {
437                                          result.add(new ColorArgument(c));
438                                   }
439                                   else
440                                   {
441                                           Boolean b = parseBoolean(st.sval);
442                                           if (b!=null)
443                                           {
444                                                  result.add(new BooleanArgument(b));
445                                           }
446                                           else
447                                           {
448                                                  result.add(new StringArgument(st.sval));                                         
449                                           }
450                                   }
451                           }
452                           break;
453                           case('"'):
454                           {
455                                   result.add(new StringArgument(st.sval));
456                           }
457                           break;
458                           case('['):
459                           {
460                                   result.add(new ArrayArgument(parseArguments(st, false)));
461                           }
462                           break;
463                           case('('):
464                           {
465                                   result.add(new ArrayArgument(parseArguments(st, true)));
466                           }
467                           break;
468                           case(')'):
469                           {
470                                   if (parType)
471                                     return result;
472                                   else
473                                         throw new Exception(SCRIPT_ERROR_PREFIX+": Opening "+(parType?"parenthesis":"bracket")+" matched with a closing "+(!parType?"parenthesis":"bracket"));                                    
474                           }
475                           case(']'):
476                           {
477                                   if (!parType)
478                                     return result;
479                                   else
480                                         throw new Exception(SCRIPT_ERROR_PREFIX+": Opening "+(parType?"parenthesis":"bracket")+" matched with a closing "+(!parType?"parenthesis":"bracket"));                                    
481                           }
482                           case(','):
483                                   break;
484                           case(StreamTokenizer.TT_EOF):
485                           {
486                                   throw new Exception(SCRIPT_ERROR_PREFIX+": Unmatched opening "+(parType?"parenthesis":"bracket"));
487                           }
488                           
489                         }
490                 }
491                 return result;
492         }
493         
494         
495         private static Command parseCommand(String cmd) throws Exception
496         {
497                 int cut = cmd.indexOf("(");
498                 if (cut==-1)
499                 {
500                         throw new Exception(SCRIPT_ERROR_PREFIX+": Syntax error");
501                 }
502                 String fun = cmd.substring(0,cut);
503                 Function f  = getFunction(fun);
504                 if (f==Function.UNKNOWN)
505                 { throw new Exception(SCRIPT_ERROR_PREFIX+": Unknown function \""+fun+"\""); }
506                 StreamTokenizer st = new StreamTokenizer(new StringReader(cmd.substring(cut+1)));
507                 st.eolIsSignificant(false);
508                 st.parseNumbers();
509                 st.quoteChar('\"');
510                 st.ordinaryChar('=');
511                 st.ordinaryChar(',');
512                 st.ordinaryChar('[');
513                 st.ordinaryChar(']');
514                 st.ordinaryChar('(');
515                 st.ordinaryChar(')');
516                 st.wordChars('#', '#');
517                 Vector<Argument> argv = parseArguments(st,true);
518                 checkArgs(f,argv);
519                 Command result = new Command(f,argv); 
520                 return result;
521         }
522         
523         private static boolean checkArgs(Function f, Vector<Argument> argv) throws Exception
524         {
525                 ArgumentType[] argtypes = getPrototype(f);
526                 if (argtypes.length!=argv.size())
527                         throw new Exception(SCRIPT_ERROR_PREFIX+": Wrong number of argument for function \""+f+"\".");
528                 for (int i=0;i<argtypes.length;i++)
529                 {
530                         if (argtypes[i] != argv.get(i)._t)
531                         {
532                                 throw new Exception(SCRIPT_ERROR_PREFIX+": Bad type ("+argtypes[i]+"!="+argv.get(i)._t+") for argument #"+(i+1)+" in function \""+f+"\".");
533                         }
534                 }
535                 return true;
536         }
537         
538         private static Vector<Command> parseScript(String cmd) throws Exception
539         {
540                 initFunctions();
541                 Vector<Command> cmds = new Vector<Command>();
542                 String[] data = cmd.split(";");
543                 for (int i=0;i<data.length;i++)
544                 {
545                         cmds.add(parseCommand(data[i].trim()));
546                 }
547                 return cmds;
548         }
549         
550         
551 }