]> git.mxchange.org Git - flightgear.git/blobdiff - src/Traffic/TrafficMgr.cxx
Clean up namespace issues
[flightgear.git] / src / Traffic / TrafficMgr.cxx
index 7c13f0db602d59710d1b007b62a67f5025041569..ee8e9c64feaec3169fe0cf7c7e17e23c26511d46 100644 (file)
@@ -18,7 +18,7 @@
  *
  *
  **************************************************************************/
+
 /* 
  * Traffic manager parses airlines timetable-like data and uses this to 
  * determine the approximate position of each AI aircraft in its database.
 #include <string>
 #include <vector>
 #include <algorithm>
-
-#include <plib/ul.h>
+#include <boost/foreach.hpp>
 
 #include <simgear/compiler.h>
 #include <simgear/misc/sg_path.hxx>
+#include <simgear/misc/sg_dir.hxx>
 #include <simgear/props/props.hxx>
-#include <simgear/route/waypoint.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/xml/easyxml.hxx>
+#include <simgear/threads/SGThread.hxx>
+#include <simgear/threads/SGGuard.hxx>
 
 #include <AIModel/AIAircraft.hxx>
 #include <AIModel/AIFlightPlan.hxx>
 #include <Airports/simple.hxx>
 #include <Main/fg_init.hxx>
 
-
-
 #include "TrafficMgr.hxx"
 
 using std::sort;
 using std::strcmp;
+using std::endl;
+
+/**
+ * Thread encapsulating parsing the traffic schedules. 
+ */
+class ScheduleParseThread : public SGThread
+{
+public:
+  ScheduleParseThread(FGTrafficManager* traffic) :
+    _trafficManager(traffic),
+    _isFinished(false),
+    _cancelThread(false)
+  {
+    
+  }
+  
+  // if we're destroyed while running, ensure the thread exits cleanly
+  ~ScheduleParseThread()
+  {
+    _lock.lock();
+    if (!_isFinished) {
+      _cancelThread = true; // request cancellation so we don't wait ages
+      _lock.unlock();
+      join();
+    } else {
+      _lock.unlock();
+    }
+  }
+  
+  void setTrafficDir(const SGPath& trafficDirPath)
+  {
+    _trafficDirPath = trafficDirPath;
+  }
+  
+  bool isFinished() const
+  {
+    SGGuard<SGMutex> g(_lock);
+    return _isFinished;
+  }
+  
+  virtual void run()
+  {
+    SGTimeStamp st;
+    st.stamp();
+    
+    simgear::Dir trafficDir(_trafficDirPath);
+    simgear::PathList d = trafficDir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT);
+    
+    BOOST_FOREACH(SGPath p, d) {
+      simgear::Dir d2(p);
+      simgear::PathList trafficFiles = d2.children(simgear::Dir::TYPE_FILE, ".xml");
+      BOOST_FOREACH(SGPath xml, trafficFiles) {
+        _trafficManager->parseSchedule(xml);
+        if (_cancelThread) {
+          return;
+        }
+      }
+    } // of sub-directories in AI/Traffic iteration
+    
+  //  _trafficManager->parseSchedules(schedulesToRead);
+    SG_LOG(SG_AI, SG_INFO, "parsing traffic schedules took:" << st.elapsedMSec() << "msec");
+    
+    SGGuard<SGMutex> g(_lock);
+    _isFinished = true;
+  }
+private:
+  FGTrafficManager* _trafficManager;
+  mutable SGMutex _lock;
+  bool _isFinished;
+  bool _cancelThread;
+  SGPath _trafficDirPath;
+};
+
 /******************************************************************************
  * TrafficManager
  *****************************************************************************/
-FGTrafficManager::FGTrafficManager()
+FGTrafficManager::FGTrafficManager() :
+  inited(false),
+  doingInit(false),
+  waitingMetarTime(0.0),
+  enabled("/sim/traffic-manager/enabled"),
+  aiEnabled("/sim/ai/enabled"),
+  realWxEnabled("/environment/realwx/enabled"),
+  metarValid("/environment/metar/valid")
 {
-  //score = 0;
-  //runCount = 0;
-  acCounter = 0;
+    //score = 0;
+    //runCount = 0;
+    acCounter = 0;
 }
 
