]> git.mxchange.org Git - flightgear.git/blob - src/Traffic/TrafficMgr.cxx
PLIB net removed from FlightGear
[flightgear.git] / src / Traffic / TrafficMgr.cxx
1 /******************************************************************************
2  * TrafficMGr.cxx
3  * Written by Durk Talsma, started May 5, 2004.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  *
20  **************************************************************************/
21
22 /* 
23  * Traffic manager parses airlines timetable-like data and uses this to 
24  * determine the approximate position of each AI aircraft in its database.
25  * When an AI aircraft is close to the user's position, a more detailed 
26  * AIModels based simulation is set up. 
27  * 
28  * I'm currently assuming the following simplifications:
29  * 1) The earth is a perfect sphere
30  * 2) Each aircraft flies a perfect great circle route.
31  * 3) Each aircraft flies at a constant speed (with infinite accelerations and
32  *    decelerations) 
33  * 4) Each aircraft leaves at exactly the departure time. 
34  * 5) Each aircraft arrives at exactly the specified arrival time. 
35  *
36  *
37  *****************************************************************************/
38
39 #ifdef HAVE_CONFIG_H
40 #  include "config.h"
41 #endif
42
43 #include <stdlib.h>
44 #include <time.h>
45 #include <cstring>
46 #include <iostream>
47 #include <fstream>
48
49
50 #include <string>
51 #include <vector>
52 #include <algorithm>
53
54 #include <plib/ul.h>
55
56 #include <simgear/compiler.h>
57 #include <simgear/misc/sg_path.hxx>
58 #include <simgear/props/props.hxx>
59 #include <simgear/route/waypoint.hxx>
60 #include <simgear/structure/subsystem_mgr.hxx>
61 #include <simgear/xml/easyxml.hxx>
62
63 #include <AIModel/AIAircraft.hxx>
64 #include <AIModel/AIFlightPlan.hxx>
65 #include <AIModel/AIBase.hxx>
66 #include <Airports/simple.hxx>
67 #include <Main/fg_init.hxx>
68
69
70
71 #include "TrafficMgr.hxx"
72
73 using std::sort;
74 using std::strcmp;
75
76 /******************************************************************************
77  * TrafficManager
78  *****************************************************************************/
79 FGTrafficManager::FGTrafficManager()
80 {
81     //score = 0;
82     //runCount = 0;
83     acCounter = 0;
84 }
85
86 FGTrafficManager::~FGTrafficManager()
87 {
88     // Save the heuristics data
89     bool saveData = false;
90     ofstream cachefile;
91     if (fgGetBool("/sim/traffic-manager/heuristics")) {
92         SGPath cacheData(fgGetString("/sim/fg-home"));
93         cacheData.append("ai");
94         string airport = fgGetString("/sim/presets/airport-id");
95
96         if ((airport) != "") {
97             char buffer[128];
98             ::snprintf(buffer, 128, "%c/%c/%c/",
99                        airport[0], airport[1], airport[2]);
100             cacheData.append(buffer);
101             if (!cacheData.exists()) {
102                 cacheData.create_dir(0777);
103             }
104             cacheData.append(airport + "-cache.txt");
105             //cerr << "Saving AI traffic heuristics" << endl;
106             saveData = true;
107             cachefile.open(cacheData.str().c_str());
108         }
109     }
110     for (ScheduleVectorIterator sched = scheduledAircraft.begin();
111          sched != scheduledAircraft.end(); sched++) {
112         if (saveData) {
113             cachefile << (*sched)->getRegistration() << " "
114                 << (*sched)->getRunCount() << " "
115                 << (*sched)->getHits() << endl;
116         }
117         delete(*sched);
118     }
119     if (saveData) {
120         cachefile.close();
121     }
122     scheduledAircraft.clear();
123     flights.clear();
124 }
125
126
127 void FGTrafficManager::init()
128 {
129     ulDir *d, *d2;
130     ulDirEnt *dent, *dent2;
131
132     heuristicsVector heuristics;
133     HeuristicMap heurMap;
134
135     if (string(fgGetString("/sim/traffic-manager/datafile")) == string("")) {
136         SGPath aircraftDir = globals->get_fg_root();
137         SGPath path = aircraftDir;
138
139         aircraftDir.append("AI/Traffic");
140         if ((d = ulOpenDir(aircraftDir.c_str())) != NULL) {
141             while ((dent = ulReadDir(d)) != NULL) {
142                 if (string(dent->d_name) != string(".") &&
143                     string(dent->d_name) != string("..") && dent->d_isdir) {
144                     SGPath currACDir = aircraftDir;
145                     currACDir.append(dent->d_name);
146                     if ((d2 = ulOpenDir(currACDir.c_str())) == NULL)
147                         return;
148                     while ((dent2 = ulReadDir(d2)) != NULL) {
149                         SGPath currFile = currACDir;
150                         currFile.append(dent2->d_name);
151                         if (currFile.extension() == string("xml")) {
152                             SGPath currFile = currACDir;
153                             currFile.append(dent2->d_name);
154                             SG_LOG(SG_GENERAL, SG_DEBUG,
155                                    "Scanning " << currFile.
156                                    str() << " for traffic");
157                             readXML(currFile.str(), *this);
158                         }
159                     }
160                     ulCloseDir(d2);
161                 }
162             }
163             ulCloseDir(d);
164         }
165     } else {
166         fgSetBool("/sim/traffic-manager/heuristics", false);
167         SGPath path = string(fgGetString("/sim/traffic-manager/datafile"));
168         string ext = path.extension();
169         if (path.extension() == "xml") {
170             if (path.exists()) {
171                 readXML(path.str(), *this);
172             }
173         } else if (path.extension() == "conf") {
174             if (path.exists()) {
175                 readTimeTableFromFile(path);
176             }
177         } else {
178              SG_LOG(SG_GENERAL, SG_ALERT,
179                                "Unknown data format " << path.str()
180                                 << " for traffic");
181         }
182         //exit(1);
183     }
184     if (fgGetBool("/sim/traffic-manager/heuristics")) {
185         //cerr << "Processing Heuristics" << endl;
186         // Load the heuristics data
187         SGPath cacheData(fgGetString("/sim/fg-home"));
188         cacheData.append("ai");
189         string airport = fgGetString("/sim/presets/airport-id");
190         if ((airport) != "") {
191             char buffer[128];
192             ::snprintf(buffer, 128, "%c/%c/%c/",
193                        airport[0], airport[1], airport[2]);
194             cacheData.append(buffer);
195             cacheData.append(airport + "-cache.txt");
196             if (cacheData.exists()) {
197                 ifstream data(cacheData.c_str());
198                 while (1) {
199                     Heuristic h; // = new Heuristic;
200                     data >> h.registration >> h.runCount >> h.hits;
201                     if (data.eof())
202                         break;
203                     HeuristicMapIterator itr = heurMap.find(h.registration);
204                     if (itr != heurMap.end()) {
205                          SG_LOG(SG_GENERAL, SG_WARN,"Traffic Manager Warning: found duplicate tailnumber " << 
206                          h.registration << " for AI aircraft");
207                     }
208                     heurMap[h.registration] = h;
209                     heuristics.push_back(h);
210                 }
211             }
212         }
213         for (currAircraft = scheduledAircraft.begin();
214              currAircraft != scheduledAircraft.end(); currAircraft++) {
215             string registration = (*currAircraft)->getRegistration();
216             HeuristicMapIterator itr = heurMap.find(registration);
217             //cerr << "Processing heuristics for" << (*currAircraft)->getRegistration() << endl;
218             if (itr == heurMap.end()) {
219                 //cerr << "No heuristics found for " << registration << endl;
220             } else {
221                 (*currAircraft)->setrunCount(itr->second.runCount);
222                 (*currAircraft)->setHits(itr->second.hits);
223                 //cerr <<"Runcount " << itr->second->runCount << ".Hits " << itr->second->hits << endl;
224             }
225         }
226         //cerr << "Done" << endl;
227         //for (heuristicsVectorIterator hvi = heuristics.begin();
228         //     hvi != heuristics.end(); hvi++) {
229         //    delete(*hvi);
230         //}
231     }
232     // Do sorting and scoring separately, to take advantage of the "homeport| variable
233     for (currAircraft = scheduledAircraft.begin();
234          currAircraft != scheduledAircraft.end(); currAircraft++) {
235         (*currAircraft)->setScore();
236     }
237     sort(scheduledAircraft.begin(), scheduledAircraft.end(),
238          compareSchedules);
239     currAircraft = scheduledAircraft.begin();
240     currAircraftClosest = scheduledAircraft.begin();
241 }
242
243 void FGTrafficManager::update(double /*dt */ )
244 {
245     if (fgGetBool("/environment/metar/valid") == false) {
246         return;
247     }
248     time_t now = time(NULL) + fgGetLong("/sim/time/warp");
249     if (scheduledAircraft.size() == 0) {
250         return;
251     }
252
253     SGVec3d userCart =
254         SGVec3d::fromGeod(SGGeod::
255                           fromDeg(fgGetDouble("/position/longitude-deg"),
256                                   fgGetDouble("/position/latitude-deg")));
257
258     if (currAircraft == scheduledAircraft.end()) {
259         currAircraft = scheduledAircraft.begin();
260     }
261     //cerr << "Processing << " << (*currAircraft)->getRegistration() << " with score " << (*currAircraft)->getScore() << endl;
262     if (!((*currAircraft)->update(now, userCart))) {
263         // NOTE: With traffic manager II, this statement below is no longer true
264         // after proper initialization, we shouldnt get here.
265         // But let's make sure
266         //SG_LOG( SG_GENERAL, SG_ALERT, "Failed to update aircraft schedule in traffic manager");
267     }
268     currAircraft++;
269 }
270
271 void FGTrafficManager::release(int id)
272 {
273     releaseList.push_back(id);
274 }
275
276 bool FGTrafficManager::isReleased(int id)
277 {
278     IdListIterator i = releaseList.begin();
279     while (i != releaseList.end()) {
280         if ((*i) == id) {
281             releaseList.erase(i);
282             return true;
283         }
284         i++;
285     }
286     return false;
287 }
288
289
290 void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
291 {
292     string model;
293     string livery;
294     string homePort;
295     string registration;
296     string flightReq;
297     bool   isHeavy;
298     string acType;
299     string airline;
300     string m_class;
301     string FlightType;
302     double radius;
303     double offset;
304
305     char buffer[256];
306     string buffString;
307     vector <string> tokens, depTime,arrTime;
308     vector <string>::iterator it;
309     ifstream infile(infileName.str().c_str());
310     while (1) {
311          infile.getline(buffer, 256);
312          if (infile.eof()) {
313              break;
314          }
315          //cerr << "Read line : " << buffer << endl;
316          buffString = string(buffer);
317          tokens.clear();
318          Tokenize(buffString, tokens, " \t");
319          //for (it = tokens.begin(); it != tokens.end(); it++) {
320          //    cerr << "Tokens: " << *(it) << endl;
321          //}
322          //cerr << endl;
323          if (!tokens.empty()) {
324              if (tokens[0] == string("AC")) {
325                  if (tokens.size() != 13) {
326                      SG_LOG(SG_GENERAL, SG_ALERT, "Error parsing traffic file " << infileName.str() << " at " << buffString);
327                      exit(1);
328                  }
329                  model          = tokens[12];
330                  livery         = tokens[6];
331                  homePort       = tokens[1];
332                  registration   = tokens[2];
333                  if (tokens[11] == string("false")) {
334                      isHeavy = false;
335                  } else {
336                      isHeavy = true;
337                  }
338                  acType         = tokens[4];
339                  airline        = tokens[5];
340                  flightReq      = tokens[3] + tokens[5];
341                  m_class        = tokens[10];
342                  FlightType     = tokens[9];
343                  radius         = atof(tokens[8].c_str());
344                  offset         = atof(tokens[7].c_str());;
345                  SG_LOG(SG_GENERAL, SG_ALERT, "Adding Aircraft" << model << " " << livery << " " << homePort << " " 
346                                                                 << registration << " " << flightReq << " " << isHeavy 
347                                                                 << " " << acType << " " << airline << " " << m_class 
348                                                                 << " " << FlightType << " " << radius << " " << offset);
349                  scheduledAircraft.push_back(new FGAISchedule(model, 
350                                                               livery, 
351                                                               homePort,
352                                                               registration, 
353                                                               flightReq,
354                                                               isHeavy,
355                                                               acType, 
356                                                               airline, 
357                                                               m_class, 
358                                                               FlightType,
359                                                               radius,
360                                                               offset));
361              }
362              if (tokens[0] == string("FLIGHT")) {
363                  //cerr << "Found flight " << buffString << " size is : " << tokens.size() << endl;
364                  if (tokens.size() != 10) {
365                      SG_LOG(SG_GENERAL, SG_ALERT, "Error parsing traffic file " << infileName.str() << " at " << buffString);
366                      exit(1);
367                  }
368                  string callsign = tokens[1];
369                  string fltrules = tokens[2];
370                  string weekdays = tokens[3];
371                  string departurePort = tokens[5];
372                  string arrivalPort   = tokens[7];
373                  int    cruiseAlt     = atoi(tokens[8].c_str());
374                  string depTimeGen    = tokens[4];
375                  string arrTimeGen    = tokens[6];
376                  string repeat        = "WEEK";
377                  string requiredAircraft = tokens[9];
378
379                  if (weekdays.size() != 7) {
380                      SG_LOG(SG_GENERAL, SG_ALERT, "Found misconfigured weekdays string" << weekdays);
381                      exit(1);
382                  }
383                  depTime.clear();
384                  arrTime.clear();
385                  Tokenize(depTimeGen, depTime, ":");
386                  Tokenize(arrTimeGen, arrTime, ":");
387                  double dep = atof(depTime[0].c_str()) + (atof(depTime[1].c_str()) / 60.0);
388                  double arr = atof(arrTime[0].c_str()) + (atof(arrTime[1].c_str()) / 60.0);
389                  //cerr << "Using " << dep << " " << arr << endl;
390                  bool arrivalWeekdayNeedsIncrement = false;
391                  if (arr < dep) {
392                        arrivalWeekdayNeedsIncrement = true;
393                  }
394                  for (int i = 0; i < 7; i++) {
395                      int j = i+1;
396                      if (weekdays[i] != '.') {
397                          char buffer[4];
398                          snprintf(buffer, 4, "%d/", j);
399                          string departureTime = string(buffer) + depTimeGen + string(":00");
400                          string arrivalTime;
401                          if (!arrivalWeekdayNeedsIncrement) {
402                              arrivalTime   = string(buffer) + arrTimeGen + string(":00");
403                          }
404                          if (arrivalWeekdayNeedsIncrement && i != 6 ) {
405                              snprintf(buffer, 4, "%d/", j+1);
406                              arrivalTime   = string(buffer) + arrTimeGen + string(":00");
407                          }
408                          if (arrivalWeekdayNeedsIncrement && i == 6 ) {
409                              snprintf(buffer, 4, "%d/", 0);
410                              arrivalTime   = string(buffer) + arrTimeGen  + string(":00");
411                          }
412                          SG_LOG(SG_GENERAL, SG_ALERT, "Adding flight " << callsign       << " "
413                                                       << fltrules       << " "
414                                                       <<  departurePort << " "
415                                                       <<  arrivalPort   << " "
416                                                       <<  cruiseAlt     << " "
417                                                       <<  departureTime << " "
418                                                       <<  arrivalTime   << " "
419                                                       << repeat        << " " 
420                                                       <<  requiredAircraft);
421
422                          flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
423                                                                  fltrules,
424                                                                  departurePort,
425                                                                  arrivalPort,
426                                                                  cruiseAlt,
427                                                                  departureTime,
428                                                                  arrivalTime,
429                                                                  repeat,
430                                                                  requiredAircraft));
431                     }
432                 }
433              }
434          }
435
436     }
437     //exit(1);
438 }
439
440
441 void FGTrafficManager::Tokenize(const string& str,
442                       vector<string>& tokens,
443                       const string& delimiters)
444 {
445     // Skip delimiters at beginning.
446     string::size_type lastPos = str.find_first_not_of(delimiters, 0);
447     // Find first "non-delimiter".
448     string::size_type pos     = str.find_first_of(delimiters, lastPos);
449
450     while (string::npos != pos || string::npos != lastPos)
451     {
452         // Found a token, add it to the vector.
453         tokens.push_back(str.substr(lastPos, pos - lastPos));
454         // Skip delimiters.  Note the "not_of"
455         lastPos = str.find_first_not_of(delimiters, pos);
456         // Find next "non-delimiter"
457         pos = str.find_first_of(delimiters, lastPos);
458     }
459 }
460
461
462 void FGTrafficManager::startXML()
463 {
464     //cout << "Start XML" << endl;
465     requiredAircraft = "";
466     homePort = "";
467 }
468
469 void FGTrafficManager::endXML()
470 {
471     //cout << "End XML" << endl;
472 }
473
474 void FGTrafficManager::startElement(const char *name,
475                                     const XMLAttributes & atts)
476 {
477     const char *attval;
478     //cout << "Start element " << name << endl;
479     //FGTrafficManager temp;
480     //for (int i = 0; i < atts.size(); i++)
481     //  if (string(atts.getName(i)) == string("include"))
482     attval = atts.getValue("include");
483     if (attval != 0) {
484         //cout << "including " << attval << endl;
485         SGPath path = globals->get_fg_root();
486         path.append("/Traffic/");
487         path.append(attval);
488         readXML(path.str(), *this);
489     }
490     elementValueStack.push_back("");
491     //  cout << "  " << atts.getName(i) << '=' << atts.getValue(i) << endl; 
492 }
493
494 void FGTrafficManager::endElement(const char *name)
495 {
496     //cout << "End element " << name << endl;
497     const string & value = elementValueStack.back();
498
499     if (!strcmp(name, "model"))
500         mdl = value;
501     else if (!strcmp(name, "livery"))
502         livery = value;
503     else if (!strcmp(name, "home-port"))
504         homePort = value;
505     else if (!strcmp(name, "registration"))
506         registration = value;
507     else if (!strcmp(name, "airline"))
508         airline = value;
509     else if (!strcmp(name, "actype"))
510         acType = value;
511     else if (!strcmp(name, "required-aircraft"))
512         requiredAircraft = value;
513     else if (!strcmp(name, "flighttype"))
514         flighttype = value;
515     else if (!strcmp(name, "radius"))
516         radius = atoi(value.c_str());
517     else if (!strcmp(name, "offset"))
518         offset = atoi(value.c_str());
519     else if (!strcmp(name, "performance-class"))
520         m_class = value;
521     else if (!strcmp(name, "heavy")) {
522         if (value == string("true"))
523             heavy = true;
524         else
525             heavy = false;
526     } else if (!strcmp(name, "callsign"))
527         callsign = value;
528     else if (!strcmp(name, "fltrules"))
529         fltrules = value;
530     else if (!strcmp(name, "port"))
531         port = value;
532     else if (!strcmp(name, "time"))
533         timeString = value;
534     else if (!strcmp(name, "departure")) {
535         departurePort = port;
536         departureTime = timeString;
537     } else if (!strcmp(name, "cruise-alt"))
538         cruiseAlt = atoi(value.c_str());
539     else if (!strcmp(name, "arrival")) {
540         arrivalPort = port;
541         arrivalTime = timeString;
542     } else if (!strcmp(name, "repeat"))
543         repeat = value;
544     else if (!strcmp(name, "flight")) {
545         // We have loaded and parsed all the information belonging to this flight
546         // so we temporarily store it. 
547         //cerr << "Pusing back flight " << callsign << endl;
548         //cerr << callsign  <<  " " << fltrules     << " "<< departurePort << " " <<  arrivalPort << " "
549         //   << cruiseAlt <<  " " << departureTime<< " "<< arrivalTime   << " " << repeat << endl;
550
551         //Prioritize aircraft 
552         string apt = fgGetString("/sim/presets/airport-id");
553         //cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
554         //if (departurePort == apt) score++;
555         //flights.push_back(new FGScheduledFlight(callsign,
556         //                                fltrules,
557         //                                departurePort,
558         //                                arrivalPort,
559         //                                cruiseAlt,
560         //                                departureTime,
561         //                                arrivalTime,
562         //                                repeat));
563         if (requiredAircraft == "") {
564             char buffer[16];
565             snprintf(buffer, 16, "%d", acCounter);
566             requiredAircraft = buffer;
567         }
568         SG_LOG(SG_GENERAL, SG_DEBUG, "Adding flight: " << callsign << " "
569                << fltrules << " "
570                << departurePort << " "
571                << arrivalPort << " "
572                << cruiseAlt << " "
573                << departureTime << " "
574                << arrivalTime << " " << repeat << " " << requiredAircraft);
575         // For database maintainance purposes, it may be convenient to
576         // 
577         if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
578              SG_LOG(SG_GENERAL, SG_ALERT, "Traffic Dump FLIGHT," << callsign << ","
579                           << fltrules << ","
580                           << departurePort << ","
581                           << arrivalPort << ","
582                           << cruiseAlt << ","
583                           << departureTime << ","
584                           << arrivalTime << "," << repeat << "," << requiredAircraft);
585         }
586         flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
587                                                                   fltrules,
588                                                                   departurePort,
589                                                                   arrivalPort,
590                                                                   cruiseAlt,
591                                                                   departureTime,
592                                                                   arrivalTime,
593                                                                   repeat,
594                                                                   requiredAircraft));
595         requiredAircraft = "";
596     } else if (!strcmp(name, "aircraft")) {
597         string isHeavy;
598         if (heavy) {
599             isHeavy = "true";
600         } else {
601             isHeavy = "false"; 
602         }
603         /*
604         cerr << "Traffic Dump AC," << homePort << "," << registration << "," << requiredAircraft 
605              << "," << acType << "," << livery << "," 
606              << airline << "," << offset << "," << radius << "," << flighttype << "," << isHeavy << "," << mdl << endl;*/
607         int proportion =
608             (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
609         int randval = rand() & 100;
610         if (randval <= proportion) {
611             if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
612                 SG_LOG(SG_GENERAL, SG_ALERT, "Traffic Dump AC," << homePort << "," << registration << "," << requiredAircraft 
613                  << "," << acType << "," << livery << "," 
614                  << airline << ","  << m_class << "," << offset << "," << radius << "," << flighttype << "," << isHeavy << "," << mdl);
615             }
616             //scheduledAircraft.push_back(new FGAISchedule(mdl, 
617             //                                     livery, 
618             //                                     registration, 
619             //                                     heavy,
620             //                                     acType, 
621             //                                     airline, 
622             //                                     m_class, 
623             //                                     flighttype,
624             //                                     radius,
625             //                                     offset,
626             //                                     score,
627             //                                     flights));
628             if (requiredAircraft == "") {
629                 char buffer[16];
630                 snprintf(buffer, 16, "%d", acCounter);
631                 requiredAircraft = buffer;
632             }
633             if (homePort == "") {
634                 homePort = departurePort;
635             }
636             scheduledAircraft.push_back(new FGAISchedule(mdl,
637                                                          livery,
638                                                          homePort,
639                                                          registration,
640                                                          requiredAircraft,
641                                                          heavy,
642                                                          acType,
643                                                          airline,
644                                                          m_class,
645                                                          flighttype,
646                                                          radius, offset));
647
648             //  while(flights.begin() != flights.end()) {
649 //      flights.pop_back();
650 //       }
651         } else {
652             cerr << "Skipping : " << randval;
653         }
654         acCounter++;
655         requiredAircraft = "";
656         homePort = "";
657         //for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
658         //  {
659         //    delete (*flt);
660         //  }
661         //flights.clear();
662         SG_LOG(SG_GENERAL, SG_BULK, "Reading aircraft : "
663                << registration << " with prioritization score " << score);
664         score = 0;
665     }
666     elementValueStack.pop_back();
667 }
668
669 void FGTrafficManager::data(const char *s, int len)
670 {
671     string token = string(s, len);
672     //cout << "Character data " << string(s,len) << endl;
673     elementValueStack.back() += token;
674 }
675
676 void FGTrafficManager::pi(const char *target, const char *data)
677 {
678     //cout << "Processing instruction " << target << ' ' << data << endl;
679 }
680
681 void FGTrafficManager::warning(const char *message, int line, int column)
682 {
683     SG_LOG(SG_IO, SG_WARN,
684            "Warning: " << message << " (" << line << ',' << column << ')');
685 }
686
687 void FGTrafficManager::error(const char *message, int line, int column)
688 {
689     SG_LOG(SG_IO, SG_ALERT,
690            "Error: " << message << " (" << line << ',' << column << ')');
691 }