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