-FGTrafficManager:: ~FGTrafficManager()
+FGTrafficManager::~FGTrafficManager()
 {
-  for (ScheduleVectorIterator sched = scheduledAircraft.begin(); sched != scheduledAircraft.end(); sched++)
-    {
-      delete (*sched);
+    shutdown();
+}
+
+void FGTrafficManager::shutdown()
+{
+    if (!inited) {
+      if (doingInit) {
+        scheduleParser.reset();
+        doingInit = false;
+      }
+      
+      return;
+    }
+  
+    // Save the heuristics data
+    bool saveData = false;
+    std::ofstream cachefile;
+    if (fgGetBool("/sim/traffic-manager/heuristics")) {
+        SGPath cacheData(globals->get_fg_home());
+        cacheData.append("ai");
+        string airport = fgGetString("/sim/presets/airport-id");
+
+        if ((airport) != "") {
+            char buffer[128];
+            ::snprintf(buffer, 128, "%c/%c/%c/",
+                       airport[0], airport[1], airport[2]);
+            cacheData.append(buffer);
+            if (!cacheData.exists()) {
+                cacheData.create_dir(0777);
+            }
+            cacheData.append(airport + "-cache.txt");
+            //cerr << "Saving AI traffic heuristics" << endl;
+            saveData = true;
+            cachefile.open(cacheData.str().c_str());
+            cachefile << "[TrafficManagerCachedata:ref:2011:09:04]" << endl;
+        }
+    }
+  
+    BOOST_FOREACH(FGAISchedule* acft, scheduledAircraft) {
+        if (saveData) {
+            cachefile << acft->getRegistration() << " "
+                << acft->getRunCount() << " "
+                << acft->getHits() << " "
+                << acft->getLastUsed() << endl;
+        }
+        delete acft;
+    }
+    if (saveData) {
+        cachefile.close();
     }
-  scheduledAircraft.clear();
-  flights.clear();
+    scheduledAircraft.clear();
+    flights.clear();
+
+    currAircraft = scheduledAircraft.begin();
+    doingInit = false;
+    inited = false;
 }
 
+/// caution - this is run on the helper thread to improve startup
+/// responsiveness - do not access properties or global state from
+/// here, since there's no locking protection at all
+void FGTrafficManager::parseSchedule(const SGPath& path)
+{
+  readXML(path.str(), *this);
+}
 
 void FGTrafficManager::init()
-{ 
-  ulDir* d, *d2;
-  ulDirEnt* dent, *dent2;
-  SGPath aircraftDir = globals->get_fg_root();
+{
+    if (!enabled) {
+      return;
+    }
 
-  SGPath path = aircraftDir;
-  
-  aircraftDir.append("AI/Traffic");
-  if ((d = ulOpenDir(aircraftDir.c_str())) != NULL)
-    {
-      while((dent = ulReadDir(d)) != NULL) {
-       if (string(dent->d_name) != string(".")  && 
-           string(dent->d_name) != string("..") &&
-           dent->d_isdir)
-         {
-           SGPath currACDir = aircraftDir;
-           currACDir.append(dent->d_name);
-           if ((d2 = ulOpenDir(currACDir.c_str())) == NULL)
-             return;
-           while ((dent2 = ulReadDir(d2)) != NULL) {
-             SGPath currFile = currACDir;
-             currFile.append(dent2->d_name);
-             if (currFile.extension() == string("xml"))
-               {
-                 SGPath currFile = currACDir;
-                 currFile.append(dent2->d_name);
-                 SG_LOG(SG_GENERAL, SG_DEBUG, "Scanning " << currFile.str() << " for traffic");
-                 readXML(currFile.str(),*this);
-               }
-           }
-           ulCloseDir(d2);
-         }
-      }
-      ulCloseDir(d);
+    assert(!doingInit);
+    doingInit = true;
+    if (string(fgGetString("/sim/traffic-manager/datafile")) == string("")) {
+        scheduleParser.reset(new ScheduleParseThread(this));
+        scheduleParser->setTrafficDir(SGPath(globals->get_fg_root(), "AI/Traffic"));      
+        scheduleParser->start();
+    } else {
+        fgSetBool("/sim/traffic-manager/heuristics", false);
+        SGPath path = string(fgGetString("/sim/traffic-manager/datafile"));
+        string ext = path.extension();
+        if (path.extension() == "xml") {
+            if (path.exists()) {
+                readXML(path.str(), *this);
+            }
+        } else if (path.extension() == "conf") {
+            if (path.exists()) {
+                readTimeTableFromFile(path);
+            }
+        } else {
+             SG_LOG(SG_AI, SG_ALERT,
+                               "Unknown data format " << path.str()
+                                << " for traffic");
+        }
+        //exit(1);
+    }
+}
+
+
+
+void FGTrafficManager::finishInit()
+{
+    assert(doingInit);
+    SG_LOG(SG_AI, SG_INFO, "finishing AI-Traffic init");
+    loadHeuristics();
+    
+    // Do sorting and scoring separately, to take advantage of the "homeport" variable
+    BOOST_FOREACH(FGAISchedule* schedule, scheduledAircraft) {
+        schedule->setScore();
     }
     
+    sort(scheduledAircraft.begin(), scheduledAircraft.end(),
+         compareSchedules);
     currAircraft = scheduledAircraft.begin();
     currAircraftClosest = scheduledAircraft.begin();
+    
+    doingInit = false;
+    inited = true;
 }
 
-void FGTrafficManager::update(double /*dt*/)
+void FGTrafficManager::loadHeuristics()
 {
-  if (fgGetBool("/environment/metar/valid") == false) {
-       return;
-  }
-  time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-  if (scheduledAircraft.size() == 0) {
-    return;
-  }
-  
-  SGVec3d userCart = SGVec3d::fromGeod(SGGeod::fromDeg(
-    fgGetDouble("/position/longitude-deg"), 
-    fgGetDouble("/position/latitude-deg")));
+    if (!fgGetBool("/sim/traffic-manager/heuristics")) {
+        return;
+    }
   
-  if(currAircraft == scheduledAircraft.end())
+    HeuristicMap heurMap;
+    //cerr << "Processing Heuristics" << endl;
+    // Load the heuristics data
+    SGPath cacheData(globals->get_fg_home());
+    cacheData.append("ai");
+    string airport = fgGetString("/sim/presets/airport-id");
+    if ((airport) != "") {
+      char buffer[128];
+      ::snprintf(buffer, 128, "%c/%c/%c/",
+                 airport[0], airport[1], airport[2]);
+      cacheData.append(buffer);
+      cacheData.append(airport + "-cache.txt");
+      string revisionStr;
+      if (cacheData.exists()) {
+        std::ifstream data(cacheData.c_str());
+        data >> revisionStr;
+        if (revisionStr != "[TrafficManagerCachedata:ref:2011:09:04]") {
+          SG_LOG(SG_GENERAL, SG_ALERT,"Traffic Manager Warning: discarding outdated cachefile " << 
+                 cacheData.c_str() << " for Airport " << airport);
+        } else {
+          while (1) {
+            Heuristic h; // = new Heuristic;
+            data >> h.registration >> h.runCount >> h.hits >> h.lastRun;
+            if (data.eof())
+              break;
+            HeuristicMapIterator itr = heurMap.find(h.registration);
+            if (itr != heurMap.end()) {
+              SG_LOG(SG_GENERAL, SG_WARN,"Traffic Manager Warning: found duplicate tailnumber " << 
+                     h.registration << " for AI aircraft");
+            } else {
+              heurMap[h.registration] = h;
+            }
+          }
+        }
+      }
+    } 
+    
+  for(currAircraft = scheduledAircraft.begin(); currAircraft != scheduledAircraft.end(); ++currAircraft) {
+        string registration = (*currAircraft)->getRegistration();
+        HeuristicMapIterator itr = heurMap.find(registration);
+        if (itr != heurMap.end()) {
+            (*currAircraft)->setrunCount(itr->second.runCount);
+            (*currAircraft)->setHits(itr->second.hits);
+            (*currAircraft)->setLastUsed(itr->second.lastRun);
+        }
+    }
+}
+
+bool FGTrafficManager::metarReady(double dt)
+{
+    // wait for valid METAR (when realWX is enabled only), since we need
+    // to know the active runway
+    if (metarValid || !realWxEnabled)
     {
-      currAircraft = scheduledAircraft.begin();
+        waitingMetarTime = 0.0;
+        return true;
     }
-  if (!((*currAircraft)->update(now, userCart)))
+
+    // METAR timeout: when running offline, remote server is down etc
+    if (waitingMetarStation != fgGetString("/environment/metar/station-id"))
     {
-      // NOTE: With traffic manager II, this statement below is no longer true
-      // after proper initialization, we shouldnt get here.
-      // But let's make sure
-      //SG_LOG( SG_GENERAL, SG_ALERT, "Failed to update aircraft schedule in traffic manager");
+        // station has changed: wait for reply, restart timeout
+        waitingMetarTime = 0.0;
+        waitingMetarStation = fgGetString("/environment/metar/station-id");
+        return false;
     }
-  currAircraft++;
-}
 
-void FGTrafficManager::release(int id)
-{
-  releaseList.push_back(id);
+    // timeout elapsed (10 seconds)?
+    if (waitingMetarTime > 20.0)
+    {
+        return true;
+    }
+
+    waitingMetarTime += dt;
+    return false;
 }
 
-bool FGTrafficManager::isReleased(int id)
+void FGTrafficManager::update(double dt)
 {
-  IdListIterator i = releaseList.begin();
-  while (i != releaseList.end())
+    if (!enabled)
+    {
+        if (inited || doingInit)
+            shutdown();
+        return;
+    }
+
+    if (!metarReady(dt))
+        return;
+
+    if (!aiEnabled)
     {
-      if ((*i) == id)
-       {
-         releaseList.erase(i);
-         return true;
-       }
-      i++;
+        // traffic depends on AI module
+        aiEnabled = true;
+    }
+
+    if (!inited) {
+        if (!doingInit) {
+            init();
+        }
+        
+        if (!scheduleParser->isFinished()) {
+          return;
+        }
+      
+        finishInit();
     }
-  return false;
+        
+    time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+    if (scheduledAircraft.empty()) {
+        return;
+    }
+
+    SGVec3d userCart = globals->get_aircraft_position_cart();
+
+    if (currAircraft == scheduledAircraft.end()) {
+        currAircraft = scheduledAircraft.begin();
+    }
+    //cerr << "Processing << " << (*currAircraft)->getRegistration() << " with score " << (*currAircraft)->getScore() << endl;
+    if (!((*currAircraft)->update(now, userCart))) {
+        (*currAircraft)->taint();
+    }
+    currAircraft++;
 }
-/*
+
 void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
 {
     string model;
@@ -202,7 +433,7 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
     string buffString;
     vector <string> tokens, depTime,arrTime;
     vector <string>::iterator it;
-    ifstream infile(infileName.str().c_str());
+    std::ifstream infile(infileName.str().c_str());
     while (1) {
          infile.getline(buffer, 256);
          if (infile.eof()) {
@@ -238,9 +469,16 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
                  FlightType     = tokens[9];
                  radius         = atof(tokens[8].c_str());
                  offset         = atof(tokens[7].c_str());;
-                 //cerr << "Found AC string " << model << " " << livery << " " << homePort << " " 
-                 //     << registration << " " << flightReq << " " << isHeavy << " " << acType << " " << airline << " " << m_class 
-                 //     << " " << FlightType << " " << radius << " " << offset << endl;
+                 
+                 if (!FGAISchedule::validModelPath(model)) {
+                     SG_LOG(SG_GENERAL, SG_WARN, "TrafficMgr: Missing model path:" << 
+                            model << " from " << infileName.str());
+                 } else {
+                 
+                 SG_LOG(SG_GENERAL, SG_INFO, "Adding Aircraft" << model << " " << livery << " " << homePort << " " 
+                                                                << registration << " " << flightReq << " " << isHeavy 
+                                                                << " " << acType << " " << airline << " " << m_class 
+                                                                << " " << FlightType << " " << radius << " " << offset);
                  scheduledAircraft.push_back(new FGAISchedule(model, 
                                                               livery, 
                                                               homePort,
@@ -253,6 +491,7 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
                                                               FlightType,
                                                               radius,
                                                               offset));
+                 } // of valid model path
              }
              if (tokens[0] == string("FLIGHT")) {
                  //cerr << "Found flight " << buffString << " size is : " << tokens.size() << endl;
@@ -270,9 +509,9 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
                  string arrTimeGen    = tokens[6];
                  string repeat        = "WEEK";
                  string requiredAircraft = tokens[9];
-                 
+
                  if (weekdays.size() != 7) {
-                     cerr << "Found misconfigured weekdays string" << weekdays << endl;
+                     SG_LOG(SG_GENERAL, SG_ALERT, "Found misconfigured weekdays string" << weekdays);
                      exit(1);
                  }
                  depTime.clear();
@@ -287,31 +526,32 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
                        arrivalWeekdayNeedsIncrement = true;
                  }
                  for (int i = 0; i < 7; i++) {
+                     int j = i+1;
                      if (weekdays[i] != '.') {
                          char buffer[4];
-                         snprintf(buffer, 4, "%d/", i);
+                         snprintf(buffer, 4, "%d/", j);
                          string departureTime = string(buffer) + depTimeGen + string(":00");
                          string arrivalTime;
                          if (!arrivalWeekdayNeedsIncrement) {
                              arrivalTime   = string(buffer) + arrTimeGen + string(":00");
                          }
                          if (arrivalWeekdayNeedsIncrement && i != 6 ) {
-                             snprintf(buffer, 4, "%d/", i+1);
+                             snprintf(buffer, 4, "%d/", j+1);
                              arrivalTime   = string(buffer) + arrTimeGen + string(":00");
                          }
                          if (arrivalWeekdayNeedsIncrement && i == 6 ) {
                              snprintf(buffer, 4, "%d/", 0);
                              arrivalTime   = string(buffer) + arrTimeGen  + string(":00");
                          }
-                         cerr << "Adding flight: " << callsign       << " "
-                                                   << fltrules       << " "
-                                                   <<  departurePort << " "
-                                                   <<  arrivalPort   << " "
-                                                   <<  cruiseAlt     << " "
-                                                   <<  departureTime << " "
-                                                   <<  arrivalTime   << " "
-                                                   <<  repeat        << " " 
-                                                   <<  requiredAircraft << endl;
+                         SG_LOG(SG_GENERAL, SG_ALERT, "Adding flight " << callsign       << " "
+                                                      << fltrules       << " "
+                                                      <<  departurePort << " "
+                                                      <<  arrivalPort   << " "
+                                                      <<  cruiseAlt     << " "
+                                                      <<  departureTime << " "
+                                                      <<  arrivalTime   << " "
+                                                      << repeat        << " " 
+                                                      <<  requiredAircraft);
 
                          flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
                                                                  fltrules,
@@ -329,9 +569,9 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
 
     }
     //exit(1);
-}*/
+}
+
 
-/*
 void FGTrafficManager::Tokenize(const string& str,
                       vector<string>& tokens,
                       const string& delimiters)
@@ -351,156 +591,180 @@ void FGTrafficManager::Tokenize(const string& str,
         pos = str.find_first_of(delimiters, lastPos);
     }
 }
-*/
 
-void  FGTrafficManager::startXML () {
-  //cout << "Start XML" << endl;
-  requiredAircraft = "";
-  homePort         = "";
+
+void FGTrafficManager::startXML()
+{
+    //cout << "Start XML" << endl;
+    requiredAircraft = "";
+    homePort = "";
 }
 
-void  FGTrafficManager::endXML () {
-  //cout << "End XML" << endl;
+void FGTrafficManager::endXML()
+{
+    //cout << "End XML" << endl;
 }
 
-void  FGTrafficManager::startElement (const char * name, const XMLAttributes &atts) {
-  const char * attval;
-  //cout << "Start element " << name << endl;
-  //FGTrafficManager temp;
-  //for (int i = 0; i < atts.size(); i++)
-  //  if (string(atts.getName(i)) == string("include"))
-  attval = atts.getValue("include");
-  if (attval != 0)
-      {
-       //cout << "including " << attval << endl;
-       SGPath path = 
-         globals->get_fg_root();
-       path.append("/Traffic/");
-       path.append(attval);
-       readXML(path.str(), *this);
-      }
-  elementValueStack.push_back( "" );
-  //  cout << "  " << atts.getName(i) << '=' << atts.getValue(i) << endl; 
+void FGTrafficManager::startElement(const char *name,
+                                    const XMLAttributes & atts)
+{
+    const char *attval;
+    //cout << "Start element " << name << endl;
+    //FGTrafficManager temp;
+    //for (int i = 0; i < atts.size(); i++)
+    //  if (string(atts.getName(i)) == string("include"))
+    attval = atts.getValue("include");
+    if (attval != 0) {
+        //cout << "including " << attval << endl;
+        SGPath path = globals->get_fg_root();
+        path.append("/Traffic/");
+        path.append(attval);
+        readXML(path.str(), *this);
+    }
+    elementValueStack.push_back("");
+    //  cout << "  " << atts.getName(i) << '=' << atts.getValue(i) << endl; 
 }
 
-void  FGTrafficManager::endElement (const char * name) {
-  //cout << "End element " << name << endl;
-  const string& value = elementValueStack.back();
-
-  if (!strcmp(name, "model"))
-    mdl = value;
-  else if (!strcmp(name, "livery"))
-    livery = value;
-  else if (!strcmp(name, "home-port"))
-    homePort = value;
-  else if (!strcmp(name, "registration"))
-    registration = value;
-  else if (!strcmp(name, "airline"))
-    airline = value;
-  else if (!strcmp(name, "actype"))
-    acType = value;
-  else if (!strcmp(name, "required-aircraft"))
-    requiredAircraft = value;
-  else if (!strcmp(name, "flighttype"))
-    flighttype = value;
-  else if (!strcmp(name, "radius"))
-    radius = atoi(value.c_str());
-  else if (!strcmp(name, "offset"))
-    offset = atoi(value.c_str());
-  else if (!strcmp(name, "performance-class"))
-    m_class = value;
-  else if (!strcmp(name, "heavy"))
-    {
-      if(value == string("true"))
-       heavy = true;
-      else
-       heavy = false;
+void FGTrafficManager::endElement(const char *name)
+{
+    //cout << "End element " << name << endl;
+    const string & value = elementValueStack.back();
+
+    if (!strcmp(name, "model"))
+        mdl = value;
+    else if (!strcmp(name, "livery"))
+        livery = value;
+    else if (!strcmp(name, "home-port"))
+        homePort = value;
+    else if (!strcmp(name, "registration"))
+        registration = value;
+    else if (!strcmp(name, "airline"))
+        airline = value;
+    else if (!strcmp(name, "actype"))
+        acType = value;
+    else if (!strcmp(name, "required-aircraft"))
+        requiredAircraft = value;
+    else if (!strcmp(name, "flighttype"))
+        flighttype = value;
+    else if (!strcmp(name, "radius"))
+        radius = atoi(value.c_str());
+    else if (!strcmp(name, "offset"))
+        offset = atoi(value.c_str());
+    else if (!strcmp(name, "performance-class"))
+        m_class = value;
+    else if (!strcmp(name, "heavy")) {
+        if (value == string("true"))
+            heavy = true;
+        else
+            heavy = false;
+    } else if (!strcmp(name, "callsign"))
+        callsign = value;
+    else if (!strcmp(name, "fltrules"))
+        fltrules = value;
+    else if (!strcmp(name, "port"))
+        port = value;
+    else if (!strcmp(name, "time"))
+        timeString = value;
+    else if (!strcmp(name, "departure")) {
+        departurePort = port;
+        departureTime = timeString;
+    } else if (!strcmp(name, "cruise-alt"))
+        cruiseAlt = atoi(value.c_str());
+    else if (!strcmp(name, "arrival")) {
+        arrivalPort = port;
+        arrivalTime = timeString;
+    } else if (!strcmp(name, "repeat"))
+        repeat = value;
+    else if (!strcmp(name, "flight")) {
+        // We have loaded and parsed all the information belonging to this flight
+        // so we temporarily store it. 
+        //cerr << "Pusing back flight " << callsign << endl;
+        //cerr << callsign  <<  " " << fltrules     << " "<< departurePort << " " <<  arrivalPort << " "
+        //   << cruiseAlt <<  " " << departureTime<< " "<< arrivalTime   << " " << repeat << endl;
+
+        //Prioritize aircraft 
+        string apt = fgGetString("/sim/presets/airport-id");
+        //cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
+        //if (departurePort == apt) score++;
+        //flights.push_back(new FGScheduledFlight(callsign,
+        //                                fltrules,
+        //                                departurePort,
+        //                                arrivalPort,
+        //                                cruiseAlt,
+        //                                departureTime,
+        //                                arrivalTime,
+        //                                repeat));
+        if (requiredAircraft == "") {
+            char buffer[16];
+            snprintf(buffer, 16, "%d", acCounter);
+            requiredAircraft = buffer;
+        }
+        SG_LOG(SG_GENERAL, SG_DEBUG, "Adding flight: " << callsign << " "
+               << fltrules << " "
+               << departurePort << " "
+               << arrivalPort << " "
+               << cruiseAlt << " "
+               << departureTime << " "
+               << arrivalTime << " " << repeat << " " << requiredAircraft);
+        // For database maintainance purposes, it may be convenient to
+        // 
+        if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
+             SG_LOG(SG_GENERAL, SG_ALERT, "Traffic Dump FLIGHT," << callsign << ","
+                          << fltrules << ","
+                          << departurePort << ","
+                          << arrivalPort << ","
+                          << cruiseAlt << ","
+                          << departureTime << ","
+                          << arrivalTime << "," << repeat << "," << requiredAircraft);
+        }
+        flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
+                                                                  fltrules,
+                                                                  departurePort,
+                                                                  arrivalPort,
+                                                                  cruiseAlt,
+                                                                  departureTime,
+                                                                  arrivalTime,
+                                                                  repeat,
+                                                                  requiredAircraft));
+        requiredAircraft = "";
+    } else if (!strcmp(name, "aircraft")) {
+        endAircraft();
     }
-  else if (!strcmp(name, "callsign"))
-    callsign = value;
-  else if (!strcmp(name, "fltrules"))
-    fltrules = value;
-  else if (!strcmp(name, "port"))
-    port = value;
-  else if (!strcmp(name, "time"))
-    timeString = value;
-  else if (!strcmp(name, "departure"))
-    {
-      departurePort = port;
-      departureTime = timeString;
+    
+    elementValueStack.pop_back();
+}
+
+void FGTrafficManager::endAircraft()
+{
+    string isHeavy = heavy ? "true" : "false";
+
+    if (missingModels.find(mdl) != missingModels.end()) {
+    // don't stat() or warn again
+        requiredAircraft = homePort = "";
+        return;
     }
-  else if (!strcmp(name, "cruise-alt"))
-    cruiseAlt = atoi(value.c_str());
-  else if (!strcmp(name, "arrival"))
-    {
-      arrivalPort = port;
-      arrivalTime = timeString;
+    
+    if (!FGAISchedule::validModelPath(mdl)) {
+        missingModels.insert(mdl);
+        SG_LOG(SG_GENERAL, SG_WARN, "TrafficMgr: Missing model path:" << mdl);
+        requiredAircraft = homePort = "";
+        return;
     }
-  else if (!strcmp(name, "repeat"))
-    repeat = value;
-  else if (!strcmp(name, "flight"))
-    {
-      // We have loaded and parsed all the information belonging to this flight
-      // so we temporarily store it. 
-      //cerr << "Pusing back flight " << callsign << endl;
-      //cerr << callsign  <<  " " << fltrules     << " "<< departurePort << " " <<  arrivalPort << " "
-      //   << cruiseAlt <<  " " << departureTime<< " "<< arrivalTime   << " " << repeat << endl;
-
-      //Prioritize aircraft 
-      string apt = fgGetString("/sim/presets/airport-id");
-      //cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
-      //if (departurePort == apt) score++;
-      //flights.push_back(new FGScheduledFlight(callsign,
-       //                                fltrules,
-       //                                departurePort,
-       //                                arrivalPort,
-       //                                cruiseAlt,
-       //                                departureTime,
-       //                                arrivalTime,
-       //                                repeat));
-    if (requiredAircraft == "") {
-        char buffer[16];
-        snprintf(buffer, 16, "%d", acCounter);
-        requiredAircraft = buffer;
+        
+    int proportion =
+        (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
+    int randval = rand() & 100;
+    if (randval > proportion) {
+        requiredAircraft = homePort = "";
+        return;
     }
-    SG_LOG(SG_GENERAL, SG_DEBUG, "Adding flight: " << callsign       << " "
-                              << fltrules       << " "
-                              <<  departurePort << " "
-                              <<  arrivalPort   << " "
-                              <<  cruiseAlt     << " "
-                              <<  departureTime << " "
-                              <<  arrivalTime   << " "
-                              <<  repeat        << " " 
-                              <<  requiredAircraft);
-
-     flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
-                                                                 fltrules,
-                                                                 departurePort,
-                                                                 arrivalPort,
-                                                                 cruiseAlt,
-                                                                 departureTime,
-                                                                 arrivalTime,
-                                                                 repeat,
-                                                                 requiredAircraft));
-      requiredAircraft = "";
-  }
-  else if (!strcmp(name, "aircraft"))
-    {
-      int proportion = (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
-      int randval = rand() & 100;
-      if (randval < proportion) {
-          //scheduledAircraft.push_back(new FGAISchedule(mdl, 
-       //                                     livery, 
-       //                                     registration, 
-       //                                     heavy,
-       //                                     acType, 
-       //                                     airline, 
-       //                                     m_class, 
-       //                                     flighttype,
-       //                                     radius,
-       //                                     offset,
-       //                                     score,
-       //                                     flights));
+    
+    if (fgGetBool("/sim/traffic-manager/dumpdata") == true) {
+        SG_LOG(SG_GENERAL, SG_ALERT, "Traffic Dump AC," << homePort << "," << registration << "," << requiredAircraft 
+               << "," << acType << "," << livery << "," 
+               << airline << ","  << m_class << "," << offset << "," << radius << "," << flighttype << "," << isHeavy << "," << mdl);
+    }
+
     if (requiredAircraft == "") {
         char buffer[16];
         snprintf(buffer, 16, "%d", acCounter);
@@ -509,55 +773,45 @@ void  FGTrafficManager::endElement (const char * name) {
     if (homePort == "") {
         homePort = departurePort;
     }
-            scheduledAircraft.push_back(new FGAISchedule(mdl, 
-                                                         livery, 
-                                                         homePort,
-                                                         registration, 
-                                                         requiredAircraft,
-                                                         heavy,
-                                                         acType, 
-                                                         airline, 
-                                                         m_class, 
-                                                         flighttype,
-                                                         radius,
-                                                         offset));
-
-     //  while(flights.begin() != flights.end()) {
-//     flights.pop_back();
-//       }
-        }
+    
+    scheduledAircraft.push_back(new FGAISchedule(mdl,
+                                                 livery,
+                                                 homePort,
+                                                 registration,
+                                                 requiredAircraft,
+                                                 heavy,
+                                                 acType,
+                                                 airline,
+                                                 m_class,
+                                                 flighttype,
+                                                 radius, offset));
+            
     acCounter++;
     requiredAircraft = "";
     homePort = "";
-  //for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
-  //  {
-  //    delete (*flt);
-  //  }
-  //flights.clear();
-      SG_LOG( SG_GENERAL, SG_BULK, "Reading aircraft : " 
-             << registration 
-             << " with prioritization score " 
-             << score);
-      score = 0;
-    }
-  elementValueStack.pop_back();
+    score = 0;
 }
-
-void  FGTrafficManager::data (const char * s, int len) {
-  string token = string(s,len);
-  //cout << "Character data " << string(s,len) << endl;
-  elementValueStack.back() += token;
+    
+void FGTrafficManager::data(const char *s, int len)
+{
+    string token = string(s, len);
+    //cout << "Character data " << string(s,len) << endl;
+    elementValueStack.back() += token;
 }
 
-void  FGTrafficManager::pi (const char * target, const char * data) {
-  //cout << "Processing instruction " << target << ' ' << data << endl;
+void FGTrafficManager::pi(const char *target, const char *data)
+{
+    //cout << "Processing instruction " << target << ' ' << data << endl;
 }
 
-void  FGTrafficManager::warning (const char * message, int line, int column) {
-  SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
+void FGTrafficManager::warning(const char *message, int line, int column)
+{
+    SG_LOG(SG_IO, SG_WARN,
+           "Warning: " << message << " (" << line << ',' << column << ')');
 }
 
-void  FGTrafficManager::error (const char * message, int line, int column) {
-  SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
+void FGTrafficManager::error(const char *message, int line, int column)
+{
+    SG_LOG(SG_IO, SG_ALERT,
+           "Error: " << message << " (" << line << ',' << column << ')');
 }
-