Salome HOME
mergefrom branch BR_V511_PR tag mergeto_trunk_03feb09
[modules/yacs.git] / src / engine / Loop.cxx
1 //  Copyright (C) 2006-2008  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 #include "Loop.hxx"
20 #include "InputPort.hxx"
21 #include "OutputPort.hxx"
22 #include "InputDataStreamPort.hxx"
23 #include "OutputDataStreamPort.hxx"
24 #include "LinkInfo.hxx"
25 #include "Runtime.hxx"
26 #include "Visitor.hxx"
27 #include <cassert>
28 #include <iostream>
29
30 //#define _DEVDEBUG_
31 #include "YacsTrace.hxx"
32
33 using namespace YACS::ENGINE;
34 using namespace std;
35
36 InputPort4DF2DS::InputPort4DF2DS(DFToDSForLoop *node, TypeCode* type):
37   InputPort("", node, type),
38   DataPort("", node, type),
39   Port(node),_data(0)
40 {
41 }
42
43 void InputPort4DF2DS::getAllRepresentants(std::set<InPort *>& repr) const
44 {
45   set<InPort *> s=_node->getOutputDataStreamPort("")->edSetInPort();
46   repr.insert(s.begin(),s.end());
47 }
48
49 void *InputPort4DF2DS::get() const throw(Exception)
50 {
51   if(!_data)
52     {
53       std::string what="InputPort4DF2DS::get : no value currently in input whith name \""; what+=_name; what+="\"";
54       throw Exception(what);
55     }
56   return (void *)_data;
57 }
58
59 void InputPort4DF2DS::exRestoreInit()
60 {
61   if(!_initValue)
62     return;
63   if(_data)
64     _data->decrRef();
65   _data=_initValue;
66   _data->incrRef();
67 }
68
69 void InputPort4DF2DS::exSaveInit()
70 {
71   if(_initValue)
72     _initValue->decrRef();
73   _initValue=_data;
74   _initValue->incrRef();
75 }
76
77 void InputPort4DF2DS::put(const void *data) throw(ConversionException)
78 {
79   put((Any *)data);
80 }
81
82 InputPort *InputPort4DF2DS::clone(Node *newHelder) const
83 {
84   throw Exception("InputPort4DF2DS::clone : internal error");
85 }
86
87 void InputPort4DF2DS::put(Any *data)
88 {
89   if(_data)
90     _data->decrRef();
91   _data=data;
92   _data->incrRef();
93 }
94
95 InputPort4DF2DS::~InputPort4DF2DS()
96 {
97   if(_data)
98     _data->decrRef();
99 }
100
101 DFToDSForLoop::DFToDSForLoop(Loop *loop, const std::string& name, TypeCode* type):ElementaryNode(""),_nbOfTimeUsed(1)
102 {
103   _name="DF2DS For "; _name+=loop->getName(); _name+=" representing port "; _name+=name;
104   _father=loop;
105   _setOfInputPort.push_back(new InputPort4DF2DS(this,type));
106   _setOfOutputDataStreamPort.push_back(new OutputDataStreamPort("",this,Loop::MappingDF2DS(type)));
107 }
108
109 DFToDSForLoop::~DFToDSForLoop()
110 {
111 }
112
113 void DFToDSForLoop::getReadyTasks(std::vector<Task *>& tasks)
114 {
115 }
116
117 InputPort *DFToDSForLoop::getInputPort(const std::string& name) const throw(Exception)
118 {
119   list<InputPort *>::const_iterator it =_setOfInputPort.begin();
120   return (*it);
121 }
122
123 OutputDataStreamPort *DFToDSForLoop::getOutputDataStreamPort(const std::string& name) const throw(Exception)
124 {
125   list<OutputDataStreamPort *>::const_iterator it =_setOfOutputDataStreamPort.begin();
126   return (*it);
127 }
128
129 void DFToDSForLoop::load()
130 {
131 }
132
133 void DFToDSForLoop::execute()
134 {
135   //TO IMPLEMENT
136 }
137
138 Node *DFToDSForLoop::simpleClone(ComposedNode *father, bool editionOnly) const
139 {
140   throw Exception("DFToDSForLoop::simpleClone : Internal error");
141 }
142
143 OutputPort4DS2DF::OutputPort4DS2DF(DSToDFForLoop *node, TypeCode *type):
144   OutputPort("", node, type),
145   DataPort("", node, type),
146   Port(node),_data(0)
147 {
148 }
149
150 void OutputPort4DS2DF::getAllRepresented(std::set<OutPort *>& represented) const
151 {
152   set<OutPort *> setO=_node->getInputDataStreamPort("")->edSetOutPort();
153   for(set<OutPort *>::iterator iter=setO.begin();iter!=setO.end();iter++)
154     (*iter)->getAllRepresented(represented);
155 }
156
157 void OutputPort4DS2DF::put(const void *data) throw(ConversionException)
158 {
159   put((Any *)data);
160   OutputPort::put(data);
161 }
162
163 OutputPort *OutputPort4DS2DF::clone(Node *newHelder) const
164 {
165   throw Exception("OutputPort4DS2DF::clone : Internal error");
166 }
167
168 void OutputPort4DS2DF::put(Any *data)
169 {
170   if(_data)
171     _data->decrRef();
172   _data=data;
173   _data->incrRef();
174 }
175
176 OutputPort4DS2DF::~OutputPort4DS2DF()
177 {
178   if(_data)
179     _data->decrRef();
180 }
181
182 InputDataStreamPort4DS2DF::InputDataStreamPort4DS2DF(DSToDFForLoop *node, TypeCode* type):
183   InputDataStreamPort("", node, type),
184   DataPort("", node, type),
185   Port(node)
186 {
187 }
188
189 void InputDataStreamPort4DS2DF::getAllRepresentants(std::set<InPort *>& repr) const
190 {
191   set<InPort *> s=_node->getOutputPort("")->edSetInPort();
192   repr.insert(s.begin(),s.end());
193 }
194
195 DSToDFForLoop::DSToDFForLoop(Loop *loop, const std::string& name, TypeCode* type):ElementaryNode(""),_nbOfTimeUsed(1)
196 {
197   _name="DS2DF For "; _name+=loop->getName(); _name+=" representing port "; _name+=name;
198   _father=loop;
199   _setOfOutputPort.push_back(new OutputPort4DS2DF(this,type));
200   _setOfInputDataStreamPort.push_back(new InputDataStreamPort4DS2DF(this,type));
201 }
202
203 Node *DSToDFForLoop::simpleClone(ComposedNode *father, bool editionOnly) const
204 {
205   throw Exception("DSToDFForLoop::simpleClone : Internal error");
206 }
207
208 DSToDFForLoop::~DSToDFForLoop()
209 {
210 }
211
212 void DSToDFForLoop::getReadyTasks(std::vector<Task *>& tasks)
213 {
214 }
215
216 OutputPort *DSToDFForLoop::getOutputPort(const std::string& name) const throw(Exception)
217 {
218   list<OutputPort *>::const_iterator it = _setOfOutputPort.begin();
219   return (*it);
220 }
221
222 InputDataStreamPort *DSToDFForLoop::getInputDataStreamPort(const std::string& name) const throw(Exception)
223 {
224   list<InputDataStreamPort *>::const_iterator it = _setOfInputDataStreamPort.begin();
225   return (*it);
226 }
227
228 void DSToDFForLoop::load()
229 {
230 }
231
232 void DSToDFForLoop::execute()
233 {
234   //TO IMPLEMENT
235 }
236
237 FakeNodeForLoop::FakeNodeForLoop(Loop *loop, bool normalFinish, bool internalError):ElementaryNode("thisIsAFakeNode"),
238                                                                                     _loop(loop),
239                                                                                     _normalFinish(normalFinish),
240                                                                                     _internalError(internalError)
241 {
242   setState(YACS::TOACTIVATE);
243   _father=_loop->getFather();
244 }
245
246 FakeNodeForLoop::FakeNodeForLoop(const FakeNodeForLoop& other):ElementaryNode(other),_loop(0),
247                                                                _normalFinish(false),_internalError(true)
248 {
249 }
250
251 Node *FakeNodeForLoop::simpleClone(ComposedNode *father, bool editionOnly) const
252 {
253   return new FakeNodeForLoop(*this);
254 }
255
256 void FakeNodeForLoop::exForwardFailed()
257 {
258   _loop->exForwardFailed();
259   FakeNodeForLoop *normallyThis=_loop->_nodeForNullTurnOfLoops;
260   _loop->_nodeForNullTurnOfLoops=0;
261   delete normallyThis;
262 }
263
264 void FakeNodeForLoop::exForwardFinished()
265
266   _loop->exForwardFinished();
267   FakeNodeForLoop *normallyThis=_loop->_nodeForNullTurnOfLoops;
268   _loop->_nodeForNullTurnOfLoops=0;
269   delete normallyThis;
270 }
271
272 void FakeNodeForLoop::execute()
273 {
274   if(!_normalFinish)
275     throw Exception("");//only to trigger ABORT on Executor
276 }
277
278 void FakeNodeForLoop::aborted()
279 {
280   if(_internalError)
281     _loop->setState(YACS::INTERNALERR);
282   else
283     _loop->setState(YACS::ERROR);
284 }
285
286 void FakeNodeForLoop::finished()
287 {
288   _loop->setState(YACS::DONE);
289 }
290
291 Loop::Loop(const Loop& other, ComposedNode *father, bool editionOnly):StaticDefinedComposedNode(other,father),_nbOfTurns(0),_nodeForNullTurnOfLoops(0),_node(0)
292 {
293   if(other._node)
294     _node=other._node->simpleClone(this,editionOnly);
295 }
296
297 Loop::Loop(const std::string& name):StaticDefinedComposedNode(name),_node(0),_nbOfTurns(0),_nodeForNullTurnOfLoops(0)
298 {
299 }
300
301 Loop::~Loop()
302 {
303   delete _node;
304   delete _nodeForNullTurnOfLoops;
305   for(set<DSToDFForLoop *>::iterator iter1=_inputsTraducer.begin();iter1!=_inputsTraducer.end();iter1++)
306     delete (*iter1);
307   for(set<DFToDSForLoop *>::iterator iter2=_outputsTraducer.begin();iter2!=_outputsTraducer.end();iter2++)
308     delete (*iter2);
309 }
310
311 void Loop::init(bool start)
312 {
313   StaticDefinedComposedNode::init(start);
314   _nbOfTurns=0;
315   if(_node)
316     _node->init(start); // if start is true, refresh the internal node
317   else
318     throw Exception("Loop::initLoop : no nodes specifies to be repeated ");
319   delete _nodeForNullTurnOfLoops;
320   _nodeForNullTurnOfLoops=0;
321 }
322
323 Node *Loop::edSetNode(Node *node)
324 {
325   if(_node==node)
326     return 0;
327   if(node)
328     {
329       if(node->_father)
330         {
331           string what = "Loop::edSetNode: node "; what += node->getName(); what += " is not orphan ! "; 
332           throw Exception(what);
333         }
334     }
335   checkNoCrossHierachyWith(node);
336   StaticDefinedComposedNode::edRemoveChild(_node);
337   Node *ret=_node;
338   _node=node;
339   _node->_father=this;
340   //set _modified flag so that edUpdateState() can refresh state
341   modified();
342   return ret;
343 }
344
345 bool Loop::edAddChild(Node *node) throw(Exception)
346 {
347   return edSetNode(node);
348 }
349
350 Node *Loop::edRemoveNode()
351 {
352   StaticDefinedComposedNode::edRemoveChild(_node);
353   Node *ret=_node;
354   _node=0;
355   modified();
356   return ret;
357 }
358
359 //! Collect all the child nodes that are ready
360 /*!
361  * \param tasks : vector of tasks to collect ready nodes
362  */
363 void Loop::getReadyTasks(std::vector<Task *>& tasks)
364 {
365   if(!_node)
366     return;
367   /*
368    * To change the way ComposedNode state is handled, uncomment the following line
369    * see Bloc::getReadyTasks
370    */
371   if(_state==YACS::TOACTIVATE) setState(YACS::ACTIVATED);
372   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
373     if(_nodeForNullTurnOfLoops)
374       _nodeForNullTurnOfLoops->getReadyTasks(tasks);
375     else
376       {
377         _node->getReadyTasks(tasks);
378         for(set<DSToDFForLoop *>::iterator iter1=_inputsTraducer.begin();iter1!=_inputsTraducer.end();iter1++)
379           (*iter1)->getReadyTasks(tasks);
380         for(set<DFToDSForLoop *>::iterator iter2=_outputsTraducer.begin();iter2!=_outputsTraducer.end();iter2++)
381           (*iter2)->getReadyTasks(tasks);
382       }
383 }
384
385 void Loop::edRemoveChild(Node *node) throw(Exception)
386 {
387   StaticDefinedComposedNode::edRemoveChild(node);
388   if(_node==node)
389     _node=0;
390   modified();
391 }
392
393 void Loop::selectRunnableTasks(std::vector<Task *>& tasks)
394 {
395 }
396
397 std::list<Node *> Loop::edGetDirectDescendants() const
398 {
399   list<Node *> ret;
400   if(_node)
401     ret.push_back(_node);
402   return ret;
403 }
404
405 std::list<InputPort *> Loop::getSetOfInputPort() const
406 {
407   list<InputPort *> ret=StaticDefinedComposedNode::getSetOfInputPort();
408   ret.push_back(getDecisionPort());
409   return ret;
410 }
411
412 int Loop::getNumberOfInputPorts() const
413 {
414   return StaticDefinedComposedNode::getNumberOfInputPorts()+1;
415 }
416
417 Node *Loop::getChildByShortName(const std::string& name) const throw(Exception)
418 {
419   if (_node)
420     if(name==_node->getName())
421       return _node;
422   string what("node "); what+= name ; what+=" is not a child of loop node "; what += getName();
423   throw Exception(what);
424 }
425
426 TypeCode* Loop::MappingDF2DS(TypeCode* type) throw(Exception)
427 {
428   return type;
429 }
430
431 TypeCode* Loop::MappingDS2DF(TypeCode* type) throw(Exception)
432 {
433   return type;
434 }
435
436 void Loop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
437 {
438   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
439   if(typeOfPortInstance!=InputPort::NAME or
440      (typeOfPortInstance == InputPort::NAME and 
441       initialStart->getNameOfTypeOfCurrentInstance()== OutputPort::NAME and 
442       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
443     return ;
444   InputPort *portCasted=(InputPort *)port;
445   set<DSToDFForLoop*>::iterator iter;
446   //Determinig if a DSToDFForLoop node has already been created for delegation of 'port'
447   for(iter=_inputsTraducer.begin();iter!=_inputsTraducer.end();iter++)
448     if((*iter)->getOutputPort("")->isAlreadyInSet(portCasted))
449       break;
450   if(iter==_inputsTraducer.end())
451     {//first time that 'port' is delegated on higher level
452       pair<set<DSToDFForLoop*>::iterator, bool> iter2=_inputsTraducer.insert(new DSToDFForLoop(this,portCasted->getName(),Loop::MappingDF2DS(portCasted->edGetType())));
453       iter=iter2.first;
454       (*iter)->getOutputPort("")->addInPort(portCasted);
455     }
456   else
457     (*iter)->loopHasOneMoreRef();
458   port=(*iter)->getInputDataStreamPort("");
459 }
460
461 void Loop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
462 {
463   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
464   if(typeOfPortInstance!=OutputPort::NAME or
465     ( typeOfPortInstance == OutputPort::NAME and 
466       finalTarget->getNameOfTypeOfCurrentInstance()== InputPort::NAME and 
467       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
468     return ;
469   OutPort *portCasted=port.first;
470   set<DFToDSForLoop*>::iterator iter;
471   //Determinig if a DFToDSForLoop node has already been created for delegation of 'port'
472   for(iter=_outputsTraducer.begin();iter!=_outputsTraducer.end();iter++)
473     if(portCasted->isAlreadyLinkedWith((*iter)->getInputPort("")))
474       break;
475   DFToDSForLoop *kl;
476   if(iter==_outputsTraducer.end())
477     {//first time that 'port' is delegated on higher level
478       //_outputsTraducer.insert(new DFToDSForLoop(this,portCasted->getName(),portCasted->edGetType()));
479       kl=new DFToDSForLoop(this,portCasted->getName(),portCasted->edGetType());
480       pair<set<DFToDSForLoop*>::iterator, bool> iter2=_outputsTraducer.insert(kl);
481       iter=iter2.first;
482       portCasted->addInPort((*iter)->getInputPort(""));
483     }
484   else
485     {
486       kl=*iter;
487       kl->loopHasOneMoreRef();
488     }
489   edAddLink(isInMyDescendance((port.first)->getNode())->getOutGate(),kl->getInGate());
490   port.first=(*iter)->getOutputDataStreamPort("");
491 }
492
493 void Loop::getDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
494 {
495   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
496   if(typeOfPortInstance!=InputPort::NAME or
497      (typeOfPortInstance == InputPort::NAME and 
498       initialStart->getNameOfTypeOfCurrentInstance()== OutputPort::NAME and 
499       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
500     return ;
501   InputPort *portCasted=(InputPort *)port;
502   set<DSToDFForLoop*>::iterator iter;
503   for(iter=_inputsTraducer.begin();iter!=_inputsTraducer.end();iter++)
504     if((*iter)->getOutputPort("")->isAlreadyInSet(portCasted))
505       break;
506   if(iter==_inputsTraducer.end())
507     {
508       string what("Loop::getDelegateOf : Port with name "); what+=portCasted->getName(); what+=" not exported by loop "; what+=_name; 
509       throw Exception(what);
510     }
511   else
512     port=(*iter)->getInputDataStreamPort("");
513 }
514
515 void Loop::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, 
516                          const std::list<ComposedNode *>& pointsOfView) throw(Exception)
517 {
518   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
519   if(typeOfPortInstance!=OutputPort::NAME or
520     ( typeOfPortInstance == OutputPort::NAME and 
521       finalTarget->getNameOfTypeOfCurrentInstance()== InputPort::NAME and 
522       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
523     return ;
524   OutPort *portCasted=port.first;
525   set<DFToDSForLoop*>::iterator iter;
526   for(iter=_outputsTraducer.begin();iter!=_outputsTraducer.end();iter++)
527     if(portCasted->isAlreadyLinkedWith((*iter)->getInputPort("")))
528       break;
529   if(iter==_outputsTraducer.end())
530     {
531       string what("Loop::getDelegateOf : Port with name "); what+=portCasted->getName(); what+=" not exported by loop "; what+=_name; 
532       throw Exception(what);
533     }
534   else
535     port.first=(*iter)->getOutputDataStreamPort("");
536 }
537
538 void Loop::releaseDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
539 {
540   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
541   if(typeOfPortInstance!=InputPort::NAME or
542     ( typeOfPortInstance == InputPort::NAME and 
543       initialStart->getNameOfTypeOfCurrentInstance()== OutputPort::NAME and 
544       !isNecessaryToBuildSpecificDelegateDF2DS(pointsOfView)) )
545     return ;
546   InputPort *portCasted=(InputPort *)port;
547   set<DSToDFForLoop*>::iterator iter;
548   for(iter=_inputsTraducer.begin();iter!=_inputsTraducer.end();iter++)
549     if((*iter)->getOutputPort("")->isAlreadyInSet(portCasted))
550       break;
551   if(iter==_inputsTraducer.end())
552     {
553       string what("Loop::releaseDelegateOf Port with name "); what+=portCasted->getName(); what+=" not exported by loop "; what+=_name; 
554       throw Exception(what);
555     }
556   else
557     {
558       port=(*iter)->getInputDataStreamPort("");
559       if((*iter)->loopHasOneLessRef())
560         {
561           (*iter)->getOutputPort("")->removeInPort(portCasted,false);
562           delete (*iter);
563           _inputsTraducer.erase(iter);
564         }
565     }
566 }
567
568 void Loop::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
569 {
570   if(portDwn==portUp)
571     return ;
572   set<DFToDSForLoop*>::iterator iter;
573   for(iter=_outputsTraducer.begin();iter!=_outputsTraducer.end();iter++)
574     if((*iter)->getOutputDataStreamPort("")==portUp)
575       break;
576   if((*iter)->loopHasOneLessRef())
577     {
578       portDwn->removeInPort((*iter)->getInputPort(""),false);
579       delete (*iter);
580       _outputsTraducer.erase(iter);
581     }
582 }
583
584 void Loop::checkNoCyclePassingThrough(Node *node) throw(Exception)
585 {
586   //throw Exception("Loop::checkNoCyclePassingThrough : Internal error occured");
587 }
588
589 void Loop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
590 {
591   Node *nodeEnd=end->getNode();
592   if(nodeEnd==this)
593     {//In this case 'end' port is a special port of this (for exemple ForLoop::_nbOfTimesPort)
594       //ASSERT(!direction) see Loop::checkControlDependancy (bw only)
595       solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
596     }
597   else
598     StaticDefinedComposedNode::checkCFLinks(starts,end,alreadyFed,direction,info);
599 }
600
601 /*!
602  * \note : States if a DF port must be considered on an upper level in hierarchy as a DS port or not from 'pointsOfView' observers.
603  * \return : 
604  *            - True : a traduction DF->DS has to be done
605  *            - False : no traduction needed
606  */
607 bool Loop::isNecessaryToBuildSpecificDelegateDF2DS(const std::list<ComposedNode *>& pointsOfView)
608 {
609   bool ret=false;
610   for(list<ComposedNode *>::const_iterator iter=pointsOfView.begin();iter!=pointsOfView.end() && !ret;iter++)
611     ret=(*iter)->isRepeatedUnpredictablySeveralTimes();
612   return ret;
613 }
614
615 //! Connect an OutPort to an InPort and add control link if necessary
616 /*!
617  * Connect the ports with a data link (edAddLink) 
618  * In a Loop don't add control flow link : use this only to add data back links
619  *
620  * \param start : the OutPort to connect
621  * \param end : the InPort to connect
622  * \return  true if a new link has been created, false otherwise.
623  */
624 bool Loop::edAddDFLink(OutPort *start, InPort *end) throw(Exception)
625 {
626   return edAddLink(start,end);
627 }
628
629 //! Dump the node state to a stream
630 /*!
631  * \param os : the output stream
632  */
633 void Loop::writeDot(std::ostream &os) const
634 {
635   os << "  subgraph cluster_" << getId() << "  {\n" ;
636   //only one node in a loop
637   if(_node)
638     {
639       _node->writeDot(os);
640       os << getId() << " -> " << _node->getId() << ";\n";
641     }
642   os << "}\n" ;
643   os << getId() << "[fillcolor=\"" ;
644   YACS::StatesForNode state=getEffectiveState();
645   os << getColorState(state);
646   os << "\" label=\"" << "Loop:" ;
647   os << getQualifiedName() <<"\"];\n";
648 }
649
650
651 void Loop::accept(Visitor *visitor)
652 {
653   visitor->visitLoop(this);
654 }
655
656 void Loop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
657                                   std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
658                                   std::vector<OutPort *>& fwCross,
659                                   std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
660                                   LinkInfo& info) const
661 {
662   //First testing if end==getDecisionPort. This is the only case possible in theory.
663   if(end!=getDecisionPort())
664     return StaticDefinedComposedNode::checkControlDependancy(start,end,cross,fw,fwCross,bw,info);
665   if(cross)
666     throw Exception("Internal error occured - cross type link detected on decision port of a loop. Forbidden !");
667   fw[(ComposedNode *)this].push_back(start);
668 }
669
670 void Loop::checkBasicConsistency() const throw(Exception)
671 {
672   DEBTRACE("Loop::checkBasicConsistency");
673   ComposedNode::checkBasicConsistency();
674   if(!_node)
675     throw Exception("For a loop, internal node is mandatory");
676 }
677
678 /*!
679  *  For use only when loading a previously saved execution
680  */
681
682 void YACS::ENGINE::NbDoneLoader(Loop* node, int val)
683 {
684   node->_nbOfTurns = val;
685 }