Salome HOME
Copyright update 2020
[modules/yacs.git] / src / engine / Switch.cxx
1 // Copyright (C) 2006-2020  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, or (at your option) any later version.
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 "Switch.hxx"
21 #include "Visitor.hxx"
22 #include "LinkInfo.hxx"
23
24 #include <iostream>
25 #include <sstream>
26 #include <cassert>
27
28 //#define _DEVDEBUG_
29 #include "YacsTrace.hxx"
30
31 using namespace YACS::ENGINE;
32 using namespace std;
33
34 const char Switch::DEFAULT_NODE_NAME[]="default";
35 const int Switch::ID_FOR_DEFAULT_NODE=-1973012217;
36 const char Switch::SELECTOR_INPUTPORT_NAME[]="select";
37
38 int CollectorSwOutPort::edGetNumberOfOutLinks() const
39 {
40   return 1;
41 }
42
43 std::set<InPort *> CollectorSwOutPort::edSetInPort() const
44 {
45   set<InPort *> ret;
46   if(_consumer)
47     ret.insert(_consumer);
48   return ret;
49 }
50
51 bool CollectorSwOutPort::isAlreadyLinkedWith(InPort *with) const
52 {
53   set<InPort *> s;
54   with->getAllRepresentants(s);
55   return s.find(_consumer)!=s.end();
56 }
57
58 std::string CollectorSwOutPort::getNameOfTypeOfCurrentInstance() const
59 {
60   return _className;
61 }
62
63 void CollectorSwOutPort::edRemoveAllLinksLinkedWithMe() throw(YACS::Exception)
64 {
65   map<int, OutPort *>::iterator pt;
66   if(_consumer)
67     for(pt=_potentialProducers.begin();pt!=_potentialProducers.end();pt++)
68       ((*pt).second)->removeInPort(_consumer,true);
69 }
70
71 TypeOfChannel CollectorSwOutPort::getTypeOfChannel() const
72 {
73   return (*(_potentialProducers.begin())).second->getTypeOfChannel();
74 }
75
76 void CollectorSwOutPort::getAllRepresented(std::set<OutPort *>& represented) const
77 {
78   map<int, OutPort *>::const_iterator pt;
79   for(pt=_potentialProducers.begin();pt!=_potentialProducers.end();pt++)
80     ((*pt).second)->getAllRepresented(represented);
81 }
82
83 bool CollectorSwOutPort::addInPort(InPort *inPort) throw(YACS::Exception)
84 {
85   if(_currentProducer)
86     {//a specific link is beeing done
87       bool ret=_currentProducer->addInPort(inPort);
88       _currentProducer=0;
89       return ret;
90     }
91   else//global links asked
92     for(map<int, OutPort *>::iterator iter=_potentialProducers.begin();iter!=_potentialProducers.end();iter++)
93       (*iter).second->addInPort(inPort);
94 }
95
96 int CollectorSwOutPort::removeInPort(InPort *inPort, bool forward) throw(YACS::Exception)
97 {
98   if(_currentProducer)
99     {
100       return _currentProducer->removeInPort(inPort,forward);
101     }
102   else
103     throw Exception("CollectorSwOutputPort::edRemoveInputPort : internal error on link removal.");
104   _currentProducer=0;
105 }
106
107 /*!
108  * \note : 'master' specifies the instance of Switch of which 'this' collects all of these direct 
109  *          or indirect outports going to the same port 'port' (which is out of scope of 'master').
110  */
111 CollectorSwOutPort::CollectorSwOutPort(Switch *master, InPort *port):OutPort("",master,port->edGetType()),
112                                                                      DataPort("",master,port->edGetType()),
113                                                                      Port(master),
114                                                                      _consumer(port),_currentProducer(0)
115 {
116   _name="Representant_of_"; _name+=master->getName(); _name+="_for_inport_"; _name+=master->getRootNode()->getInPortName(_consumer);
117 }
118
119 CollectorSwOutPort::CollectorSwOutPort(const CollectorSwOutPort& other, Switch *master):OutPort("",master,other.edGetType()),
120                                                                                         DataPort("",master,other.edGetType()),
121                                                                                         Port(master),
122                                                                                         _consumer(0),_currentProducer(0)
123 {
124   _name=other._name;
125   Switch *othSw=(Switch *)other._node;
126   for(map<int, OutPort *>::const_iterator iter=other._potentialProducers.begin();iter!=other._potentialProducers.end();iter++)
127     {
128       string name=othSw->getOutPortName((*iter).second);
129       _potentialProducers[(*iter).first]=master->getOutPort(name);
130     }
131 }
132
133 void CollectorSwOutPort::addPotentialProducerForMaster(OutPort *port)
134 {
135   int i=((Switch *)_node)->getRankOfNode(port->getNode());
136   map<int, OutPort *>::iterator pt=_potentialProducers.find(i);
137   if(pt==_potentialProducers.end())
138     {
139       _potentialProducers[i]=port;
140       _currentProducer=port;
141     }
142   else
143     {
144       _currentProducer=(*pt).second;
145       if(_currentProducer!=port)
146         {
147           string what("CollectorSwOutPort::addPotentialProducerForMaster : In switch node "); what+=_node->getName();
148           what+=" for input named \'"; what+=_consumer->getName(); what+="\' the output "; what+=_currentProducer->getName();
149           what+=" already got out for case of label "; 
150           what+=Switch::getRepresentationOfCase((*pt).first); 
151           throw Exception(what);
152         }
153     }
154   _className=port->getNameOfTypeOfCurrentInstance();
155 }
156
157 bool CollectorSwOutPort::removePotentialProducerForMaster()
158 {
159   int i;
160   map<int, OutPort *>::iterator result;
161   for(result=_potentialProducers.begin();result!=_potentialProducers.end();result++)
162     if((*result).second==_currentProducer)
163       {
164         i=(*result).first;
165         break;
166       }
167   if(result==_potentialProducers.end())
168     {
169       ostringstream stream; stream << "CollectorSwOutPort::removePotentialProducerForMaster : link from the branch whith id ";
170       stream << i << " not defined";
171       throw Exception(stream.str());
172     }
173   if((*result).second!=_currentProducer)
174     {
175       ostringstream stream; stream << "CollectorSwOutPort::removePotentialProducerForMaster : link from the branch whith id ";
176       stream << i << " defined but the output specified is not compatible";
177       throw Exception(stream.str());
178     }
179   _potentialProducers.erase(result);
180   return _potentialProducers.empty();
181 }
182
183 bool CollectorSwOutPort::checkManagementOfPort(OutPort *port) throw(YACS::Exception)
184 {
185   for(map<int, OutPort *>::iterator iter=_potentialProducers.begin();iter!=_potentialProducers.end();iter++)
186     if((*iter).second==port)
187       {
188         _currentProducer=port;
189         return _potentialProducers.size()==1;
190       }
191   throw Exception("CollectorSwOutPort::checkManagementOfPort : unexported port");
192 }
193
194 /*!
195  * Called by Switch::checkCFLinks.
196  */
197 void CollectorSwOutPort::checkConsistency(LinkInfo& info) const
198 {
199   if(((Switch *)_node)->getNbOfCases()!=_potentialProducers.size())
200     info.pushErrSwitch((CollectorSwOutPort *)this);
201   for(map<int, OutPort *>::const_iterator iter=_potentialProducers.begin();iter!=_potentialProducers.end();iter++)
202     (*iter).second->checkConsistency(info);
203 }
204
205 /*!
206  * Called by LinkInfo::getErrRepr to have a comprehensible message on throw.
207  * When called, typically checkCompletenessOfCases has detected that some potential producers were laking...
208  */
209 void CollectorSwOutPort::getHumanReprOfIncompleteCases(std::ostream& stream) const
210 {
211   set<int> lackingCases;
212   for(map< int ,Node * >::const_iterator iter=((Switch *)_node)->_mapOfNode.begin();iter!=((Switch *)_node)->_mapOfNode.end();iter++)
213     {
214       if(_potentialProducers.find((*iter).first)==_potentialProducers.end())
215         lackingCases.insert((*iter).first);
216     }
217   ostringstream streamForExc;
218   stream << "For link to " <<  _consumer->getName() << " of node " << _consumer->getNode()->getName() 
219          << " the cases of switch node named " << _node->getName() 
220          << " do not define links for following cases ids :";
221   for(set<int>::iterator iter=lackingCases.begin();iter!=lackingCases.end();iter++)
222       stream << Switch::getRepresentationOfCase(*iter) << " ";
223   stream << endl;
224 }
225
226 FakeNodeForSwitch::FakeNodeForSwitch(Switch *sw, bool normalFinish, bool internalError):ElementaryNode("thisIsAFakeNode"),
227                                                                                         _sw(sw),
228                                                                                         _normalFinish(normalFinish),
229                                                                                         _internalError(internalError)
230 {
231   _state=YACS::TOACTIVATE;
232   _father=_sw->getFather();
233 }
234
235 FakeNodeForSwitch::FakeNodeForSwitch(const FakeNodeForSwitch& other):ElementaryNode(other),_sw(0),
236                                                                      _normalFinish(false),
237                                                                      _internalError(true)
238 {
239 }
240
241 Node *FakeNodeForSwitch::simpleClone(ComposedNode *father, bool editionOnly) const
242 {
243   return new FakeNodeForSwitch(*this);
244 }
245
246 void FakeNodeForSwitch::exForwardFailed()
247 {
248   _sw->exForwardFailed();
249 }
250
251 void FakeNodeForSwitch::exForwardFinished()
252
253   _sw->exForwardFinished(); 
254 }
255
256 void FakeNodeForSwitch::execute()
257 {
258   if(!_normalFinish)
259     throw Exception("");//only to trigger ABORT on Executor
260 }
261
262 void FakeNodeForSwitch::aborted()
263 {
264   if(_internalError)
265     _sw->_state!=YACS::INTERNALERR;
266   else
267     _sw->setState(YACS::ERROR);
268 }
269
270 void FakeNodeForSwitch::finished()
271 {
272   _sw->setState(YACS::DONE);
273 }
274
275 /*! \class YACS::ENGINE::Switch
276  *  \brief Control node that emulates the C switch
277  *
278  *  \ingroup Nodes
279  */
280
281 Switch::Switch(const Switch& other, ComposedNode *father, bool editionOnly):StaticDefinedComposedNode(other,father),_condition(other._condition,this),
282                                                                             _undispatchableNotificationNode(0)
283 {
284   for(map<int,Node *>::const_iterator iter=other._mapOfNode.begin();iter!=other._mapOfNode.end();iter++)
285     _mapOfNode[(*iter).first]=(*iter).second->clone(this,editionOnly);
286   if(!editionOnly)
287     for(map<InPort *, CollectorSwOutPort * >::const_iterator iter2=other._outPortsCollector.begin();iter2!=other._outPortsCollector.end();iter2++)
288       {
289         CollectorSwOutPort *newCol=new CollectorSwOutPort(*((*iter2).second),this);
290         _alreadyExistingCollectors.push_back(newCol);
291       }
292 }
293
294 Switch::Switch(const std::string& name):StaticDefinedComposedNode(name),_condition(SELECTOR_INPUTPORT_NAME,this,Runtime::_tc_int),_undispatchableNotificationNode(0)
295 {
296 }
297
298 Switch::~Switch()
299 {
300   if(_undispatchableNotificationNode)delete _undispatchableNotificationNode;
301
302   for(map< int , Node * >::iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
303     delete (*iter).second;
304   for(map<InPort *, CollectorSwOutPort * >::iterator iter2=_outPortsCollector.begin();iter2!=_outPortsCollector.end();iter2++)
305     delete (*iter2).second;
306   for(vector<CollectorSwOutPort *>::iterator iter3=_alreadyExistingCollectors.begin();iter3!=_alreadyExistingCollectors.end();iter3++)
307     delete (*iter3);
308 }
309
310 Node *Switch::simpleClone(ComposedNode *father, bool editionOnly) const
311 {
312   return new Switch(*this,father,editionOnly);
313 }
314
315 void Switch::exUpdateState()
316 {
317   DEBTRACE("Switch::exUpdateState " << _state);
318   if(_state == YACS::DISABLED)
319     return;
320   if(_inGate.exIsReady())
321     {
322       setState(YACS::ACTIVATED);
323       if(_condition.isEmpty())
324         _undispatchableNotificationNode=new FakeNodeForSwitch(this,false,true);
325       else
326         {
327           map< int , Node * >::iterator iter=_mapOfNode.find(_condition.getIntValue());
328           if(iter==_mapOfNode.end())
329             {
330               iter=_mapOfNode.find(ID_FOR_DEFAULT_NODE);
331               if(iter==_mapOfNode.end())
332                 {
333                   bool normalFinish=getAllOutPortsLeavingCurrentScope().empty();
334                   delete _undispatchableNotificationNode;
335                   _undispatchableNotificationNode=new FakeNodeForSwitch(this,normalFinish);
336                 }
337               else
338                 ((*iter).second)->exUpdateState();
339             }
340           else
341             ((*iter).second)->exUpdateState();
342         }
343     }
344 }
345
346 void Switch::init(bool start)
347 {
348   DEBTRACE("Switch::init " << start);
349   StaticDefinedComposedNode::init(start);
350   int i=0;
351   for(map< int , Node * >::iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++, i++)
352     {
353       if(!(*iter).second)
354         {
355           ostringstream stream;
356           stream << "Switch::init : initialization failed due to unitialized branch of id " << (*iter).first;
357           throw Exception(stream.str());
358         }
359       ((*iter).second)->init(start);
360     }
361 }
362
363 void Switch::getReadyTasks(std::vector<Task *>& tasks)
364 {
365   /*
366    * To change the way ComposedNode state is handled, uncomment the following line
367    * see Bloc::getReadyTasks
368    */
369   if(_state==YACS::TOACTIVATE) setState(YACS::ACTIVATED);
370   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
371     {
372       map< int , Node * >::iterator iter=_mapOfNode.find(_condition.getIntValue());
373       if(iter!=_mapOfNode.end())
374         ((*iter).second)->getReadyTasks(tasks);
375       else
376         {
377           iter=_mapOfNode.find(ID_FOR_DEFAULT_NODE);
378           if(iter!=_mapOfNode.end())
379             (*iter).second->getReadyTasks(tasks);//Default Node is returned
380           else
381             if(_undispatchableNotificationNode)
382               _undispatchableNotificationNode->getReadyTasks(tasks);
383             else
384               throw Exception("Switch::getReadyTasks : internal error");
385         }
386     }
387 }
388
389 list<Node *> Switch::edGetDirectDescendants() const
390 {
391   list<Node *> ret;
392   for(map< int , Node * >::const_iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
393     if((*iter).second)
394       ret.push_back((*iter).second);
395   return ret;
396 }
397
398 int Switch::getNumberOfInputPorts() const
399
400   return StaticDefinedComposedNode::getNumberOfInputPorts()+1;
401 }
402
403 int Switch::getMaxLevelOfParallelism() const
404 {
405   int ret(0);
406   for(std::map< int , Node * >::const_iterator it=_mapOfNode.begin();it!=_mapOfNode.end();it++)
407     ret=std::max(ret,((*it).second)->getMaxLevelOfParallelism());
408   return ret;
409 }
410
411 void Switch::getWeightRegardingDPL(ComplexWeight *weight)
412 {
413   ComplexWeight localWeight;
414   for(std::map< int , Node * >::const_iterator it=_mapOfNode.begin();it!=_mapOfNode.end();it++)
415   {
416     ((*it).second)->getWeightRegardingDPL(&localWeight);
417     weight->max(localWeight);
418     localWeight.setToZero();
419   }
420 }
421
422 void Switch::partitionRegardingDPL(const PartDefinition *pd, std::map<ComposedNode *, YACS::BASES::AutoRefCnt<PartDefinition> >& zeMap)
423 {
424   for(std::map< int , Node * >::const_iterator it=_mapOfNode.begin();it!=_mapOfNode.end();it++)
425     (*it).second->partitionRegardingDPL(pd,zeMap);
426 }
427
428 void Switch::edRemoveChild(Node *node) throw(YACS::Exception)
429 {
430   map< int , Node * >::iterator iter=_mapOfNode.begin();
431   for(;iter!=_mapOfNode.end();iter++)
432     if(node==(*iter).second)
433       {
434         edReleaseCase((*iter).first);
435         return;
436       }
437   ostringstream what; what << "Switch::edRemoveChild : node with name " << node->getName() << " is not a direct child of Switch node " << _name; 
438   throw Exception(what.str());
439 }
440
441 std::list<InputPort *> Switch::getSetOfInputPort() const
442 {
443   list<InputPort *> ret=StaticDefinedComposedNode::getSetOfInputPort();
444   ret.push_back((InputPort *)&_condition);
445   return ret;
446 }
447
448
449 std::list<InputPort *> Switch::getLocalInputPorts() const
450 {
451   list<InputPort *> ret=StaticDefinedComposedNode::getLocalInputPorts();
452   ret.push_back((InputPort *)&_condition);
453   return ret;
454 }
455 OutPort *Switch::getOutPort(const std::string& name) const throw(YACS::Exception)
456 {
457   for(map<InPort *, CollectorSwOutPort * >::const_iterator iter=_outPortsCollector.begin();iter!=_outPortsCollector.end();iter++)
458     if(name==(*iter).second->getName())
459       return (*iter).second;
460   for(vector<CollectorSwOutPort *>::const_iterator iter2=_alreadyExistingCollectors.begin();iter2!=_alreadyExistingCollectors.end();iter2++)
461     if(name==(*iter2)->getName())
462       return *iter2;
463   return StaticDefinedComposedNode::getOutPort(name);
464 }
465
466 InputPort *Switch::getInputPort(const std::string& name) const throw(YACS::Exception)
467 {
468   if(name==SELECTOR_INPUTPORT_NAME)
469     return (InputPort *)&_condition;
470   return StaticDefinedComposedNode::getInputPort(name);
471 }
472
473 Node *Switch::getChildByShortName(const std::string& name) const throw(YACS::Exception)
474 {
475   if(name==DEFAULT_NODE_NAME)
476     {
477       map< int , Node * >::const_iterator iter=_mapOfNode.find(ID_FOR_DEFAULT_NODE);
478       if(iter!=_mapOfNode.end())
479         return (Node *)((*iter).second);
480       else
481         {
482           string what("Switch::getChildByShortName : no default node defined for switch of name "); what+=getName();
483           throw Exception(what);
484         }
485     }
486   for(map< int , Node * >::const_iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
487     {
488       if(name==((*iter).second)->getQualifiedName())
489         return (*iter).second;
490     }
491   string what("node "); what+= name ; what+=" is not a child of node switch "; what += getName();
492   throw Exception(what);
493 }
494
495 Node *Switch::edSetDefaultNode(Node *node)
496 {
497   return edSetNode(ID_FOR_DEFAULT_NODE,node);
498 }
499
500 Node *Switch::edReleaseDefaultNode() throw(YACS::Exception)
501 {
502   return edReleaseCase(ID_FOR_DEFAULT_NODE);
503 }
504
505 Node *Switch::edReleaseCase(int caseId) throw(YACS::Exception)
506 {
507   map< int , Node * >::iterator iter=_mapOfNode.find(caseId);
508   if(iter==_mapOfNode.end())
509     { 
510       string what("Switch::edReleaseCase : the case # "); what+=getRepresentationOfCase(caseId);  what+=" is not set yet.";
511       throw Exception(what);
512     }
513   else
514     {
515       Node *ret=(*iter).second;
516       StaticDefinedComposedNode::edRemoveChild(ret);
517       _mapOfNode.erase(iter);
518       modified();
519       return ret;
520     }
521 }
522
523 Node *Switch::edGetNode(int caseId)
524 {
525   if (!_mapOfNode.count(caseId)) return 0;
526   return _mapOfNode[caseId];
527 }
528
529
530 /*!
531  * \param caseId : the case ID chosen to place 'node'
532  * \param node   : the node for the specified 'caseId'
533  * \return : If an old node with id equal to 'caseId' exists before, this old node is returned so that to be deallocated.
534  *           0 is returned if caseId is a new ID.
535  *  \b WARNING : 'node' is held by 'this' after call, whereas returned node is no more held. 
536  */
537 Node *Switch::edSetNode(int caseId, Node *node) throw(YACS::Exception)
538 {
539   if(!node)
540     throw Exception("Switch::edSetNode : null node cannot be set as a case in switch node");
541   if(node->_father!=0)
542     throw Exception("Switch::edSetNode : node already held by another father");
543   checkNoCrossHierachyWith(node);
544   node->_father=this;
545   map< int , Node * >::iterator iter=_mapOfNode.find(caseId);
546   if(iter==_mapOfNode.end())
547     {
548       _mapOfNode[caseId]=node;
549       modified();
550       return 0;
551     }
552   else
553     {
554       if(node!=(*iter).second)
555         {
556           Node *ret=(*iter).second;
557           (*iter).second=node;
558           modified();
559           return ret;
560         }
561     }
562 }
563
564 //! Change the case of a node
565 /*!
566  *  \param oldCase : the case value to change
567  *  \param newCase : the new value to set
568  *  raise an exception if the old case does not exist or if the new case already exists
569  */
570 void Switch::edChangeCase(int oldCase, int newCase)
571 {
572   std::map< int , Node * >::iterator iter=_mapOfNode.find(oldCase);
573   if(iter==_mapOfNode.end())
574     {
575       //the case does not exists
576       throw Exception("Switch::edChangeCase : case does not exist");
577     }
578   iter=_mapOfNode.find(newCase);
579   if(iter != _mapOfNode.end())
580     {
581       //the new case exists
582       throw Exception("Switch::edChangeCase : new case exists");
583     }
584   Node* node=_mapOfNode[oldCase];
585   _mapOfNode.erase(oldCase);
586   _mapOfNode[newCase]=node;
587   modified();
588 }
589
590 int Switch::getMaxCase()
591 {
592   int aCase = 0;
593   map<int, Node*>::const_iterator it = _mapOfNode.begin();
594   for(; it != _mapOfNode.end(); ++it)
595     if ((*it).first > aCase)
596       aCase = (*it).first;
597   return aCase;
598 }
599
600 //! Get the progress weight of the graph
601 /*!
602  * Only elementary nodes have weight. If the switch node is not done, we add the weight of all his descendants,
603  * otherwise only the weight of the used case count.
604  */
605 list<ProgressWeight> Switch::getProgressWeight() const
606 {
607   list<ProgressWeight> ret;
608   list<Node *> setOfNode=edGetDirectDescendants();
609   if (getState() == YACS::DONE)
610     {
611       for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
612       {
613         if (getEffectiveState(*iter) == YACS::DONE)
614           ret=(*iter)->getProgressWeight();
615       }
616     }
617   else
618     {
619       for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
620         {
621           list<ProgressWeight> myCurrentSet=(*iter)->getProgressWeight();
622           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
623         }
624     }
625   return ret;
626 }
627
628 bool Switch::edAddChild(Node *node) throw(YACS::Exception)
629 {
630   int aCase = getMaxCase() + 1;
631   DEBTRACE(aCase);
632   bool ret = edSetNode(aCase, node);
633   DEBTRACE(ret);
634   return ret;
635 }
636
637 YACS::Event Switch::updateStateOnFinishedEventFrom(Node *node)
638 {
639   setState(YACS::DONE);
640   return YACS::FINISH;//notify to father node that 'this' has becomed finished.
641 }
642
643 std::set<InPort *> Switch::getAllInPortsComingFromOutsideOfCurrentScope() const
644 {
645   set<InPort *> ret=StaticDefinedComposedNode::getAllInPortsComingFromOutsideOfCurrentScope();
646   set<OutPort *> temp2=_condition.edSetOutPort();
647   for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
648     if(!isInMyDescendance((*iter3)->getNode()))
649       {
650         ret.insert((InPort *)&_condition);
651         break;
652       }
653   return ret;
654 }
655
656 void Switch::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
657 {
658   map<InPort *, CollectorSwOutPort * >::const_iterator iter=_outPortsCollector.find(end);
659   if(iter!=_outPortsCollector.end())
660     {
661       set<OutPort *> represented;
662       (*iter).second->getAllRepresented(represented);
663       list<OutPort *> others;
664       for(list<OutPort *>::const_iterator iter2=starts.begin();iter2!=starts.end();iter2++)
665         if(represented.find(*iter2)==represented.end())
666           others.push_back(*iter2);
667       if(others.empty())
668         alreadyFed=FED_ST;
669       else
670         StaticDefinedComposedNode::checkCFLinks(others,end,alreadyFed,direction,info);//should never happend;
671     }
672   else
673     StaticDefinedComposedNode::checkCFLinks(starts,end,alreadyFed,direction,info);
674 }
675
676 void Switch::checkControlDependancy(OutPort *start, InPort *end, bool cross,
677                                     std::map < ComposedNode *,  std::list < OutPort * > >& fw,
678                                     std::vector<OutPort *>& fwCross,
679                                     std::map< ComposedNode *, std::list < OutPort *> >& bw,
680                                     LinkInfo& info) const
681 {
682   throw Exception("Switch::checkControlDependancy : a link was dectected between 2 cases of a switch. Impossible !");
683 }
684
685 void Switch::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
686 {
687   throw Exception("Switch::checkNoCyclePassingThrough : uncorrect control flow link relative to switch");
688 }
689
690 void Switch::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
691                                   InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
692 {
693   throw Exception("Switch::checkLinkPossibility : A link between 2 different cases of a same Switch requested -> Impossible");
694 }
695
696 void Switch::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
697 {
698   map<InPort *, CollectorSwOutPort * >::iterator result=_outPortsCollector.find(finalTarget);
699   CollectorSwOutPort *newCollector;
700   if(result!=_outPortsCollector.end())
701     newCollector=(*result).second;
702   else
703     {
704       newCollector=new CollectorSwOutPort(this,finalTarget);
705       newCollector->edSetType((port.first)->edGetType());
706       _outPortsCollector[finalTarget]=newCollector;
707     }
708   newCollector->addPotentialProducerForMaster(port.first);
709   port.second=newCollector;
710   port.first=newCollector;
711 }
712
713 void Switch::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
714 {
715   map<InPort *, CollectorSwOutPort * >::iterator iter=_outPortsCollector.find(finalTarget);
716   if(iter==_outPortsCollector.end())
717     {
718       string what("Switch::getDelegateOf : not exported OuputPort with name "); what+=(port.first)->getName(); what+=" for target inport of name ";
719       what+=finalTarget->getName();
720       throw Exception(what);
721     }
722   ((*iter).second)->checkManagementOfPort(port.first);
723   port.second=(*iter).second;
724   port.first=(*iter).second;
725 }
726
727 void Switch::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
728 {
729   set<OutPort *> repr;
730   portDwn->getAllRepresented(repr);
731   if(repr.size()==1)
732     {
733       CollectorSwOutPort *portCasted=dynamic_cast<CollectorSwOutPort *>(portUp);
734       if(portCasted->removePotentialProducerForMaster())//normally always true
735         {
736           delete portCasted;
737           _outPortsCollector.erase(finalTarget);
738         }
739     }
740 }
741
742 int Switch::getNbOfCases() const
743 {
744   return _mapOfNode.size();
745 }
746
747 int Switch::getRankOfNode(Node *node) const
748 {
749   Node *directSon=isInMyDescendance(node);
750   for(map< int , Node * >::const_iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
751     if((*iter).second==directSon)
752       return (*iter).first;
753   throw Exception("Switch::getRankOfNode : node not in switch");
754 }
755
756 string Switch::getRepresentationOfCase(int i)
757 {
758   if(i!=ID_FOR_DEFAULT_NODE)
759     {
760       ostringstream stream;
761       stream << i;
762       return stream.str();
763     }
764   else
765     return DEFAULT_NODE_NAME;
766 }
767
768 //! Return the effective state of a node in the context of this switch (its father)
769 /*!
770  * \param node: the node which effective state is queried
771  * \return the effective node state
772  */
773 YACS::StatesForNode Switch::getEffectiveState(const Node* node) const
774 {
775   YACS::StatesForNode effectiveState=Node::getEffectiveState();
776   if(effectiveState==YACS::READY)
777     return YACS::READY;
778   if(effectiveState==YACS::TOACTIVATE)
779     return YACS::READY;
780   if(effectiveState==YACS::DISABLED)
781     return YACS::DISABLED;
782
783   return node->getState();
784 }
785 YACS::StatesForNode Switch::getEffectiveState() const
786 {
787   return Node::getEffectiveState();
788 }
789
790 void Switch::writeDot(std::ostream &os) const
791 {
792   os << "  subgraph cluster_" << getId() << "  {\n" ;
793   for(map<int,Node*>::const_iterator iter=_mapOfNode.begin();iter!=_mapOfNode.end();iter++)
794     {
795       Node* n=(*iter).second;
796       n->writeDot(os);
797       os << getId() << " -> " << n->getId() << ";\n";
798     }
799   os << "}\n" ;
800   os << getId() << "[fillcolor=\"" ;
801   YACS::StatesForNode state=Node::getEffectiveState();
802   os << getColorState(state);
803   os << "\" label=\"" << "Switch:" ;
804   os << getQualifiedName() <<"\"];\n";
805 }
806
807 std::string Switch::getMyQualifiedName(const Node *directSon) const
808 {
809   string id=getCaseId(directSon);
810   id+=directSon->getName();
811   return id;
812 }
813
814 std::string Switch::getCaseId(const Node *node) const throw(YACS::Exception)
815 {
816   const char sep='_';
817   map<int, Node*>::const_iterator iter;
818   for (iter = _mapOfNode.begin(); iter != _mapOfNode.end(); iter++)
819       if (iter->second == node)
820         {
821           stringstream a;
822           if (iter->first == Switch::ID_FOR_DEFAULT_NODE)
823             a << DEFAULT_NODE_NAME << sep;
824           else if (iter->first <0)
825             a << "m" << -iter->first << sep;
826           else a  << "p" << iter->first << sep; 
827           return a.str();
828         }
829   string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
830   throw Exception(what);  
831 }
832
833 void Switch::accept(Visitor *visitor)
834 {
835   visitor->visitSwitch(this);
836 }