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