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