Xcos: fix some issues on Xcos->Scilab actions
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / io / scicos / BlockModelElement.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - DIGITEO - ClĂ©ment DAVID
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.io.scicos;
14
15 import static java.util.Arrays.asList;
16
17 import java.util.List;
18
19 import org.scilab.modules.types.ScilabBoolean;
20 import org.scilab.modules.types.ScilabDouble;
21 import org.scilab.modules.types.ScilabList;
22 import org.scilab.modules.types.ScilabMList;
23 import org.scilab.modules.types.ScilabString;
24 import org.scilab.modules.types.ScilabTList;
25 import org.scilab.modules.types.ScilabType;
26 import org.scilab.modules.xcos.block.BasicBlock;
27 import org.scilab.modules.xcos.block.BasicBlock.SimulationFunctionType;
28 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongElementException;
29 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongStructureException;
30 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongTypeException;
31 import org.scilab.modules.xcos.port.BasicPort;
32 import org.scilab.modules.xcos.port.command.CommandPort;
33 import org.scilab.modules.xcos.port.control.ControlPort;
34
35 /**
36  * Protected class which decode model fields of a block.
37  * 
38  * This class is intentionally package-protected to prevent external use.
39  */
40 //CSOFF: ClassDataAbstractionCoupling
41 class BlockModelElement extends BlockPartsElement {
42         private static final List<String> DATA_FIELD_NAMES = asList("model", "sim",
43                         "in", "in2", "intyp", "out", "out2", "outtyp", "evtin", "evtout",
44                         "state", "dstate", "odstate", "rpar", "ipar", "opar", "blocktype",
45                         "firing", "dep_ut", "label", "nzcross", "nmode", "equations");
46
47         private static final int CTRL_PORT_INDEX = 8;
48         private static final int CMD_PORT_INDEX = 9;
49         private static final int STATE_INDEX = 10;
50         private static final int FIRING_INDEX = 17;
51         private static final int DEPENDU_INDEX = 18;
52
53         /** Mutable field to easily get the data through methods */
54         private ScilabMList data;
55         
56         /**
57          * Default constructor
58          */
59         public BlockModelElement() { }
60
61         /**
62          * Decode Scicos element into the block.
63          * 
64          * This decode method doesn't coverage Port management because we need
65          * graphics informations to handle it.
66          * 
67          * @param element
68          *            the scicos element
69          * @param into
70          *            the previously instantiated block.
71          * @return the modified into block.
72          * @throws ScicosFormatException
73          *             on error.
74          * @see org.scilab.modules.xcos.io.scicos.Element#decode(org.scilab.modules.types.ScilabType,
75          *      java.lang.Object)
76          */
77         @Override
78         public BasicBlock decode(ScilabType element, BasicBlock into)
79                         throws ScicosFormatException {
80
81                 if (into == null) {
82                         throw new IllegalArgumentException();
83                 }
84
85                 data = (ScilabMList) element;
86                 BasicBlock local = into;
87                 
88                 validate();
89                 
90                 local = beforeDecode(element, local);
91                 
92                 /*
93                  * fill the data
94                  */
95                 fillSimulationFunction(local);
96                 fillControlCommandPorts(local);
97                 fillFirstRawParameters(local);
98                 fillFiringParameters(local);
99                 fillSecondRawParameters(local);
100                 
101                 local = afterDecode(element, local);
102
103                 return local;
104         }
105
106         /**
107          * Fill the simulation data into the block
108          * 
109          * @param into
110          *            the target instance
111          */
112         private void fillSimulationFunction(BasicBlock into) {
113                 String functionName = into.getSimulationFunctionName();
114                 SimulationFunctionType functionType = into.getSimulationFunctionType();
115
116                 if (data.get(1) instanceof ScilabString) {
117                         functionName = ((ScilabString) data.get(1)).getData()[0][0];
118                 } else if ((data.get(1) instanceof ScilabList)) {
119                         functionName = ((ScilabString) ((ScilabList) data.get(1)).get(0))
120                                         .getData()[0][0];
121                         functionType = SimulationFunctionType
122                                         .convertScilabValue((int) ((ScilabDouble) ((ScilabList) data
123                                                         .get(1)).get(1)).getRealPart()[0][0]);
124                 }
125
126                 into.setSimulationFunctionName(functionName);
127                 into.setSimulationFunctionType(functionType);
128         }
129
130         /**
131          * Fill the block with the control and command ports
132          * 
133          * @param into
134          *            the target instance
135          */
136         private void fillControlCommandPorts(BasicBlock into) {
137                 ScilabDouble dataNbControlPort = (ScilabDouble) data
138                                 .get(CTRL_PORT_INDEX);
139                 ScilabDouble dataNbCommandPort = (ScilabDouble) data
140                                 .get(CMD_PORT_INDEX);
141
142                 if (dataNbControlPort.getRealPart() != null) {
143                         int nbControlPort = dataNbControlPort.getHeight();
144                         for (int i = 0; i < nbControlPort; i++) {
145                                 final BasicPort port = new ControlPort();
146                                 
147                                 // do not use BasicPort#addPort() to avoid the view update
148                                 port.setOrdering(i + 1);
149                                 into.insert(port, i);
150                         }
151                 }
152
153                 if (dataNbCommandPort.getRealPart() != null) {
154                         int nbCommandPort = dataNbCommandPort.getHeight();
155                         for (int i = 0; i < nbCommandPort; i++) {
156                                 final BasicPort port = new CommandPort();
157                                 
158                                 // do not use BasicPort#addPort() to avoid the view update
159                                 port.setOrdering(i + 1);
160                                 into.insert(port, i);
161                         }
162                 }
163         }
164
165         /**
166          * Fill the block with the first raw parameters
167          * 
168          * @param into
169          *            the target instance
170          */
171         private void fillFirstRawParameters(BasicBlock into) {
172                 // state
173                 int field = STATE_INDEX;
174                 into.setState(data.get(field));
175
176                 // dstate
177                 field++;
178                 into.setDState(data.get(field));
179
180                 // odstate
181                 field++;
182                 into.setODState(data.get(field));
183
184                 // rpar
185                 field++;
186                 into.setRealParameters(data.get(field));
187
188                 // ipar
189                 field++;
190                 into.setIntegerParameters(data.get(field));
191
192                 // opar
193                 field++;
194                 into.setObjectsParameters(data.get(field));
195
196                 // blocktype
197                 field++;
198                 into.setBlockType(((ScilabString) data.get(field)).getData()[0][0]);
199         }
200
201         /**
202          * Fill the block with the firing parameters
203          * 
204          * @param into
205          *            the target instance
206          */
207         private void fillFiringParameters(BasicBlock into) {
208                 /*
209                  * A boolean can be used to indicate that no initial event will be emitted. 
210                  */
211                 if (data.get(FIRING_INDEX) instanceof ScilabBoolean) {
212                         return;
213                 }
214                 
215                 /*
216                  * Normal behavior
217                  */
218                 final ScilabDouble firing = (ScilabDouble) data.get(FIRING_INDEX);
219
220                 if (!isEmptyField(firing)) {
221                         final List<CommandPort> allCommandPorts = BasicBlockInfo
222                                         .getAllTypedPorts(into, false, CommandPort.class);
223
224                         final boolean isColumnDominant = firing.getHeight() >= firing
225                                         .getWidth();
226                         final double[][] values = firing.getRealPart();
227                         final int[] indexes = {0, 0};
228
229                         for (int i = 0; i < allCommandPorts.size(); i++) {
230                                 allCommandPorts.get(i).setInitialState(
231                                                 values[indexes[0]][indexes[1]]);
232                                 incrementIndexes(indexes, isColumnDominant);
233                         }
234                 }
235         }
236
237         /**
238          * Fill the block with the second raw parameters
239          * 
240          * @param into
241          *            the target instance
242          */
243         private void fillSecondRawParameters(BasicBlock into) {
244                 // dep-ut
245                 int field = DEPENDU_INDEX;
246                 into.setDependsOnU(((ScilabBoolean) data.get(field)).getData()[0][0]);
247                 into.setDependsOnT(((ScilabBoolean) data.get(field)).getData()[0][1]);
248
249                 // label
250                 // do nothing
251                 field++;
252
253                 // nzcross
254                 field++;
255                 into.setNbZerosCrossing(data.get(field));
256
257                 // nmode
258                 field++;
259                 into.setNmode(data.get(field));
260
261                 // equation
262                 field++;
263                 into.setEquations(data.get(field));
264         }
265
266         /**
267          * Validate the current data.
268          * 
269          * This method doesn't pass the metrics because it perform many test.
270          * Therefore all these tests are trivial and the conditioned action only
271          * throw an exception.
272          * 
273          * @throws ScicosFormatException
274          *             when there is a validation error.
275          */
276         // CSOFF: CyclomaticComplexity
277         // CSOFF: NPathComplexity
278         // CSOFF: JavaNCSS
279         // CSOFF: MethodLength
280         private void validate() throws ScicosFormatException {
281                 if (!canDecode(data)) {
282                         throw new WrongElementException();
283                 }
284
285                 int field = 0;
286
287                 // we test if the structure as enough field
288                 if (data.size() != DATA_FIELD_NAMES.size()) {
289                         throw new WrongStructureException(DATA_FIELD_NAMES);
290                 }
291
292                 /*
293                  * Checking the MList header
294                  */
295
296                 // Check the first field
297                 if (!(data.get(field) instanceof ScilabString)) {
298                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
299                 }
300                 final String[] header = ((ScilabString) data.get(field)).getData()[0];
301
302                 // Checking for the field names
303                 if (header.length != DATA_FIELD_NAMES.size()) {
304                         throw new WrongStructureException(DATA_FIELD_NAMES);
305                 }
306                 for (int i = 0; i < header.length; i++) {
307                         if (!header[i].equals(DATA_FIELD_NAMES.get(i))) {
308                                 throw new WrongStructureException(DATA_FIELD_NAMES);
309                         }
310                 }
311
312                 /*
313                  * Checking the data
314                  */
315
316                 // sim : String or list(String, int)
317                 field++;
318                 if (!(data.get(field) instanceof ScilabString)
319                                 && !(data.get(field) instanceof ScilabList)) {
320                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
321                 }
322
323                 // in
324                 field++;
325                 if (!(data.get(field) instanceof ScilabDouble)) {
326                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
327                 }
328
329                 // in2
330                 field++;
331                 if (!(data.get(field) instanceof ScilabDouble)) {
332                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
333                 }
334
335                 // intyp
336                 field++;
337                 if (!(data.get(field) instanceof ScilabDouble)) {
338                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
339                 }
340
341                 // out
342                 field++;
343                 if (!(data.get(field) instanceof ScilabDouble)) {
344                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
345                 }
346
347                 // out2
348                 field++;
349                 if (!(data.get(field) instanceof ScilabDouble)) {
350                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
351                 }
352
353                 // outtyp
354                 field++;
355                 if (!(data.get(field) instanceof ScilabDouble)) {
356                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
357                 }
358
359                 // evtin
360                 field++;
361                 if (!(data.get(field) instanceof ScilabDouble)) {
362                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
363                 }
364
365                 // evtout
366                 field++;
367                 if (!(data.get(field) instanceof ScilabDouble)) {
368                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
369                 }
370
371                 // state
372                 field++;
373                 if (!(data.get(field) instanceof ScilabDouble)) {
374                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
375                 }
376
377                 // dstate
378                 // TODO: the ScilabString value is undocumented
379                 field++;
380                 if (!(data.get(field) instanceof ScilabDouble)
381                                 && !(data.get(field) instanceof ScilabString)) {
382                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
383                 }
384
385                 // odstate
386                 field++;
387                 if (!(data.get(field) instanceof ScilabDouble)
388                                 && !(data.get(field) instanceof ScilabList)) {
389                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
390                 }
391
392                 // rpar
393                 // SuperBlocks store all "included" data in rpar field.
394                 field++;
395                 if (!(data.get(field) instanceof ScilabDouble)
396                                 && !(data.get(field) instanceof ScilabMList)
397                                 && !(data.get(field) instanceof ScilabString)) {
398                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
399                 }
400
401                 // ipar
402                 // !! WARNING !! scifunc_block_m ipar = list(...)
403                 field++;
404                 if (!(data.get(field) instanceof ScilabDouble)
405                                 && !(data.get(field) instanceof ScilabList)) {
406                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
407                 }
408
409                 // opar
410                 field++;
411                 if (!(data.get(field) instanceof ScilabDouble)
412                                 && !(data.get(field) instanceof ScilabList)) {
413                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
414                 }
415
416                 // blocktype
417                 field++;
418                 if (!(data.get(field) instanceof ScilabString)) {
419                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
420                 }
421
422                 // firing
423                 field++;
424                 if (!(data.get(field) instanceof ScilabDouble)
425                                 && !(data.get(field) instanceof ScilabBoolean)) {
426                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
427                 }
428
429                 // dep-ut
430                 field++;
431                 if (!(data.get(field) instanceof ScilabBoolean)) {
432                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
433                 }
434
435                 // label
436                 field++;
437                 if (!(data.get(field) instanceof ScilabString)) {
438                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
439                 }
440
441                 // nzcross
442                 field++;
443                 if (!(data.get(field) instanceof ScilabDouble)) {
444                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
445                 }
446
447                 // nmode
448                 field++;
449                 if (!(data.get(field) instanceof ScilabDouble)) {
450                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
451                 }
452
453                 // equations
454                 field++;
455                 if (!(data.get(field) instanceof ScilabTList)
456                                 && !isEmptyField(data.get(field))) {
457                         throw new WrongTypeException(DATA_FIELD_NAMES, field);
458                 }
459         }
460         // CSON: CyclomaticComplexity
461         // CSON: NPathComplexity
462         // CSON: JavaNCSS
463         // CSON: MethodLength
464
465         /**
466          * Check if the element can be decoded.
467          * 
468          * @param element
469          *            the Scicos element
470          * @return true, if the Scicos types match.
471          * @see org.scilab.modules.xcos.io.scicos.Element#canDecode(org.scilab.modules.types.ScilabType)
472          */
473         @Override
474         public boolean canDecode(ScilabType element) {
475                 data = (ScilabMList) element;
476
477                 final String type = ((ScilabString) data.get(0)).getData()[0][0];
478                 return type.equals(DATA_FIELD_NAMES.get(0));
479         }
480
481         /**
482          * Encode the instance into the element
483          * 
484          * @param from the source instance
485          * @param element must be null.
486          * @return the element parameter
487          * @see org.scilab.modules.xcos.io.scicos.Element#encode(java.lang.Object, org.scilab.modules.types.ScilabType)
488          */
489         // CSOFF: JavaNCSS
490         @Override
491         public ScilabType encode(BasicBlock from, ScilabType element) {
492                 data = (ScilabMList) element;
493                 int field = 0;
494                 ScilabType property;
495                 
496                 if (data == null) {
497                         data = allocateElement();
498                 } else {
499                         throw new IllegalArgumentException("The element parameter must be null.");
500                 }
501                 
502                 data = (ScilabMList) beforeEncode(from, data);
503                 
504                 /*
505                  * Fill the element
506                  */
507                 field++; // sim
508                 data.set(field, from.getSimulationFunctionNameAndType());
509                 
510                 /*
511                  * Fields managed by specific elements :
512                  *  - in
513                  *  - in2
514                  *  - intyp
515                  *  - out
516                  *  - out2
517                  *  - outyp
518                  * see InputPortElement and OutputPortElement.
519                  */
520                 field++; // in
521                 field++; // in2
522                 field++; // intyp
523                 field++; // out
524                 field++; // out2
525                 field++; // outtyp
526                 
527                 /*
528                  * Event ports
529                  */
530                 field++; // evtin
531                 final List<ControlPort> ctrlPorts = BasicBlockInfo.getAllTypedPorts(from, false, ControlPort.class);
532                 data.set(field, BasicBlockInfo.getAllPortsDataLines(ctrlPorts));
533                 field++; // evtout
534                 final List<CommandPort> cmdPorts = BasicBlockInfo.getAllTypedPorts(from, false, CommandPort.class);
535                 data.set(field, BasicBlockInfo.getAllPortsDataLines(cmdPorts));
536                 
537                 /*
538                  * State
539                  */
540                 field++; // state
541                 data.set(field, from.getState());
542                 field++; // dstate
543                 data.set(field, from.getDState());
544                 field++; // odstate
545                 data.set(field, from.getODState());
546                 
547                 /*
548                  * Parameters
549                  */
550                 field++; // rpar
551                 property = from.getRealParameters();
552                 if (property == null) {
553                         property = new ScilabDouble();
554                 }
555                 data.set(field, property);
556                 
557                 field++; // ipar
558                 property = from.getIntegerParameters();
559                 if (property == null) {
560                         property = new ScilabDouble();
561                 }
562                 data.set(field, property);
563                 
564                 field++; // opar
565                 property = from.getObjectsParameters();
566                 if (property == null) {
567                         property = new ScilabDouble();
568                 }
569                 data.set(field, property);
570                 
571                 field++; // blocktype
572                 data.set(field, new ScilabString(from.getBlockType()));
573                 
574                 field++; // firing
575                 property = from.getAllCommandPortsInitialStates();
576                 if (property == null) {
577                         property = new ScilabDouble();
578                 }
579                 data.set(field, property);
580                 
581                 field++; // dep_ut
582                 boolean[][] dependsOnUandT = {{from.isDependsOnU() , from.isDependsOnT()}};
583                 data.set(field, new ScilabBoolean(dependsOnUandT));
584                 
585                 field++; // label
586                 data.set(field, new ScilabString(from.getId()));
587                 
588                 field++; // nzcross
589                 property = from.getNbZerosCrossing();
590                 if (property == null) {
591                         property = new ScilabDouble();
592                 }
593                 data.set(field, property);
594                 
595                 field++; // nmode
596                 property = from.getNmode();
597                 if (property == null) {
598                         property = new ScilabDouble();
599                 }
600                 data.set(field, property);
601                 
602                 field++; // equations
603                 property = from.getEquations();
604                 if (property == null) {
605                         property = new ScilabList();
606                 }
607                 data.set(field, property);
608                 
609                 data = (ScilabMList) afterEncode(from, data);
610                 
611                 return data;
612         }
613         // CSON: JavaNCSS
614         
615         /**
616          * Allocate a new element
617          * @return the new element
618          */
619         private ScilabMList allocateElement() {
620                 ScilabMList element = new ScilabMList(DATA_FIELD_NAMES.toArray(new String[0]));
621                 element.add(new ScilabList()); // sim
622                 addSizedPortVector(element, ScilabDouble.class, getInSize()); // in
623                 addSizedPortVector(element, ScilabDouble.class, getInSize()); // in2
624                 addSizedPortVector(element, ScilabDouble.class, getInSize()); // intyp
625                 addSizedPortVector(element, ScilabDouble.class, getOutSize()); // out
626                 addSizedPortVector(element, ScilabDouble.class, getOutSize()); // out2
627                 addSizedPortVector(element, ScilabDouble.class, getOutSize()); // outtyp
628                 addSizedPortVector(element, ScilabDouble.class, getEinSize()); // evtin
629                 addSizedPortVector(element, ScilabDouble.class, getEoutSize()); // evtout
630                 element.add(new ScilabDouble()); // state
631                 element.add(new ScilabDouble()); // dstate
632                 element.add(new ScilabDouble()); // ostate
633                 element.add(new ScilabDouble()); // rpar
634                 element.add(new ScilabDouble()); // ipar
635                 element.add(new ScilabDouble()); // opar
636                 element.add(new ScilabString()); // blocktype
637                 element.add(new ScilabDouble()); // firing
638                 element.add(new ScilabDouble()); // dep_ut
639                 element.add(new ScilabString("")); // label
640                 element.add(new ScilabDouble()); // nzcross
641                 element.add(new ScilabDouble()); // nmode
642                 element.add(new ScilabList()); // equations
643                 return element;
644         }
645 }
646 //CSON: ClassDataAbstractionCoupling