Salome HOME
40a3e342e2a6b86983325d809e1d66752228acb9
[modules/yacs.git] / src / engine / LinkInfo.cxx
1 // Copyright (C) 2006-2022  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 "LinkInfo.hxx"
21 #include "Switch.hxx"
22
23 #include <sstream>
24
25 using namespace std;
26 using namespace YACS::ENGINE;
27
28 static const char GLOBAL_MESSAGE1[]="Global report  : \n";
29
30 static const char LINK_REPR[]="link";
31
32 LinkInfo::LinkInfo(unsigned char level):_levelOfInfo(level),_level(0)
33 {
34 }
35
36 void LinkInfo::clearAll()
37 {
38   _level=0;
39   _unsetInPort.clear();
40   _onlyBackDefined.clear();
41   _uselessLinks.clear();
42   _infos.clear();
43   _collapse.clear();
44   _errors.clear();
45   _errorsOnSwitchCases.clear();
46 }
47
48 void LinkInfo::startCollapseTransac()
49 {
50   _level++;
51 }
52
53 void LinkInfo::endCollapseTransac()
54 {
55   if(--_level==0)
56     {
57       if(_levelOfInfo==ALL_STOP_ASAP)
58         if(areWarningsOrErrors())
59           throw Exception(getGlobalRepr());
60       else if(_levelOfInfo==WARN_ONLY_DONT_STOP)
61         if(getNumberOfWarnLinksGrp(W_ALL)!=0)
62           throw Exception(getErrRepr());
63     }
64 }
65
66 void LinkInfo::setPointOfView(ComposedNode *pov)
67 {
68   _pov=pov;
69 }
70
71 void LinkInfo::pushInfoLink(OutPort *semStart, InPort *end, InfoReason reason)
72 {
73   _infos[reason].push_back(pair<OutPort *, InPort *>(semStart,end));
74 }
75
76 void LinkInfo::pushWarnLink(OutPort *semStart, InPort *end, WarnReason reason)
77 {
78   if(_collapse[reason].empty())
79     _collapse[reason].push_back(vector< pair<OutPort *,InPort *> >());
80   else
81     if(_collapse[reason].back()[0].second!=end)
82       _collapse[reason].push_back(vector< pair<OutPort *,InPort *> >());
83   _collapse[reason].back().push_back(pair<OutPort *,InPort *>(semStart,end));
84 }
85
86 void LinkInfo::pushErrLink(OutPort *semStart, InPort *end, ErrReason reason)
87 {
88   if(reason==E_NEVER_SET_INPUTPORT)
89     _unsetInPort.push_back(end);
90   else if(reason==E_ONLY_BACKWARD_DEFINED)
91     _onlyBackDefined.push_back(end);
92   else
93     _errors[reason].push_back(pair<OutPort *, InPort *>(semStart,end));
94   if(_level==0)
95     if(_levelOfInfo==ALL_STOP_ASAP || _levelOfInfo==WARN_ONLY_DONT_STOP)
96       throw Exception(getErrRepr());
97 }
98
99 void LinkInfo::pushErrSwitch(CollectorSwOutPort *collector)
100 {
101   _errorsOnSwitchCases.push_back(collector);
102   if(_level==0)
103     if(_levelOfInfo==ALL_STOP_ASAP || _levelOfInfo==WARN_ONLY_DONT_STOP)
104       throw Exception(getErrRepr());
105 }
106
107 void LinkInfo::pushUselessCFLink(Node *start, Node *end)
108 {
109   _uselessLinks.insert(pair<Node *,Node *>(start,end));
110 }
111
112 void LinkInfo::takeDecision() const
113 {
114   if(!_errors.empty())
115     throw Exception(getErrRepr());
116 }
117
118 std::string LinkInfo::getGlobalRepr() const
119 {
120   ostringstream retS; retS << GLOBAL_MESSAGE1;
121   retS << printThereIsAre(getNumberOfErrLinks(E_ALL),"error") << ".\n";
122   retS << printThereIsAre(getNumberOfWarnLinksGrp(W_ALL),"warning") << ".\n";
123   retS << printThereIsAre(getNumberOfInfoLinks(I_ALL),"info") << ".\n";
124   if(getNumberOfErrLinks(E_ALL)>0)
125     {
126       retS << "****** ERRORS ******" << endl;
127       retS << getErrRepr() << endl;
128     }
129   if(getNumberOfWarnLinksGrp(W_ALL)>0)
130     {
131       retS << "****** WARNINGS ******" << endl;
132       retS << getWarnRepr() << endl;
133     }
134   if(getNumberOfInfoLinks(I_ALL)>0)
135     {
136       retS << "****** INFO ******" << endl;
137       retS << getInfoRepr() << endl;
138     }
139   return retS.str();
140 }
141
142 std::string LinkInfo::getInfoRepr() const
143 {
144   map<InfoReason, vector< pair<OutPort *,InPort *> > >::const_iterator iter;
145   ostringstream stream;
146   for(iter=_infos.begin();iter!=_infos.end();iter++)
147     {
148       for(vector< pair<OutPort *,InPort *> >::const_iterator iter2=(*iter).second.begin();iter2!=(*iter).second.end();iter2++)
149         {
150           stream << getStringReprOfI((*iter).first) << " between \"" << _pov->getOutPortName((*iter2).first);
151           stream << "\" and \"" << _pov->getInPortName((*iter2).second) << "\"." << endl;
152         }
153     }
154   set< pair<Node *, Node *> >::const_iterator iter3;
155   for(iter3=_uselessLinks.begin();iter3!=_uselessLinks.end();iter3++)
156     {
157       stream << "Useless CF link between \"" << _pov->getChildName((*iter3).first);
158       stream << "\" and \"" << _pov->getChildName((*iter3).second) << "\"." << endl;
159     }
160   return stream.str();
161 }
162
163 std::string LinkInfo::getWarnRepr() const
164 {
165   map<WarnReason, vector< vector< pair<OutPort *,InPort *> > > >::const_iterator iter;
166   ostringstream stream;
167   unsigned i=0;
168   for(iter=_collapse.begin();iter!=_collapse.end();iter++)
169     {
170       stream << getStringReprOfW((*iter).first) << " for group containing following group links: ";
171       vector< vector< pair<OutPort *,InPort *> > >::const_iterator iter2=(*iter).second.begin();
172       for(;iter2!=(*iter).second.end();iter2++)
173         {
174           stream << "    Group # " << i++ << " : " << endl;
175           for(vector< pair<OutPort *,InPort *> >::const_iterator iter3=(*iter2).begin();iter3!=(*iter2).end();iter3++)
176             stream << "          \"" << _pov->getOutPortName((*iter3).first) << "\" and \"" << _pov->getInPortName((*iter3).second) << endl;
177         }
178     }
179   return stream.str();
180 }
181
182 std::string LinkInfo::getErrRepr() const
183 {
184   vector<InPort *>::const_iterator iter;
185   ostringstream stream;
186   for(iter=_unsetInPort.begin();iter!=_unsetInPort.end();iter++)
187     stream << getStringReprOfE(E_NEVER_SET_INPUTPORT) << "\"" << _pov->getInPortName(*iter) << "\"." << endl;
188   for(iter=_onlyBackDefined.begin();iter!=_onlyBackDefined.end();iter++)
189     stream << getStringReprOfE(E_ONLY_BACKWARD_DEFINED) << "\"" << _pov->getInPortName(*iter) << "\"." << endl;
190   map<ErrReason, vector< pair<OutPort *,InPort *> > >::const_iterator iter2;
191   for(iter2=_errors.begin();iter2!=_errors.end();iter2++)
192     for(vector< pair<OutPort *,InPort *> >::const_iterator iter3=(*iter2).second.begin();iter3!=(*iter2).second.end();iter3++)
193       stream << getStringReprOfE((*iter2).first) << " between \"" <<_pov->getOutPortName((*iter3).first) << "\" and \"" << _pov->getInPortName((*iter3).second) << endl;
194   for(vector<CollectorSwOutPort *>::const_iterator iter3=_errorsOnSwitchCases.begin();iter3!=_errorsOnSwitchCases.end();iter3++)
195     (*iter3)->getHumanReprOfIncompleteCases(stream);
196   return stream.str();
197 }
198
199 bool LinkInfo::areWarningsOrErrors() const
200 {
201   return (getNumberOfWarnLinksGrp(W_ALL)!=0) || (getNumberOfErrLinks(E_ALL)!=0) || !_unsetInPort.empty() || !_onlyBackDefined.empty();
202 }
203
204 /*!
205  * If 'reason'==I_ALL returns nummmber of types of links info whereas it returns number of info per type.
206  */
207 unsigned LinkInfo::getNumberOfInfoLinks(InfoReason reason) const
208 {
209   if(reason==I_ALL)
210     {
211       map<InfoReason, vector< pair<OutPort *,InPort *> > >::const_iterator iter=_infos.begin();
212       unsigned val=0;
213       for(;iter!=_infos.end();iter++)
214         val+=(*iter).second.size();
215       return val+_uselessLinks.size();
216     }
217   if(reason==I_CF_USELESS)
218     return _uselessLinks.size();
219   else
220     {
221       map<InfoReason, vector< pair<OutPort *,InPort *> > >::const_iterator iter=_infos.find(reason);
222       if(iter!=_infos.end())
223         return (*iter).second.size();
224       else
225         return 0;
226     }
227 }
228
229 unsigned LinkInfo::getNumberOfWarnLinksGrp(WarnReason reason) const
230 {
231   unsigned ret=0;
232   map<WarnReason, vector< vector< pair<OutPort *,InPort *> > > >::const_iterator iter;
233   if(reason==W_ALL)
234     {
235       for(iter=_collapse.begin();iter!=_collapse.end();iter++)
236         ret+=(*iter).second.size();
237       return ret;
238     }
239   map<WarnReason, vector< vector< pair<OutPort *,InPort *> > > >::const_iterator iter2=_collapse.find(reason);
240   if(iter2!=_collapse.end())
241     return (*iter2).second.size();
242   else
243     return 0;
244 }
245
246 unsigned LinkInfo::getNumberOfErrLinks(ErrReason reason) const
247 {
248   if(reason==E_ALL)
249     return _errors.size()+_onlyBackDefined.size()+_unsetInPort.size()+_errorsOnSwitchCases.size();
250   else if(reason==E_NEVER_SET_INPUTPORT)
251     return _unsetInPort.size();
252   else if(reason==E_ONLY_BACKWARD_DEFINED)
253     return _onlyBackDefined.size();
254   else if(reason==E_UNCOMPLETE_SW)
255     return _errorsOnSwitchCases.size();
256   else
257     {
258       map<ErrReason, vector< pair<OutPort *,InPort *> > >::const_iterator iter=_errors.find(reason);
259       if(iter!=_errors.end())
260         return (*iter).second.size();
261       else
262         return 0;
263     }
264 }
265
266 std::set< std::pair<Node *, Node *> > LinkInfo::getInfoUselessLinks() const
267 {
268   return _uselessLinks;
269 }
270
271 std::pair<OutPort *, InPort *> LinkInfo::getInfoLink(unsigned id, InfoReason reason) const
272 {
273   if(reason==I_CF_USELESS)
274     return pair<OutPort *, InPort *>();
275   map<InfoReason, vector< pair<OutPort *,InPort *> > >::const_iterator iter=_infos.find(reason);
276   if(iter!=_infos.end())
277     return (*iter).second[id];
278   else
279     return pair<OutPort *, InPort *>( reinterpret_cast<OutPort *>(0), reinterpret_cast<InPort *>(0) );
280 }
281
282 std::vector< std::pair<OutPort *, InPort *> > LinkInfo::getWarnLink(unsigned id, WarnReason reason) const
283 {
284   map<WarnReason, vector< vector< pair<OutPort *,InPort *> > > >::const_iterator iter=_collapse.find(reason);
285   if(iter!=_collapse.end())
286     return (*iter).second[id];
287   else
288     return vector< pair<OutPort *, InPort *> >();
289 }
290
291 std::pair<OutPort *, InPort *> LinkInfo::getErrLink(unsigned id, ErrReason reason) const
292 {
293   if(reason==E_NEVER_SET_INPUTPORT)
294     return pair<OutPort *, InPort *>( reinterpret_cast<OutPort *>(0), _unsetInPort[id] );
295   else if(reason==E_ONLY_BACKWARD_DEFINED)
296     return pair<OutPort *, InPort *>( reinterpret_cast<OutPort *>(0), _onlyBackDefined[id] );
297   else
298     {
299       map<ErrReason, vector< pair<OutPort *,InPort *> > >::const_iterator iter=_errors.find(reason);
300       if(iter!=_errors.end())
301         return (*iter).second[id];
302       else
303         return pair<OutPort *, InPort *>( reinterpret_cast<OutPort *>(0), reinterpret_cast<InPort *>(0) );
304     }
305 }
306
307 std::string LinkInfo::getStringReprOfI(InfoReason reason)
308 {
309   string ret;
310   switch(reason)
311     {
312     case I_USELESS:
313       ret="Useless DF";
314       break;
315     case I_BACK:
316       ret="Back";
317       break;
318     case I_BACK_USELESS:
319       ret="Back and useless";
320       break;
321     case I_BACK_CRAZY:
322       ret+="Crazy back";
323       break;
324     case I_DFDS:
325       ret+="DF/DS";
326     }
327   ret+=" "; ret+=LINK_REPR;
328   return ret;
329 }
330
331 std::string LinkInfo::getStringReprOfW(WarnReason reason)
332 {
333   string ret;
334   switch(reason)
335     {
336     case W_COLLAPSE:
337       ret="Collapse";
338       break;
339     case W_COLLAPSE_AND_USELESS:
340       ret="Collapse and useless";
341       break;
342     case W_COLLAPSE_EL:
343       ret="Collapse on ElementaryNode";
344       break;
345     case W_COLLAPSE_EL_AND_USELESS:
346       ret+="Collapse on ElementaryNode and useless";
347       break;
348     case W_BACK_COLLAPSE:
349       ret+="Back collapse";
350       break;
351     case W_BACK_COLLAPSE_AND_USELESS:
352       ret+="Back collapse and useless";
353       break;
354     case W_BACK_COLLAPSE_EL:
355       ret+="Back collapse on ElementaryNode";
356       break;
357     case W_BACK_COLLAPSE_EL_AND_USELESS:
358       ret+="Back collapse and useless on ElementaryNode";
359     }
360   ret+=" "; ret+=LINK_REPR;
361   return ret;
362 }
363
364 std::string LinkInfo::getStringReprOfE(ErrReason reason)
365 {
366   string ret;
367   if(reason==E_NEVER_SET_INPUTPORT)
368     return "Never set InPort ";
369   if(reason==E_ONLY_BACKWARD_DEFINED)
370     return "Never set InPort only back defined ";
371   switch(reason)
372     {
373     case E_DS_LINK_UNESTABLISHABLE:
374       ret="DS unestablishable";
375       break;
376     case E_COLLAPSE_DFDS:
377       ret="DF/DS collapse";
378       break;
379     case E_COLLAPSE_DS:
380       ret="Inter DS collapse";
381       break;
382     case E_UNPREDICTABLE_FED:
383       ret="Unpredictable fed";
384     }
385   ret+=" "; ret+=LINK_REPR;
386   return ret;
387 }
388
389 std::string LinkInfo::printThereIsAre(unsigned val, const std::string& other)
390 {
391   ostringstream ret;
392   ret << "There ";
393   if(val==0)
394     ret << "are no";
395   else if(val==1)
396     ret << "is one";
397   else
398     ret << "are " << val;
399   ret << " " << other;
400   if(val==0 || val>1)
401     ret << "s";
402   return ret.str();
403 }