Salome HOME
29cf49595c8f4fefe35ae6873793d6119c89f80a
[modules/yacs.git] / src / engine / ForEachLoop.cxx
1 // Copyright (C) 2006-2013  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "ForEachLoop.hxx"
21 #include "TypeCode.hxx"
22 #include "Visitor.hxx"
23 #include "ComposedNode.hxx"
24 #include <iostream>
25 #include <sstream>
26
27 //#define _DEVDEBUG_
28 #include "YacsTrace.hxx"
29
30 using namespace YACS::ENGINE;
31 using namespace std;
32
33 /*! \class YACS::ENGINE::ForEachLoop
34  *  \brief Loop node for parametric calculation
35  *
36  *  \ingroup Nodes
37  */
38
39 const char FakeNodeForForEachLoop::NAME[]="thisIsAFakeNode";
40
41 const char SplitterNode::NAME_OF_SEQUENCE_INPUT[]="SmplsCollection";
42
43 const char ForEachLoop::NAME_OF_SPLITTERNODE[]="splitter";
44
45 const int ForEachLoop::NOT_RUNNING_BRANCH_ID=-1;
46
47 InterceptorInputPort::InterceptorInputPort(const std::string& name, Node *node, TypeCode* type):AnyInputPort(name,node,type),
48                                                                                                 DataPort(name,node,type),Port(node),
49                                                                                                 _repr(0)
50 {
51 }
52
53 InterceptorInputPort::InterceptorInputPort(const  InterceptorInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),
54                                                                                                 Port(other,newHelder),
55                                                                                                 _repr(0)
56 {
57 }
58
59 void InterceptorInputPort::getAllRepresentants(std::set<InPort *>& repr) const
60 {
61   set<InPort *> ports=_repr->edSetInPort();
62   for(set<InPort *>::iterator iter=ports.begin();iter!=ports.end();iter++)
63     (*iter)->getAllRepresentants(repr);
64 }
65
66 InputPort *InterceptorInputPort::clone(Node *newHelder) const
67 {
68   return new InterceptorInputPort(*this,newHelder);
69 }
70
71 void InterceptorInputPort::setRepr(AnySplitOutputPort *repr)
72 {
73   _repr=repr;
74 }
75
76 bool AnySplitOutputPort::decrRef()
77 {
78   return (--_cnt==0);
79 }
80
81 void AnySplitOutputPort::incrRef() const
82 {
83   _cnt++;
84 }
85
86 AnySplitOutputPort::AnySplitOutputPort(const std::string& name, Node *node, TypeCode *type):OutputPort(name,node,type),
87                                                                                             DataPort(name,node,type),Port(node),
88                                                                                             _repr(0),_intercptr(0),_cnt(1)
89 {
90 }
91
92 AnySplitOutputPort::AnySplitOutputPort(const AnySplitOutputPort& other, Node *newHelder):OutputPort(other,newHelder),
93                                                                                          DataPort(other,newHelder),
94                                                                                          Port(other,newHelder),
95                                                                                          _repr(0),_intercptr(0),_cnt(1)
96 {
97 }
98
99 bool AnySplitOutputPort::addInPort(InPort *inPort) throw(YACS::Exception)
100 {
101   bool ret=OutputPort::addInPort(inPort);
102   if(_repr)
103     _repr->addInPort(_intercptr);
104   return ret;
105 }
106
107 void AnySplitOutputPort::getAllRepresented(std::set<OutPort *>& represented) const
108 {
109   if(!_repr)
110     OutPort::getAllRepresented(represented);
111   else
112     _repr->getAllRepresented(represented);
113 }
114
115 int AnySplitOutputPort::removeInPort(InPort *inPort, bool forward) throw(YACS::Exception)
116 {
117   bool ret=OutputPort::removeInPort(inPort,forward);
118   if(_repr)
119     if(_setOfInputPort.empty())
120       _repr->removeInPort(_intercptr,forward);
121   return ret;
122 }
123
124 void AnySplitOutputPort::addRepr(OutPort *repr, InterceptorInputPort *intercptr)
125 {
126   _repr=repr;
127   _intercptr=intercptr;
128 }
129
130 OutputPort *AnySplitOutputPort::clone(Node *newHelder) const
131 {
132   return new AnySplitOutputPort(*this,newHelder);
133 }
134
135 SeqAnyInputPort::SeqAnyInputPort(const std::string& name, Node *node, TypeCodeSeq* type):AnyInputPort(name,node,type),DataPort(name,node,type),Port(node)
136 {
137   _type->decrRef();
138 }
139
140 SeqAnyInputPort::SeqAnyInputPort(const  SeqAnyInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),Port(other,newHelder)
141 {
142 }
143
144 InputPort *SeqAnyInputPort::clone(Node *newHelder) const
145 {
146   return new SeqAnyInputPort(*this,newHelder);
147 }
148
149 unsigned SeqAnyInputPort::getNumberOfElements() const
150 {
151   const SequenceAny * valCsted=(const SequenceAny *) _value;
152   if (valCsted) return valCsted->size();
153   return 0;
154 }
155
156 Any *SeqAnyInputPort::getValueAtRank(int i) const
157 {
158   const SequenceAny * valCsted=(const SequenceAny *) _value;
159   AnyPtr ret=(*valCsted)[i];
160   ret->incrRef();
161   return ret;
162 }
163
164 std::string SeqAnyInputPort::dump()
165 {
166   stringstream xmldump;
167   int nbElem = getNumberOfElements();
168   xmldump << "<value><array><data>" << endl;
169   for (int i = 0; i < nbElem; i++)
170     {
171       Any *val = getValueAtRank(i);
172       switch (val->getType()->kind())
173         {
174         case Double:
175           xmldump << "<value><double>" << val->getDoubleValue() << "</double></value>" << endl;
176           break;
177         case Int:
178           xmldump << "<value><int>" << val->getIntValue() << "</int></value>" << endl;
179           break;
180         case Bool:
181           xmldump << "<value><boolean>" << val->getBoolValue() << "</boolean></value>" << endl;
182           break;
183         case String:
184           xmldump << "<value><string>" << val->getStringValue() << "</string></value>" << endl;
185           break;
186         case Objref:
187           xmldump << "<value><objref>" << val->getStringValue() << "</objref></value>" << endl;
188           break;
189         default:
190           xmldump << "<value><error> NO_SERIALISATION_AVAILABLE </error></value>" << endl;
191           break;
192         }
193     }
194   xmldump << "</data></array></value>" << endl;
195   return xmldump.str();
196 }
197
198 SplitterNode::SplitterNode(const std::string& name, TypeCode *typeOfData, 
199                            ForEachLoop *father):ElementaryNode(name),
200                                                 _dataPortToDispatch(NAME_OF_SEQUENCE_INPUT,
201                                                                     this,(TypeCodeSeq *)TypeCode::sequenceTc("","",typeOfData))
202 {
203   _father=father;
204 }
205
206 SplitterNode::SplitterNode(const SplitterNode& other, ForEachLoop *father):ElementaryNode(other,father),
207                                                                            _dataPortToDispatch(other._dataPortToDispatch,this)
208 {
209 }
210
211 InputPort *SplitterNode::getInputPort(const std::string& name) const throw(YACS::Exception)
212 {
213   if(name==NAME_OF_SEQUENCE_INPUT)
214     return (InputPort *)&_dataPortToDispatch;
215   else
216     return ElementaryNode::getInputPort(name);
217 }
218
219 Node *SplitterNode::simpleClone(ComposedNode *father, bool editionOnly) const
220 {
221   return new SplitterNode(*this,(ForEachLoop *)father);
222 }
223
224 unsigned SplitterNode::getNumberOfElements() const
225 {
226   return _dataPortToDispatch.getNumberOfElements();
227 }
228
229 void SplitterNode::execute()
230 {
231   //Nothing : should never been called elsewhere big problem...
232 }
233
234 void SplitterNode::init(bool start)
235 {
236   ElementaryNode::init(start);
237   _dataPortToDispatch.exInit(start);
238 }
239
240 void SplitterNode::putSplittedValueOnRankTo(int rankInSeq, int branch, bool first)
241 {
242   Any *valueToDispatch=_dataPortToDispatch.getValueAtRank(rankInSeq);
243   ForEachLoop *fatherTyped=(ForEachLoop *)_father;
244   fatherTyped->putValueOnBranch(valueToDispatch,branch,first);
245   valueToDispatch->decrRef();
246 }
247
248 FakeNodeForForEachLoop::FakeNodeForForEachLoop(ForEachLoop *loop, bool normalFinish):ElementaryNode(NAME),
249                                                                                      _loop(loop),
250                                                                                      _normalFinish(normalFinish)
251 {
252   _state=YACS::TOACTIVATE;
253   _father=_loop->getFather();
254 }
255
256 FakeNodeForForEachLoop::FakeNodeForForEachLoop(const FakeNodeForForEachLoop& other):ElementaryNode(other),_loop(0),
257                                                                                     _normalFinish(false)
258 {
259 }
260
261 Node *FakeNodeForForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
262 {
263   return new FakeNodeForForEachLoop(*this);
264 }
265
266 void FakeNodeForForEachLoop::exForwardFailed()
267 {
268   _loop->exForwardFailed();
269 }
270
271 void FakeNodeForForEachLoop::exForwardFinished()
272
273   _loop->exForwardFinished();
274 }
275
276 void FakeNodeForForEachLoop::execute()
277 {
278   if(!_normalFinish)
279     throw Exception("");//only to trigger ABORT on Executor
280   else
281     _loop->pushAllSequenceValues();
282 }
283
284 void FakeNodeForForEachLoop::aborted()
285 {
286   _loop->setState(YACS::ERROR);
287 }
288
289 void FakeNodeForForEachLoop::finished()
290 {
291   _loop->setState(YACS::DONE);
292 }
293
294 ForEachLoop::ForEachLoop(const std::string& name, TypeCode *typeOfDataSplitted):DynParaLoop(name,typeOfDataSplitted),
295                                                                                 _splitterNode(NAME_OF_SPLITTERNODE,typeOfDataSplitted,this),
296                                                                                 _execCurrentId(0),_nodeForSpecialCases(0)
297 {
298 }
299
300 ForEachLoop::ForEachLoop(const ForEachLoop& other, ComposedNode *father, bool editionOnly):DynParaLoop(other,father,editionOnly),
301                                                                                            _splitterNode(other._splitterNode,this),
302                                                                                            _execCurrentId(0),_nodeForSpecialCases(0)
303 {
304   int i=0;
305   if(!editionOnly)
306     for(vector<AnySplitOutputPort *>::const_iterator iter2=other._outGoingPorts.begin();iter2!=other._outGoingPorts.end();iter2++,i++)
307       {
308         AnySplitOutputPort *temp=new AnySplitOutputPort(*(*iter2),this);
309         InterceptorInputPort *interc=new InterceptorInputPort(*other._intecptrsForOutGoingPorts[i],this);
310         temp->addRepr(getOutPort((*iter2)->getName()),interc);
311         interc->setRepr(temp);
312         _outGoingPorts.push_back(temp);
313         _intecptrsForOutGoingPorts.push_back(interc);
314       }
315 }
316
317 Node *ForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
318 {
319   return new ForEachLoop(*this,father,editionOnly);
320 }
321
322 ForEachLoop::~ForEachLoop()
323 {
324   cleanDynGraph();
325   for(vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
326     delete *iter;
327   for(vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();iter2!=_intecptrsForOutGoingPorts.end();iter2++)
328     delete *iter2;
329 }
330
331 void ForEachLoop::init(bool start)
332 {
333   DynParaLoop::init(start);
334   _splitterNode.init(start);
335   _execCurrentId=0;
336   cleanDynGraph();
337 }
338
339 void ForEachLoop::exUpdateState()
340 {
341   DEBTRACE("ForEachLoop::exUpdateState");
342   if(_state == YACS::DISABLED)
343     return;
344   if(_inGate.exIsReady())
345     {
346       //internal graph update
347       int i;
348       int nbOfBr=_nbOfBranches.getIntValue();
349       int nbOfElts=_splitterNode.getNumberOfElements();
350
351       DEBTRACE("nbOfElts=" << nbOfElts);
352       DEBTRACE("nbOfBr=" << nbOfBr);
353
354       if(nbOfElts==0)
355         {
356           prepareSequenceValues(0);
357           delete _nodeForSpecialCases;
358           _nodeForSpecialCases=new FakeNodeForForEachLoop(this,true);
359           setState(YACS::ACTIVATED);
360           return ;
361         }
362       if(nbOfBr<=0)
363         {
364           delete _nodeForSpecialCases;
365           _nodeForSpecialCases=new FakeNodeForForEachLoop(this,getAllOutPortsLeavingCurrentScope().empty());
366           setState(YACS::ACTIVATED);
367           return ;
368         }
369       if(nbOfBr>nbOfElts)
370         nbOfBr=nbOfElts;
371       _execNodes.resize(nbOfBr);
372       _execIds.resize(nbOfBr);
373       _execOutGoingPorts.resize(nbOfBr);
374       prepareSequenceValues(nbOfElts);
375       if(_initNode)
376         _execInitNodes.resize(nbOfBr);
377       _initializingCounter = 0;
378       if (_finalizeNode)
379         _execFinalizeNodes.resize(nbOfBr);
380
381       vector<Node *> origNodes;
382       origNodes.push_back(_initNode);
383       origNodes.push_back(_node);
384       origNodes.push_back(_finalizeNode);
385
386       //Conversion exceptions can be thrown by createOutputOutOfScopeInterceptors 
387       //so catch them to control errors
388       try
389         {
390           for(i=0;i<nbOfBr;i++)
391             {
392               DEBTRACE( "-------------- 1 " << i << " " << _execCurrentId);
393               _execIds[i]=_execCurrentId;
394               DEBTRACE( "-------------- 2" );
395               vector<Node *> clonedNodes = cloneAndPlaceNodesCoherently(origNodes);
396               if(_initNode)
397                 _execInitNodes[i] = clonedNodes[0];
398               _execNodes[i] = clonedNodes[1];
399               if(_finalizeNode)
400                 _execFinalizeNodes[i] = clonedNodes[2];
401               DEBTRACE( "-------------- 4" );
402               prepareInputsFromOutOfScope(i);
403               DEBTRACE( "-------------- 5" );
404               createOutputOutOfScopeInterceptors(i);
405               DEBTRACE( "-------------- 6" );
406               _splitterNode.putSplittedValueOnRankTo(_execCurrentId++,i,true);
407               DEBTRACE( "-------------- 7" );
408             } 
409         }
410       catch(YACS::Exception& ex)
411         {
412           //ForEachLoop must be put in error and the exception rethrown to notify the caller
413           DEBTRACE( "ForEachLoop::exUpdateState: " << ex.what() );
414           setState(YACS::ERROR);
415           exForwardFailed();
416           throw;
417         }
418
419       setState(YACS::ACTIVATED); // move the calling of setState method there for adding observers for clone nodes in GUI part
420
421       //let's go
422       for(i=0;i<nbOfBr;i++)
423         if(_initNode)
424           {
425             _execInitNodes[i]->exUpdateState();
426             _initializingCounter++;
427           }
428         else
429           {
430             _nbOfEltConsumed++;
431             _execNodes[i]->exUpdateState();
432           }
433
434       forwardExecStateToOriginalBody(_execNodes[nbOfBr-1]);
435     }
436 }
437
438 void ForEachLoop::getReadyTasks(std::vector<Task *>& tasks)
439 {
440   if(!_node)
441     return;
442   if(_state==YACS::TOACTIVATE) setState(YACS::ACTIVATED);
443   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
444     {
445       if(_nodeForSpecialCases)
446         {
447           _nodeForSpecialCases->getReadyTasks(tasks);
448           return ;
449         }
450       vector<Node *>::iterator iter;
451       for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
452         (*iter)->getReadyTasks(tasks);
453       for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
454         (*iter)->getReadyTasks(tasks);
455       for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
456         (*iter)->getReadyTasks(tasks);
457     }
458 }
459
460 int ForEachLoop::getNumberOfInputPorts() const
461 {
462   return DynParaLoop::getNumberOfInputPorts()+1;
463 }
464
465 void ForEachLoop::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
466 {
467   //TO DO
468 }
469
470 void ForEachLoop::selectRunnableTasks(std::vector<Task *>& tasks)
471 {
472 }
473
474 std::list<InputPort *> ForEachLoop::getSetOfInputPort() const
475 {
476   list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
477   ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
478   return ret;
479 }
480
481 std::list<InputPort *> ForEachLoop::getLocalInputPorts() const
482 {
483   list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
484   ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
485   return ret;
486 }
487
488 InputPort *ForEachLoop::getInputPort(const std::string& name) const throw(YACS::Exception)
489 {
490   if(name==SplitterNode::NAME_OF_SEQUENCE_INPUT)
491     return (InputPort *)&_splitterNode._dataPortToDispatch;
492   else
493     return DynParaLoop::getInputPort(name);
494 }
495
496 OutputPort *ForEachLoop::getOutputPort(const std::string& name) const throw(YACS::Exception)
497 {
498   for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
499     {
500       if(name==(*iter)->getName())
501         return (OutputPort *)(*iter);
502     }
503   return DynParaLoop::getOutputPort(name);
504 }
505
506 OutPort *ForEachLoop::getOutPort(const std::string& name) const throw(YACS::Exception)
507 {
508   for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
509     {
510       if(name==(*iter)->getName())
511         return (OutPort *)(*iter);
512     }
513   return DynParaLoop::getOutPort(name);
514 }
515
516 Node *ForEachLoop::getChildByShortName(const std::string& name) const throw(YACS::Exception)
517 {
518   if(name==NAME_OF_SPLITTERNODE)
519     return (Node *)&_splitterNode;
520   else
521     return DynParaLoop::getChildByShortName(name);
522 }
523
524 //! Method used to notify the node that a child node has finished
525 /*!
526  * Update the current state and return the change state
527  *
528  *  \param node : the child node that has finished
529  *  \return the state change
530  */
531 YACS::Event ForEachLoop::updateStateOnFinishedEventFrom(Node *node)
532 {
533   DEBTRACE("updateStateOnFinishedEventFrom " << node->getName() << " " << node->getState());
534   unsigned int id;
535   switch(getIdentityOfNotifyerNode(node,id))
536     {
537     case INIT_NODE:
538       _execNodes[id]->exUpdateState();
539       _nbOfEltConsumed++;
540       _initializingCounter--;
541       if (_initializingCounter == 0) _initNode->setState(DONE);
542       break;
543     case WORK_NODE:
544       storeOutValsInSeqForOutOfScopeUse(_execIds[id],id);
545       if(_execCurrentId==_splitterNode.getNumberOfElements())
546         {//No more elements of _dataPortToDispatch to treat
547           _execIds[id]=NOT_RUNNING_BRANCH_ID;
548           //analyzing if some samples are still on treatment on other branches.
549           bool isFinished=true;
550           for(int i=0;i<_execIds.size() && isFinished;i++)
551             isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
552           if(isFinished)
553             {
554               try 
555                 {
556                   pushAllSequenceValues();
557   
558                   if (_node)
559                     {
560                       _node->setState(YACS::DONE);
561      
562                       ComposedNode* compNode = dynamic_cast<ComposedNode*>(_node);
563                       if (compNode)
564                         {
565                           std::list<Node *> aChldn = compNode->getAllRecursiveConstituents();
566                           std::list<Node *>::iterator iter=aChldn.begin();
567                           for(;iter!=aChldn.end();iter++)
568                             (*iter)->setState(YACS::DONE);
569                         }
570                     }
571
572                   if (_finalizeNode == NULL)
573                     {
574                       // No finalize node, we just finish the loop at the end of exec nodes execution
575                       setState(YACS::DONE);
576                       return YACS::FINISH;
577                     }
578                   else
579                     {
580                       // Run the finalize nodes, the loop will be done only when they all finish
581                       _unfinishedCounter = 0;  // This counter indicates how many branches are not finished
582                       for (int i=0 ; i<_execIds.size() ; i++)
583                         {
584                           YASSERT(_execIds[i] == NOT_RUNNING_BRANCH_ID);
585                           DEBTRACE("Launching finalize node for branch " << i);
586                           _execFinalizeNodes[i]->exUpdateState();
587                           _unfinishedCounter++;
588                         }
589                       return YACS::NOEVENT;
590                     }
591                 }
592               catch(YACS::Exception& ex)
593                 {
594                   DEBTRACE("ForEachLoop::updateStateOnFinishedEventFrom: "<<ex.what());
595                   //no way to push results : put following nodes in FAILED state
596                   //TODO could be more fine grain : put only concerned nodes in FAILED state
597                   exForwardFailed();
598                   setState(YACS::ERROR);
599                   return YACS::ABORT;
600                 }
601             }
602         }
603       else if(_state == YACS::ACTIVATED)
604         {//more elements to do and loop still activated
605           _execIds[id]=_execCurrentId;
606           node->init(false);
607           _splitterNode.putSplittedValueOnRankTo(_execCurrentId++,id,false);
608           node->exUpdateState();
609           forwardExecStateToOriginalBody(node);
610           _nbOfEltConsumed++;
611         }
612       else
613         {//elements to process and loop no more activated
614           DEBTRACE("foreach loop state " << _state);
615         }
616       break;
617     case FINALIZE_NODE:
618     {
619       DEBTRACE("Finalize node finished on branch " << id);
620       _unfinishedCounter--;
621       DEBTRACE(_unfinishedCounter << " finalize nodes still running");
622       if (_unfinishedCounter == 0)
623         {
624           _finalizeNode->setState(YACS::DONE);
625           setState(YACS::DONE);
626           return YACS::FINISH;
627         }
628       else
629         return YACS::NOEVENT;
630       break;
631     }
632     default:
633       YASSERT(false);
634     }
635   return YACS::NOEVENT;
636 }
637
638 void ForEachLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
639 {
640   DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
641   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
642   if(typeOfPortInstance==OutputPort::NAME)
643     {
644       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
645       int i=0;
646       for(;iter!=_outGoingPorts.end();iter++,i++)
647         if((*iter)->getRepr()==port.first)
648           break;
649       if(iter!=_outGoingPorts.end())
650         {
651           (*iter)->incrRef();
652           (*iter)->addRepr(port.first,_intecptrsForOutGoingPorts[i]);
653           port.first=*iter;
654         }
655       else
656         {
657           TypeCodeSeq *newTc=(TypeCodeSeq *)TypeCode::sequenceTc("","",port.first->edGetType());
658           AnySplitOutputPort *newPort=new AnySplitOutputPort(getPortName(port.first),this,newTc);
659           InterceptorInputPort *intercptor=new InterceptorInputPort(string("intercptr for ")+getPortName(port.first),this,port.first->edGetType());
660           intercptor->setRepr(newPort);
661           newTc->decrRef();
662           newPort->addRepr(port.first,intercptor);
663           _outGoingPorts.push_back(newPort);
664           _intecptrsForOutGoingPorts.push_back(intercptor);
665           port.first=newPort;
666         }
667     }
668   else
669     throw Exception("ForEachLoop::buildDelegateOf : not implemented for DS because not specified");
670 }
671
672 void ForEachLoop::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
673 {
674   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
675   if(typeOfPortInstance==OutputPort::NAME)
676     {
677       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
678       for(;iter!=_outGoingPorts.end();iter++)
679         if((*iter)->getRepr()==port.first)
680           break;
681       if(iter==_outGoingPorts.end())
682         {
683           string what("ForEachLoop::getDelegateOf : Port with name "); what+=port.first->getName(); what+=" not exported by ForEachLoop "; what+=_name; 
684           throw Exception(what);
685         }
686       else
687         port.first=(*iter);
688     }
689   else
690     throw Exception("ForEachLoop::getDelegateOf : not implemented because not specified");
691 }
692
693 void ForEachLoop::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
694 {
695   string typeOfPortInstance=portDwn->getNameOfTypeOfCurrentInstance();
696   if(typeOfPortInstance==OutputPort::NAME)
697     {
698       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
699       vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();
700       for(;iter!=_outGoingPorts.end();iter++,iter2++)
701         if((*iter)->getRepr()==portDwn)
702           break;
703       //ASSERT(portUp==*iter.second)
704       if((*iter)->decrRef())
705         {
706           AnySplitOutputPort *p=*iter;
707           _outGoingPorts.erase(iter);
708           delete p;
709           InterceptorInputPort *ip=*iter2;
710           _intecptrsForOutGoingPorts.erase(iter2);
711           delete ip;
712         }
713     }
714 }
715
716 OutPort *ForEachLoop::getDynOutPortByAbsName(int branchNb, const std::string& name)
717 {
718   string portName, nodeName;
719   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
720   Node *staticChild = getChildByName(nodeName);
721   return _execNodes[branchNb]->getOutPort(portName);//It's impossible(garanteed by YACS::ENGINE::ForEachLoop::buildDelegateOf)
722   //that a link starting from _initNode goes out of scope of 'this'.
723 }
724
725 void ForEachLoop::cleanDynGraph()
726 {
727   DynParaLoop::cleanDynGraph();
728   for(vector< SequenceAny *>::iterator iter3=_execVals.begin();iter3!=_execVals.end();iter3++)
729     (*iter3)->decrRef();
730   _execVals.clear();
731   for(vector< vector<AnyInputPort *> >::iterator iter4=_execOutGoingPorts.begin();iter4!=_execOutGoingPorts.end();iter4++)
732     for(vector<AnyInputPort *>::iterator iter5=(*iter4).begin();iter5!=(*iter4).end();iter5++)
733       delete *iter5;
734   _execOutGoingPorts.clear();
735 }
736
737 void ForEachLoop::storeOutValsInSeqForOutOfScopeUse(int rank, int branchNb)
738 {
739   vector<AnyInputPort *>::iterator iter;
740   int i=0;
741   for(iter=_execOutGoingPorts[branchNb].begin();iter!=_execOutGoingPorts[branchNb].end();iter++,i++)
742     {
743       Any *val=(Any *)(*iter)->getValue();
744       _execVals[i]->setEltAtRank(rank,val);
745     }
746 }
747
748 void ForEachLoop::prepareSequenceValues(int sizeOfSamples)
749 {
750   _execVals.resize(_outGoingPorts.size());
751   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
752   for(int i=0;iter!=_outGoingPorts.end();iter++,i++)
753     _execVals[i]=SequenceAny::New((*iter)->edGetType()->contentType(),sizeOfSamples);
754 }
755
756 void ForEachLoop::pushAllSequenceValues()
757 {
758   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
759   int i=0;
760   for(;iter!=_outGoingPorts.end();iter++,i++)
761     (*iter)->put((const void *)_execVals[i]);
762 }
763
764 void ForEachLoop::createOutputOutOfScopeInterceptors(int branchNb)
765 {
766   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
767   int i=0;
768   for(;iter!=_outGoingPorts.end();iter++,i++)
769     {
770       DEBTRACE( (*iter)->getName() << " " << (*iter)->edGetType()->kind() );
771       //AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,(*iter)->edGetType());
772       OutPort *portOut=getDynOutPortByAbsName(branchNb,getOutPortName(((*iter)->getRepr())));
773       DEBTRACE( portOut->getName() );
774       AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,portOut->edGetType());
775       portOut->addInPort(interceptor);
776       _execOutGoingPorts[branchNb].push_back(interceptor);
777     }
778 }
779
780 void ForEachLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
781                                        InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
782 {
783   if(isInMyDescendance(start->getNode())==_node)
784     throw Exception("ForEachLoop::checkLinkPossibility : A link from work node to init node not permitted");
785 }
786
787 std::list<OutputPort *> ForEachLoop::getLocalOutputPorts() const
788 {
789   list<OutputPort *> ret;
790   ret.push_back(getOutputPort(NAME_OF_SPLITTED_SEQ_OUT)); 
791   return ret;
792 }
793
794 void ForEachLoop::accept(Visitor *visitor)
795 {
796   visitor->visitForEachLoop(this);
797 }
798
799 //! Dump the node state to a stream
800 /*!
801  * \param os : the output stream
802  */
803 void ForEachLoop::writeDot(std::ostream &os) const
804 {
805   os << "  subgraph cluster_" << getId() << "  {\n" ;
806   //only one node in a loop
807   if(_node)
808     {
809       _node->writeDot(os);
810       os << getId() << " -> " << _node->getId() << ";\n";
811     }
812   os << "}\n" ;
813   os << getId() << "[fillcolor=\"" ;
814   YACS::StatesForNode state=getEffectiveState();
815   os << getColorState(state);
816   os << "\" label=\"" << "Loop:" ;
817   os << getName() <<"\"];\n";
818 }
819
820 //! Reset the state of the node and its children depending on the parameter level
821 void ForEachLoop::resetState(int level)
822 {
823   if(level==0)return;
824   DynParaLoop::resetState(level);
825   _execCurrentId=0;
826   //Note: cleanDynGraph is not a virtual method (must be called from ForEachLoop object) 
827   cleanDynGraph();
828 }