]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_init.cxx
More search functions exposed to Nasal, also airport parking.
[flightgear.git] / src / Main / fg_init.cxx
1 // fg_init.cxx -- Flight Gear top level initialization routines
2 //
3 // Written by Curtis Olson, started August 1997.
4 //
5 // Copyright (C) 1997  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>             // strcmp()
31
32 #if defined( unix ) || defined( __CYGWIN__ )
33 #  include <unistd.h>           // for gethostname()
34 #endif
35 #ifdef _WIN32
36 #  include <direct.h>           // for getcwd()
37 #  define getcwd _getcwd
38 #  include <io.h>               // isatty()
39 #  define isatty _isatty
40 #  include "winsock2.h"         // for gethostname()
41 #endif
42
43 // work around a stdc++ lib bug in some versions of linux, but doesn't
44 // seem to hurt to have this here for all versions of Linux.
45 #ifdef linux
46 #  define _G_NO_EXTERN_TEMPLATES
47 #endif
48
49 #include <simgear/compiler.h>
50
51 #include <string>
52 #include <boost/algorithm/string/compare.hpp>
53 #include <boost/algorithm/string/predicate.hpp>
54
55 #include <simgear/constants.h>
56 #include <simgear/debug/logstream.hxx>
57 #include <simgear/structure/exception.hxx>
58 #include <simgear/structure/event_mgr.hxx>
59 #include <simgear/structure/SGPerfMon.hxx>
60 #include <simgear/misc/sg_path.hxx>
61 #include <simgear/misc/sg_dir.hxx>
62 #include <simgear/misc/sgstream.hxx>
63 #include <simgear/misc/strutils.hxx>
64 #include <simgear/props/props_io.hxx>
65
66 #include <simgear/misc/interpolator.hxx>
67 #include <simgear/scene/material/matlib.hxx>
68 #include <simgear/scene/model/particles.hxx>
69 #include <simgear/sound/soundmgr_openal.hxx>
70
71 #include <Aircraft/controls.hxx>
72 #include <Aircraft/replay.hxx>
73 #include <Airports/apt_loader.hxx>
74 #include <Airports/runways.hxx>
75 #include <Airports/simple.hxx>
76 #include <Airports/dynamics.hxx>
77
78 #include <AIModel/AIManager.hxx>
79
80 #include <ATCDCL/ATCmgr.hxx>
81 #include <ATC/atc_mgr.hxx>
82
83 #include <Autopilot/route_mgr.hxx>
84 #include <Autopilot/autopilotgroup.hxx>
85
86 #include <Cockpit/panel.hxx>
87 #include <Cockpit/panel_io.hxx>
88
89 #include <GUI/new_gui.hxx>
90 #include <Input/input.hxx>
91 #include <Instrumentation/instrument_mgr.hxx>
92 #include <Model/acmodel.hxx>
93 #include <Model/modelmgr.hxx>
94 #include <AIModel/submodel.hxx>
95 #include <AIModel/AIManager.hxx>
96 #include <Navaids/navdb.hxx>
97 #include <Navaids/navlist.hxx>
98 #include <Navaids/fix.hxx>
99 #include <Navaids/fixlist.hxx>
100 #include <Navaids/airways.hxx>
101 #include <Scenery/scenery.hxx>
102 #include <Scenery/tilemgr.hxx>
103 #include <Scripting/NasalSys.hxx>
104 #include <Sound/voice.hxx>
105 #include <Systems/system_mgr.hxx>
106 #include <Time/light.hxx>
107 #include <Traffic/TrafficMgr.hxx>
108 #include <MultiPlayer/multiplaymgr.hxx>
109 #include <FDM/fdm_shell.hxx>
110 #include <Environment/ephemeris.hxx>
111 #include <Environment/environment_mgr.hxx>
112
113 #include "fg_init.hxx"
114 #include "fg_io.hxx"
115 #include "fg_commands.hxx"
116 #include "fg_props.hxx"
117 #include "options.hxx"
118 #include "globals.hxx"
119 #include "logger.hxx"
120 #include "renderer.hxx"
121 #include "viewmgr.hxx"
122 #include "main.hxx"
123
124
125 using std::string;
126 using namespace boost::algorithm;
127
128
129 // Return the current base package version
130 string fgBasePackageVersion() {
131     SGPath base_path( globals->get_fg_root() );
132     base_path.append("version");
133
134     sg_gzifstream in( base_path.str() );
135     if ( !in.is_open() ) {
136         SGPath old_path( globals->get_fg_root() );
137         old_path.append( "Thanks" );
138         sg_gzifstream old( old_path.str() );
139         if ( !old.is_open() ) {
140             return "[none]";
141         } else {
142             return "[old version]";
143         }
144     }
145
146     string version;
147     in >> version;
148
149     return version;
150 }
151
152
153 template <class T>
154 bool fgFindAircraftInDir(const SGPath& dirPath, T* obj, bool (T::*pred)(const SGPath& p))
155 {
156   if (!dirPath.exists()) {
157     SG_LOG(SG_GENERAL, SG_WARN, "fgFindAircraftInDir: no such path:" << dirPath.str());
158     return false;
159   }
160     
161   bool recurse = true;
162   simgear::Dir dir(dirPath);
163   simgear::PathList setFiles(dir.children(simgear::Dir::TYPE_FILE, "-set.xml"));
164   simgear::PathList::iterator p;
165   for (p = setFiles.begin(); p != setFiles.end(); ++p) {
166     // check file name ends with -set.xml
167     
168     // if we found a -set.xml at this level, don't recurse any deeper
169     recurse = false;
170     
171     bool done = (obj->*pred)(*p);
172     if (done) {
173       return true;
174     }
175   } // of -set.xml iteration
176   
177   if (!recurse) {
178     return false;
179   }
180   
181   simgear::PathList subdirs(dir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT));
182   for (p = subdirs.begin(); p != subdirs.end(); ++p) {
183     if (p->file() == "CVS") {
184       continue;
185     }
186     
187     if (fgFindAircraftInDir(*p, obj, pred)) {
188       return true;
189     }
190   } // of subdirs iteration
191   
192   return false;
193 }
194
195 template <class T>
196 void fgFindAircraft(T* obj, bool (T::*pred)(const SGPath& p))
197 {
198   const string_list& paths(globals->get_aircraft_paths());
199   string_list::const_iterator it = paths.begin();
200   for (; it != paths.end(); ++it) {
201     bool done = fgFindAircraftInDir(SGPath(*it), obj, pred);
202     if (done) {
203       return;
204     }
205   } // of aircraft paths iteration
206   
207   // if we reach this point, search the default location (always last)
208   SGPath rootAircraft(globals->get_fg_root());
209   rootAircraft.append("Aircraft");
210   fgFindAircraftInDir(rootAircraft, obj, pred);
211 }
212
213 class FindAndCacheAircraft
214 {
215 public:
216   FindAndCacheAircraft(SGPropertyNode* autoSave)
217   {
218     _cache = autoSave->getNode("sim/startup/path-cache", true);
219   }
220   
221   bool loadAircraft()
222   {
223     std::string aircraft = fgGetString( "/sim/aircraft", "");
224     if (aircraft.empty()) {
225       SG_LOG(SG_GENERAL, SG_ALERT, "no aircraft specified");
226       return false;
227     }
228     
229     _searchAircraft = aircraft + "-set.xml";
230     std::string aircraftDir = fgGetString("/sim/aircraft-dir", "");
231     if (!aircraftDir.empty()) {
232       // aircraft-dir was set, skip any searching at all, if it's valid
233       simgear::Dir acPath(aircraftDir);
234       SGPath setFile = acPath.file(_searchAircraft);
235       if (setFile.exists()) {
236         SG_LOG(SG_GENERAL, SG_INFO, "found aircraft in dir: " << aircraftDir );
237         
238         try {
239           readProperties(setFile.str(), globals->get_props());
240         } catch ( const sg_exception &e ) {
241           SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
242           return false;
243         }
244         
245         return true;
246       } else {
247         SG_LOG(SG_GENERAL, SG_ALERT, "aircraft '" << _searchAircraft << 
248                "' not found in specified dir:" << aircraftDir);
249         return false;
250       }
251     }
252     
253     if (!checkCache()) {
254       // prepare cache for re-scan
255       SGPropertyNode *n = _cache->getNode("fg-root", true);
256       n->setStringValue(globals->get_fg_root().c_str());
257       n->setAttribute(SGPropertyNode::USERARCHIVE, true);
258       n = _cache->getNode("fg-aircraft", true);
259       n->setStringValue(getAircraftPaths().c_str());
260       n->setAttribute(SGPropertyNode::USERARCHIVE, true);
261       _cache->removeChildren("aircraft");
262   
263       fgFindAircraft(this, &FindAndCacheAircraft::checkAircraft);
264     }
265     
266     if (_foundPath.str().empty()) {
267       SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find specified aircraft: " << aircraft );
268       return false;
269     }
270     
271     SG_LOG(SG_GENERAL, SG_INFO, "Loading aircraft -set file from:" << _foundPath.str());
272     fgSetString( "/sim/aircraft-dir", _foundPath.dir().c_str());
273     if (!_foundPath.exists()) {
274       SG_LOG(SG_GENERAL, SG_ALERT, "Unable to find -set file:" << _foundPath.str());
275       return false;
276     }
277     
278     try {
279       readProperties(_foundPath.str(), globals->get_props());
280     } catch ( const sg_exception &e ) {
281       SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
282       return false;
283     }
284     
285     return true;
286   }
287   
288 private:
289   SGPath getAircraftPaths() {
290     string_list pathList = globals->get_aircraft_paths();
291     SGPath aircraftPaths;
292     string_list::const_iterator it = pathList.begin();
293     if (it != pathList.end()) {
294         aircraftPaths.set(*it);
295         it++;
296     }
297     for (; it != pathList.end(); ++it) {
298         aircraftPaths.add(*it);
299     }
300     return aircraftPaths;
301   }
302   
303   bool checkCache()
304   {
305     if (globals->get_fg_root() != _cache->getStringValue("fg-root", "")) {
306       return false; // cache mismatch
307     }
308
309     if (getAircraftPaths().str() != _cache->getStringValue("fg-aircraft", "")) {
310       return false; // cache mismatch
311     }
312     
313     vector<SGPropertyNode_ptr> cache = _cache->getChildren("aircraft");
314     for (unsigned int i = 0; i < cache.size(); i++) {
315       const char *name = cache[i]->getStringValue("file", "");
316       if (!boost::equals(_searchAircraft, name, is_iequal())) {
317         continue;
318       }
319       
320       SGPath xml(cache[i]->getStringValue("path", ""));
321       xml.append(name);
322       if (xml.exists()) {
323         _foundPath = xml;
324         return true;
325       } 
326       
327       return false;
328     } // of aircraft in cache iteration
329     
330     return false;
331   }
332   
333   bool checkAircraft(const SGPath& p)
334   {
335     // create cache node
336     int i = 0;
337     while (1) {
338         if (!_cache->getChild("aircraft", i++, false))
339             break;
340     }
341     
342     SGPropertyNode *n, *entry = _cache->getChild("aircraft", --i, true);
343
344     std::string fileName(p.file());
345     n = entry->getNode("file", true);
346     n->setStringValue(fileName);
347     n->setAttribute(SGPropertyNode::USERARCHIVE, true);
348
349     n = entry->getNode("path", true);
350     n->setStringValue(p.dir());
351     n->setAttribute(SGPropertyNode::USERARCHIVE, true);
352
353     if ( boost::equals(fileName, _searchAircraft.c_str(), is_iequal()) ) {
354         _foundPath = p;
355         return true;
356     }
357
358     return false;
359   }
360   
361   std::string _searchAircraft;
362   SGPath _foundPath;
363   SGPropertyNode* _cache;
364 };
365
366 #ifdef _WIN32
367 static SGPath platformDefaultDataPath()
368 {
369   char *envp = ::getenv( "APPDATA" );
370   SGPath config( envp );
371   config.append( "flightgear.org" );
372   return config;
373 }
374 #elif __APPLE__
375
376 #include <CoreServices/CoreServices.h>
377
378 static SGPath platformDefaultDataPath()
379 {
380   FSRef ref;
381   OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, false, &ref);
382   if (err) {
383     return SGPath();
384   }
385   
386   unsigned char path[1024];
387   if (FSRefMakePath(&ref, path, 1024) != noErr) {
388     return SGPath();
389   }
390   
391   SGPath appData;
392   appData.set((const char*) path);
393   appData.append("FlightGear");
394   return appData;
395 }
396 #else
397 static SGPath platformDefaultDataPath()
398 {
399   SGPath config( homedir );
400   config.append( ".fgfs" );
401   return config;
402 }
403 #endif
404
405 // Read in configuration (file and command line)
406 bool fgInitConfig ( int argc, char **argv )
407 {
408     SGPath dataPath = platformDefaultDataPath();
409     
410     const char *fg_home = getenv("FG_HOME");
411     if (fg_home)
412       dataPath = fg_home;
413     
414     simgear::Dir exportDir(simgear::Dir(dataPath).file("Export"));
415     if (!exportDir.exists()) {
416       exportDir.create(0777);
417     }
418     
419     // Set /sim/fg-home and don't allow malign code to override it until
420     // Nasal security is set up.  Use FG_HOME if necessary.
421     SGPropertyNode *home = fgGetNode("/sim", true);
422     home->removeChild("fg-home", 0, false);
423     home = home->getChild("fg-home", 0, true);
424     home->setStringValue(dataPath.c_str());
425     home->setAttribute(SGPropertyNode::WRITE, false);
426   
427     flightgear::Options::sharedInstance()->init(argc, argv, dataPath);
428   
429     // Read global preferences from $FG_ROOT/preferences.xml
430     SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
431     fgLoadProps("preferences.xml", globals->get_props());
432     SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
433
434     globals->loadUserSettings(dataPath);
435
436     // Scan user config files and command line for a specified aircraft.
437     flightgear::Options::sharedInstance()->initAircraft();
438
439     FindAndCacheAircraft f(globals->get_props());
440     if (!f.loadAircraft()) {
441       return false;
442     }
443
444     // parse options after loading aircraft to ensure any user
445     // overrides of defaults are honored.
446     flightgear::Options::sharedInstance()->processOptions();
447       
448     return true;
449 }
450
451 // Set current tower position lon/lat given an airport id
452 static bool fgSetTowerPosFromAirportID( const string& id) {
453     const FGAirport *a = fgFindAirportID( id);
454     if (a) {
455         SGGeod tower = a->getTowerLocation();
456         fgSetDouble("/sim/tower/longitude-deg",  tower.getLongitudeDeg());
457         fgSetDouble("/sim/tower/latitude-deg",  tower.getLatitudeDeg());
458         fgSetDouble("/sim/tower/altitude-ft", tower.getElevationFt());
459         return true;
460     } else {
461         return false;
462     }
463
464 }
465
466 struct FGTowerLocationListener : SGPropertyChangeListener {
467     void valueChanged(SGPropertyNode* node) {
468         string id(node->getStringValue());
469         if (fgGetBool("/sim/tower/auto-position",true))
470         {
471             // enforce using closest airport when auto-positioning is enabled 
472             const char* closest_airport = fgGetString("/sim/airport/closest-airport-id", "");
473             if (closest_airport && (id != closest_airport))
474             {
475                 id = closest_airport;
476                 node->setStringValue(id);
477             }
478         }
479         fgSetTowerPosFromAirportID(id);
480     }
481 };
482
483 struct FGClosestTowerLocationListener : SGPropertyChangeListener
484 {
485     void valueChanged(SGPropertyNode* )
486     {
487         // closest airport has changed
488         if (fgGetBool("/sim/tower/auto-position",true))
489         {
490             // update tower position
491             const char* id = fgGetString("/sim/airport/closest-airport-id", "");
492             if (id && *id!=0)
493                 fgSetString("/sim/tower/airport-id", id);
494         }
495     }
496 };
497
498 void fgInitTowerLocationListener() {
499     fgGetNode("/sim/tower/airport-id",  true)
500         ->addChangeListener( new FGTowerLocationListener(), true );
501     FGClosestTowerLocationListener* ntcl = new FGClosestTowerLocationListener();
502     fgGetNode("/sim/airport/closest-airport-id", true)
503         ->addChangeListener(ntcl , true );
504     fgGetNode("/sim/tower/auto-position", true)
505            ->addChangeListener(ntcl, true );
506 }
507
508 static void fgApplyStartOffset(const SGGeod& aStartPos, double aHeading, double aTargetHeading = HUGE_VAL)
509 {
510   SGGeod startPos(aStartPos);
511   if (aTargetHeading == HUGE_VAL) {
512     aTargetHeading = aHeading;
513   }
514   
515   if ( fabs( fgGetDouble("/sim/presets/offset-distance-nm") ) > SG_EPSILON ) {
516     double offsetDistance = fgGetDouble("/sim/presets/offset-distance-nm");
517     offsetDistance *= SG_NM_TO_METER;
518     double offsetAzimuth = aHeading;
519     if ( fabs(fgGetDouble("/sim/presets/offset-azimuth-deg")) > SG_EPSILON ) {
520       offsetAzimuth = fgGetDouble("/sim/presets/offset-azimuth-deg");
521       aHeading = aTargetHeading;
522     }
523
524     SGGeod offset;
525     double az2; // dummy
526     SGGeodesy::direct(startPos, offsetAzimuth + 180, offsetDistance, offset, az2);
527     startPos = offset;
528   }
529
530   // presets
531   fgSetDouble("/sim/presets/longitude-deg", startPos.getLongitudeDeg() );
532   fgSetDouble("/sim/presets/latitude-deg", startPos.getLatitudeDeg() );
533   fgSetDouble("/sim/presets/heading-deg", aHeading );
534
535   // other code depends on the actual values being set ...
536   fgSetDouble("/position/longitude-deg",  startPos.getLongitudeDeg() );
537   fgSetDouble("/position/latitude-deg",  startPos.getLatitudeDeg() );
538   fgSetDouble("/orientation/heading-deg", aHeading );
539 }
540
541 // Set current_options lon/lat given an airport id and heading (degrees)
542 bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
543     if ( id.empty() )
544         return false;
545
546     // set initial position from runway and heading
547     SG_LOG( SG_GENERAL, SG_INFO,
548             "Attempting to set starting position from airport code "
549             << id << " heading " << tgt_hdg );
550
551     const FGAirport* apt = fgFindAirportID(id);
552     if (!apt) return false;
553     FGRunway* r = apt->findBestRunwayForHeading(tgt_hdg);
554     fgSetString("/sim/atc/runway", r->ident().c_str());
555
556     SGGeod startPos = r->pointOnCenterline(fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
557           fgApplyStartOffset(startPos, r->headingDeg(), tgt_hdg);
558     return true;
559 }
560
561 // Set current_options lon/lat given an airport id and parkig position name
562 static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& parkpos ) {
563     if ( id.empty() )
564         return false;
565
566     // can't see an easy way around this const_cast at the moment
567     FGAirport* apt = const_cast<FGAirport*>(fgFindAirportID(id));
568     if (!apt) {
569         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport " << id );
570         return false;
571     }
572     FGAirportDynamics* dcs = apt->getDynamics();
573     if (!dcs) {
574         SG_LOG( SG_GENERAL, SG_ALERT,
575                 "Airport " << id << "does not appear to have parking information available");
576         return false;
577     }
578     
579     int park_index = dcs->getNrOfParkings() - 1;
580     bool succes;
581     double radius = fgGetDouble("/sim/dimensions/radius-m");
582     if ((parkpos == string("AVAILABLE")) && (radius > 0)) {
583         double lat, lon, heading;
584         string fltType;
585         string acOperator;
586         SGPath acData;
587         try {
588             acData = fgGetString("/sim/fg-home");
589             acData.append("aircraft-data");
590             string acfile = fgGetString("/sim/aircraft") + string(".xml");
591             acData.append(acfile);
592             SGPropertyNode root;
593             readProperties(acData.str(), &root);
594             SGPropertyNode * node = root.getNode("sim");
595             fltType    = node->getStringValue("aircraft-class", "NONE"     );
596             acOperator = node->getStringValue("aircraft-operator", "NONE"     );
597         } catch (const sg_exception &) {
598             SG_LOG(SG_GENERAL, SG_INFO,
599                 "Could not load aircraft aircrat type and operator information from: " << acData.str() << ". Using defaults");
600
601        // cout << path.str() << endl;
602         }
603         if (fltType.empty() || fltType == "NONE") {
604             SG_LOG(SG_GENERAL, SG_INFO,
605                 "Aircraft type information not found in: " << acData.str() << ". Using default value");
606                 fltType = fgGetString("/sim/aircraft-class"   );
607         }
608         if (acOperator.empty() || fltType == "NONE") {
609             SG_LOG(SG_GENERAL, SG_INFO,
610                 "Aircraft operator information not found in: " << acData.str() << ". Using default value");
611                 acOperator = fgGetString("/sim/aircraft-operator"   );
612         }
613
614         cerr << "Running aircraft " << fltType << " of livery " << acOperator << endl;
615         string acType; // Currently not used by findAvailable parking, so safe to leave empty. 
616         succes = dcs->getAvailableParking(&lat, &lon, &heading, &park_index, radius, fltType, acType, acOperator);
617         if (succes) {
618             fgGetString("/sim/presets/parkpos");
619             fgSetString("/sim/presets/parkpos", dcs->getParking(park_index)->getName());
620         } else {
621             SG_LOG( SG_GENERAL, SG_ALERT,
622                     "Failed to find a suitable parking at airport " << id );
623             return false;
624         }
625     } else {
626         //cerr << "We shouldn't get here when AVAILABLE" << endl;
627         while (park_index >= 0 && dcs->getParkingName(park_index) != parkpos) park_index--;
628         if (park_index < 0) {
629             SG_LOG( SG_GENERAL, SG_ALERT,
630                     "Failed to find parking position " << parkpos <<
631                     " at airport " << id );
632             return false;
633         }
634     }
635     FGParking* parking = dcs->getParking(park_index);
636     parking->setAvailable(false);
637     fgApplyStartOffset(
638       SGGeod::fromDeg(parking->getLongitude(), parking->getLatitude()),
639       parking->getHeading());
640     return true;
641 }
642
643
644 // Set current_options lon/lat given an airport id and runway number
645 static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy, bool rwy_req ) {
646     if ( id.empty() )
647         return false;
648
649     // set initial position from airport and runway number
650     SG_LOG( SG_GENERAL, SG_INFO,
651             "Attempting to set starting position for "
652             << id << ":" << rwy );
653
654     const FGAirport* apt = fgFindAirportID(id);
655     if (!apt) {
656       SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport:" << id);
657       return false;
658     }
659     
660     if (!apt->hasRunwayWithIdent(rwy)) {
661       SG_LOG( SG_GENERAL, rwy_req ? SG_ALERT : SG_INFO,
662                 "Failed to find runway " << rwy <<
663                 " at airport " << id << ". Using default runway." );
664       return false;
665     }
666     
667     FGRunway* r(apt->getRunwayByIdent(rwy));
668     fgSetString("/sim/atc/runway", r->ident().c_str());
669     SGGeod startPos = r->pointOnCenterline( fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
670           fgApplyStartOffset(startPos, r->headingDeg());
671     return true;
672 }
673
674
675 static void fgSetDistOrAltFromGlideSlope() {
676     // cout << "fgSetDistOrAltFromGlideSlope()" << endl;
677     string apt_id = fgGetString("/sim/presets/airport-id");
678     double gs = fgGetDouble("/sim/presets/glideslope-deg")
679         * SG_DEGREES_TO_RADIANS ;
680     double od = fgGetDouble("/sim/presets/offset-distance-nm");
681     double alt = fgGetDouble("/sim/presets/altitude-ft");
682
683     double apt_elev = 0.0;
684     if ( ! apt_id.empty() ) {
685         apt_elev = fgGetAirportElev( apt_id );
686         if ( apt_elev < -9990.0 ) {
687             apt_elev = 0.0;
688         }
689     } else {
690         apt_elev = 0.0;
691     }
692
693     if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) {
694         // set altitude from glideslope and offset-distance
695         od *= SG_NM_TO_METER * SG_METER_TO_FEET;
696         alt = fabs(od*tan(gs)) + apt_elev;
697         fgSetDouble("/sim/presets/altitude-ft", alt);
698         fgSetBool("/sim/presets/onground", false);
699         SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: "
700                 << alt  << " ft" );
701     } else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) {
702         // set offset-distance from glideslope and altitude
703         od  = (alt - apt_elev) / tan(gs);
704         od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM;
705         fgSetDouble("/sim/presets/offset-distance-nm", od);
706         fgSetBool("/sim/presets/onground", false);
707         SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: " 
708                 << od  << " nm" );
709     } else if( fabs(gs) > 0.01 ) {
710         SG_LOG( SG_GENERAL, SG_ALERT,
711                 "Glideslope given but not altitude or offset-distance." );
712         SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" );
713         fgSetDouble("/sim/presets/glideslope-deg", 0);
714         fgSetBool("/sim/presets/onground", true);
715     }
716 }
717
718
719 // Set current_options lon/lat given an airport id and heading (degrees)
720 static bool fgSetPosFromNAV( const string& id, const double& freq, FGPositioned::Type type ) {
721
722     const nav_list_type navlist
723         = globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq, type );
724
725     if (navlist.size() == 0 ) {
726         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
727             << id << ":" << freq );
728         return false;
729     }
730
731     if( navlist.size() > 1 ) {
732         ostringstream buf;
733         buf << "Ambigous NAV-ID: '" << id << "'. Specify id and frequency. Available stations:" << endl;
734         for( nav_list_type::const_iterator it = navlist.begin(); it != navlist.end(); ++it ) {
735             // NDB stored in kHz, VOR stored in MHz * 100 :-P
736             double factor = (*it)->type() == FGPositioned::NDB ? 1.0 : 1/100.0;
737             string unit = (*it)->type() == FGPositioned::NDB ? "kHz" : "MHz";
738             buf << (*it)->ident() << " "
739                 << setprecision(5) << (double)((*it)->get_freq() * factor) << " "
740                 << (*it)->get_lat() << "/" << (*it)->get_lon()
741                 << endl;
742         }
743
744         SG_LOG( SG_GENERAL, SG_ALERT, buf.str() );
745         return false;
746     }
747
748     FGNavRecord *nav = navlist[0];
749     fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg"));
750     return true;
751 }
752
753 // Set current_options lon/lat given an aircraft carrier id
754 static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) {
755
756     // set initial position from runway and heading
757     SGGeod geodPos;
758     double heading;
759     SGVec3d uvw;
760     if (FGAIManager::getStartPosition(carrier, posid, geodPos, heading, uvw)) {
761         double lon = geodPos.getLongitudeDeg();
762         double lat = geodPos.getLatitudeDeg();
763         double alt = geodPos.getElevationFt();
764
765         SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
766                 << carrier << " at lat = " << lat << ", lon = " << lon
767                 << ", alt = " << alt << ", heading = " << heading);
768
769         fgSetDouble("/sim/presets/longitude-deg",  lon);
770         fgSetDouble("/sim/presets/latitude-deg",  lat);
771         fgSetDouble("/sim/presets/altitude-ft", alt);
772         fgSetDouble("/sim/presets/heading-deg", heading);
773         fgSetDouble("/position/longitude-deg",  lon);
774         fgSetDouble("/position/latitude-deg",  lat);
775         fgSetDouble("/position/altitude-ft", alt);
776         fgSetDouble("/orientation/heading-deg", heading);
777
778         fgSetString("/sim/presets/speed-set", "UVW");
779         fgSetDouble("/velocities/uBody-fps", uvw(0));
780         fgSetDouble("/velocities/vBody-fps", uvw(1));
781         fgSetDouble("/velocities/wBody-fps", uvw(2));
782         fgSetDouble("/sim/presets/uBody-fps", uvw(0));
783         fgSetDouble("/sim/presets/vBody-fps", uvw(1));
784         fgSetDouble("/sim/presets/wBody-fps", uvw(2));
785
786         fgSetBool("/sim/presets/onground", true);
787
788         return true;
789     } else {
790         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = "
791                 << carrier );
792         return false;
793     }
794 }
795  
796 // Set current_options lon/lat given an airport id and heading (degrees)
797 static bool fgSetPosFromFix( const string& id )
798 {
799   FGPositioned::TypeFilter fixFilter(FGPositioned::FIX);
800   FGPositioned* fix = FGPositioned::findNextWithPartialId(NULL, id, &fixFilter);
801   if (!fix) {
802     SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate fix = " << id );
803     return false;
804   }
805   
806   fgApplyStartOffset(fix->geod(), fgGetDouble("/sim/presets/heading-deg"));
807   return true;
808 }
809
810 /**
811  * Initialize vor/ndb/ils/fix list management and query systems (as
812  * well as simple airport db list)
813  */
814 bool
815 fgInitNav ()
816 {
817     SG_LOG(SG_GENERAL, SG_INFO, "Loading Airport Database ...");
818
819     SGPath aptdb( globals->get_fg_root() );
820     aptdb.append( "Airports/apt.dat" );
821
822     SGPath p_metar( globals->get_fg_root() );
823     p_metar.append( "Airports/metar.dat" );
824
825     fgAirportDBLoad( aptdb.str(), p_metar.str() );
826     FGAirport::installPropertyListener();
827     
828     FGNavList *navlist = new FGNavList;
829     FGNavList *loclist = new FGNavList;
830     FGNavList *gslist = new FGNavList;
831     FGNavList *dmelist = new FGNavList;
832     FGNavList *tacanlist = new FGNavList;
833     FGNavList *carrierlist = new FGNavList;
834     FGTACANList *channellist = new FGTACANList;
835
836     globals->set_navlist( navlist );
837     globals->set_loclist( loclist );
838     globals->set_gslist( gslist );
839     globals->set_dmelist( dmelist );
840     globals->set_tacanlist( tacanlist );
841     globals->set_carrierlist( carrierlist );
842     globals->set_channellist( channellist );
843
844     if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, tacanlist, carrierlist, channellist) ) {
845         SG_LOG( SG_GENERAL, SG_ALERT,
846                 "Problems loading one or more navigational database" );
847     }
848     
849     SG_LOG(SG_GENERAL, SG_INFO, "  Fixes");
850     SGPath p_fix( globals->get_fg_root() );
851     p_fix.append( "Navaids/fix.dat" );
852     FGFixList fixlist;
853     fixlist.init( p_fix );  // adds fixes to the DB in positioned.cxx
854
855     SG_LOG(SG_GENERAL, SG_INFO, "  Airways");
856     flightgear::Airway::load();
857     
858     return true;
859 }
860
861
862 // Set the initial position based on presets (or defaults)
863 bool fgInitPosition() {
864     // cout << "fgInitPosition()" << endl;
865     double gs = fgGetDouble("/sim/presets/glideslope-deg")
866         * SG_DEGREES_TO_RADIANS ;
867     double od = fgGetDouble("/sim/presets/offset-distance-nm");
868     double alt = fgGetDouble("/sim/presets/altitude-ft");
869
870     bool set_pos = false;
871
872     // If glideslope is specified, then calculate offset-distance or
873     // altitude relative to glide slope if either of those was not
874     // specified.
875     if ( fabs( gs ) > 0.01 ) {
876         fgSetDistOrAltFromGlideSlope();
877     }
878
879
880     // If we have an explicit, in-range lon/lat, don't change it, just use it.
881     // If not, check for an airport-id and use that.
882     // If not, default to the middle of the KSFO field.
883     // The default values for lon/lat are deliberately out of range
884     // so that the airport-id can take effect; valid lon/lat will
885     // override airport-id, however.
886     double lon_deg = fgGetDouble("/sim/presets/longitude-deg");
887     double lat_deg = fgGetDouble("/sim/presets/latitude-deg");
888     if ( lon_deg >= -180.0 && lon_deg <= 180.0
889          && lat_deg >= -90.0 && lat_deg <= 90.0 )
890     {
891         set_pos = true;
892     }
893
894     string apt = fgGetString("/sim/presets/airport-id");
895     string rwy_no = fgGetString("/sim/presets/runway");
896     bool rwy_req = fgGetBool("/sim/presets/runway-requested");
897     string vor = fgGetString("/sim/presets/vor-id");
898     double vor_freq = fgGetDouble("/sim/presets/vor-freq");
899     string ndb = fgGetString("/sim/presets/ndb-id");
900     double ndb_freq = fgGetDouble("/sim/presets/ndb-freq");
901     string carrier = fgGetString("/sim/presets/carrier");
902     string parkpos = fgGetString("/sim/presets/parkpos");
903     string fix = fgGetString("/sim/presets/fix");
904     SGPropertyNode *hdg_preset = fgGetNode("/sim/presets/heading-deg", true);
905     double hdg = hdg_preset->getDoubleValue();
906
907     // save some start parameters, so that we can later say what the
908     // user really requested. TODO generalize that and move it to options.cxx
909     static bool start_options_saved = false;
910     if (!start_options_saved) {
911         start_options_saved = true;
912         SGPropertyNode *opt = fgGetNode("/sim/startup/options", true);
913
914         opt->setDoubleValue("latitude-deg", lat_deg);
915         opt->setDoubleValue("longitude-deg", lon_deg);
916         opt->setDoubleValue("heading-deg", hdg);
917         opt->setStringValue("airport", apt.c_str());
918         opt->setStringValue("runway", rwy_no.c_str());
919     }
920
921     if (hdg > 9990.0)
922         hdg = fgGetDouble("/environment/config/boundary/entry/wind-from-heading-deg", 270);
923
924     if ( !set_pos && !apt.empty() && !parkpos.empty() ) {
925         // An airport + parking position is requested
926         if ( fgSetPosFromAirportIDandParkpos( apt, parkpos ) ) {
927             // set tower position
928             fgSetString("/sim/airport/closest-airport-id",  apt.c_str());
929             fgSetString("/sim/tower/airport-id",  apt.c_str());
930             set_pos = true;
931         }
932     }
933
934     if ( !set_pos && !apt.empty() && !rwy_no.empty() ) {
935         // An airport + runway is requested
936         if ( fgSetPosFromAirportIDandRwy( apt, rwy_no, rwy_req ) ) {
937             // set tower position (a little off the heading for single
938             // runway airports)
939             fgSetString("/sim/airport/closest-airport-id",  apt.c_str());
940             fgSetString("/sim/tower/airport-id",  apt.c_str());
941             set_pos = true;
942         }
943     }
944
945     if ( !set_pos && !apt.empty() ) {
946         // An airport is requested (find runway closest to hdg)
947         if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) {
948             // set tower position (a little off the heading for single
949             // runway airports)
950             fgSetString("/sim/airport/closest-airport-id",  apt.c_str());
951             fgSetString("/sim/tower/airport-id",  apt.c_str());
952             set_pos = true;
953         }
954     }
955
956     if (hdg_preset->getDoubleValue() > 9990.0)
957         hdg_preset->setDoubleValue(hdg);
958
959     if ( !set_pos && !vor.empty() ) {
960         // a VOR is requested
961         if ( fgSetPosFromNAV( vor, vor_freq, FGPositioned::VOR ) ) {
962             set_pos = true;
963         }
964     }
965
966     if ( !set_pos && !ndb.empty() ) {
967         // an NDB is requested
968         if ( fgSetPosFromNAV( ndb, ndb_freq, FGPositioned::NDB ) ) {
969             set_pos = true;
970         }
971     }
972
973     if ( !set_pos && !carrier.empty() ) {
974         // an aircraft carrier is requested
975         if ( fgSetPosFromCarrier( carrier, parkpos ) ) {
976             set_pos = true;
977         }
978     }
979
980     if ( !set_pos && !fix.empty() ) {
981         // a Fix is requested
982         if ( fgSetPosFromFix( fix ) ) {
983             set_pos = true;
984         }
985     }
986
987     if ( !set_pos ) {
988         // No lon/lat specified, no airport specified, default to
989         // middle of KSFO field.
990         fgSetDouble("/sim/presets/longitude-deg", -122.374843);
991         fgSetDouble("/sim/presets/latitude-deg", 37.619002);
992     }
993
994     fgSetDouble( "/position/longitude-deg",
995                  fgGetDouble("/sim/presets/longitude-deg") );
996     fgSetDouble( "/position/latitude-deg",
997                  fgGetDouble("/sim/presets/latitude-deg") );
998     fgSetDouble( "/orientation/heading-deg", hdg_preset->getDoubleValue());
999
1000     // determine if this should be an on-ground or in-air start
1001     if ((fabs(gs) > 0.01 || fabs(od) > 0.1 || alt > 0.1) && carrier.empty()) {
1002         fgSetBool("/sim/presets/onground", false);
1003     } else {
1004         fgSetBool("/sim/presets/onground", true);
1005     }
1006
1007     return true;
1008 }
1009
1010
1011 // General house keeping initializations
1012 bool fgInitGeneral() {
1013     string root;
1014
1015     SG_LOG( SG_GENERAL, SG_INFO, "General Initialization" );
1016     SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" );
1017
1018     root = globals->get_fg_root();
1019     if ( ! root.length() ) {
1020         // No root path set? Then bail ...
1021         SG_LOG( SG_GENERAL, SG_ALERT,
1022                 "Cannot continue without a path to the base package "
1023                 << "being defined." );
1024         exit(-1);
1025     }
1026     SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl );
1027
1028     globals->set_browser(fgGetString("/sim/startup/browser-app", "firefox %u"));
1029
1030     char buf[512], *cwd = getcwd(buf, 511);
1031     buf[511] = '\0';
1032     SGPropertyNode *curr = fgGetNode("/sim", true);
1033     curr->removeChild("fg-current", 0, false);
1034     curr = curr->getChild("fg-current", 0, true);
1035     curr->setStringValue(cwd ? cwd : "");
1036     curr->setAttribute(SGPropertyNode::WRITE, false);
1037
1038     fgSetBool("/sim/startup/stdout-to-terminal", isatty(1) != 0 );
1039     fgSetBool("/sim/startup/stderr-to-terminal", isatty(2) != 0 );
1040     return true;
1041 }
1042
1043 // This is the top level init routine which calls all the other
1044 // initialization routines.  If you are adding a subsystem to flight
1045 // gear, its initialization call should located in this routine.
1046 // Returns non-zero if a problem encountered.
1047 bool fgInitSubsystems() {
1048
1049     SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems");
1050     SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
1051
1052     ////////////////////////////////////////////////////////////////////
1053     // Initialize the sound subsystem.
1054     ////////////////////////////////////////////////////////////////////
1055     // Sound manager uses an own subsystem group "SOUND" which is the last
1056     // to be updated in every loop.
1057     // Sound manager is updated last so it can use the CPU while the GPU
1058     // is processing the scenery (doubled the frame-rate for me) -EMH-
1059     globals->add_subsystem("sound", new SGSoundMgr, SGSubsystemMgr::SOUND);
1060
1061     ////////////////////////////////////////////////////////////////////
1062     // Initialize the event manager subsystem.
1063     ////////////////////////////////////////////////////////////////////
1064
1065     globals->get_event_mgr()->init();
1066     globals->get_event_mgr()->setRealtimeProperty(fgGetNode("/sim/time/delta-realtime-sec", true));
1067
1068     ////////////////////////////////////////////////////////////////////
1069     // Initialize the property interpolator subsystem. Put into the INIT
1070     // group because the "nasal" subsystem may need it at GENERAL take-down.
1071     ////////////////////////////////////////////////////////////////////
1072     globals->add_subsystem("interpolator", new SGInterpolator, SGSubsystemMgr::INIT);
1073
1074
1075     ////////////////////////////////////////////////////////////////////
1076     // Add the FlightGear property utilities.
1077     ////////////////////////////////////////////////////////////////////
1078     globals->add_subsystem("properties", new FGProperties);
1079
1080
1081     ////////////////////////////////////////////////////////////////////
1082     // Add the performance monitoring system.
1083     ////////////////////////////////////////////////////////////////////
1084     globals->add_subsystem("performance-mon",
1085             new SGPerformanceMonitor(globals->get_subsystem_mgr(),
1086                                      fgGetNode("/sim/performance-monitor", true)));
1087
1088     ////////////////////////////////////////////////////////////////////
1089     // Initialize the material property subsystem.
1090     ////////////////////////////////////////////////////////////////////
1091
1092     SGPath mpath( globals->get_fg_root() );
1093     mpath.append( fgGetString("/sim/rendering/materials-file") );
1094     if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
1095             globals->get_props()) ) {
1096         SG_LOG( SG_GENERAL, SG_ALERT,
1097                 "Error loading materials file " << mpath.str() );
1098         exit(-1);
1099     }
1100
1101
1102     ////////////////////////////////////////////////////////////////////
1103     // Initialize the scenery management subsystem.
1104     ////////////////////////////////////////////////////////////////////
1105
1106     globals->get_scenery()->get_scene_graph()
1107         ->addChild(simgear::Particles::getCommonRoot());
1108     simgear::GlobalParticleCallback::setSwitch(fgGetNode("/sim/rendering/particles", true));
1109
1110     ////////////////////////////////////////////////////////////////////
1111     // Initialize the flight model subsystem.
1112     ////////////////////////////////////////////////////////////////////
1113
1114     globals->add_subsystem("flight", new FDMShell, SGSubsystemMgr::FDM);
1115
1116     ////////////////////////////////////////////////////////////////////
1117     // Initialize the weather subsystem.
1118     ////////////////////////////////////////////////////////////////////
1119
1120     // Initialize the weather modeling subsystem
1121     globals->add_subsystem("environment", new FGEnvironmentMgr);
1122     globals->add_subsystem("ephemeris", new Ephemeris);
1123     
1124     ////////////////////////////////////////////////////////////////////
1125     // Initialize the aircraft systems and instrumentation (before the
1126     // autopilot.)
1127     ////////////////////////////////////////////////////////////////////
1128
1129     globals->add_subsystem("instrumentation", new FGInstrumentMgr, SGSubsystemMgr::FDM);
1130     globals->add_subsystem("systems", new FGSystemMgr, SGSubsystemMgr::FDM);
1131
1132     ////////////////////////////////////////////////////////////////////
1133     // Initialize the XML Autopilot subsystem.
1134     ////////////////////////////////////////////////////////////////////
1135
1136     globals->add_subsystem( "xml-autopilot", FGXMLAutopilotGroup::createInstance("autopilot"), SGSubsystemMgr::FDM );
1137     globals->add_subsystem( "xml-proprules", FGXMLAutopilotGroup::createInstance("property-rule"), SGSubsystemMgr::GENERAL );
1138     globals->add_subsystem( "route-manager", new FGRouteMgr );
1139
1140     ////////////////////////////////////////////////////////////////////
1141     // Initialize the Input-Output subsystem
1142     ////////////////////////////////////////////////////////////////////
1143     globals->add_subsystem( "io", new FGIO );
1144
1145     ////////////////////////////////////////////////////////////////////
1146     // Create and register the logger.
1147     ////////////////////////////////////////////////////////////////////
1148     
1149     globals->add_subsystem("logger", new FGLogger);
1150
1151     ////////////////////////////////////////////////////////////////////
1152     // Create and register the XML GUI.
1153     ////////////////////////////////////////////////////////////////////
1154
1155     globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT);
1156
1157     //////////////////////////////////////////////////////////////////////
1158     // Initialize the 2D cloud subsystem.
1159     ////////////////////////////////////////////////////////////////////
1160     fgGetBool("/sim/rendering/bump-mapping", false);
1161
1162
1163
1164     ////////////////////////////////////////////////////////////////////
1165     // Initialise the ATC Manager
1166     // Note that this is old stuff, but might be necessesary for the 
1167     // current ATIS implementation. Therefore, leave it in here
1168     // until the ATIS system is ported over to make use of the ATIS 
1169     // sub system infrastructure.
1170     ////////////////////////////////////////////////////////////////////
1171
1172     globals->add_subsystem("ATC-old", new FGATCMgr, SGSubsystemMgr::INIT);
1173
1174     ////////////////////////////////////////////////////////////////////
1175    // Initialize the ATC subsystem
1176     ////////////////////////////////////////////////////////////////////
1177     globals->add_subsystem("ATC", new FGATCManager, SGSubsystemMgr::POST_FDM);
1178     ////////////////////////////////////////////////////////////////////
1179     // Initialise the ATIS Subsystem
1180     ////////////////////////////////////////////////////////////////////
1181     //globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM);
1182
1183
1184     ////////////////////////////////////////////////////////////////////
1185     // Initialize multiplayer subsystem
1186     ////////////////////////////////////////////////////////////////////
1187
1188     globals->add_subsystem("mp", new FGMultiplayMgr, SGSubsystemMgr::POST_FDM);
1189
1190     ////////////////////////////////////////////////////////////////////
1191     // Initialise the AI Model Manager
1192     ////////////////////////////////////////////////////////////////////
1193     SG_LOG(SG_GENERAL, SG_INFO, "  AI Model Manager");
1194     globals->add_subsystem("ai-model", new FGAIManager, SGSubsystemMgr::POST_FDM);
1195     globals->add_subsystem("submodel-mgr", new FGSubmodelMgr, SGSubsystemMgr::POST_FDM);
1196
1197
1198     // It's probably a good idea to initialize the top level traffic manager
1199     // After the AI and ATC systems have been initialized properly.
1200     // AI Traffic manager
1201     globals->add_subsystem("traffic-manager", new FGTrafficManager, SGSubsystemMgr::POST_FDM);
1202
1203     ////////////////////////////////////////////////////////////////////
1204     // Add a new 2D panel.
1205     ////////////////////////////////////////////////////////////////////
1206
1207     string panel_path(fgGetString("/sim/panel/path"));
1208     if (!panel_path.empty()) {
1209       FGPanel* p = fgReadPanel(panel_path);
1210       if (p) {
1211         globals->set_current_panel(p);
1212         p->init();
1213         p->bind();
1214         SG_LOG( SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path );
1215       } else {
1216         SG_LOG( SG_INPUT, SG_ALERT,
1217                 "Error reading new panel from " << panel_path );
1218       }
1219     }
1220
1221     ////////////////////////////////////////////////////////////////////
1222     // Initialize the controls subsystem.
1223     ////////////////////////////////////////////////////////////////////
1224
1225     globals->get_controls()->init();
1226     globals->get_controls()->bind();
1227
1228
1229     ////////////////////////////////////////////////////////////////////
1230     // Initialize the input subsystem.
1231     ////////////////////////////////////////////////////////////////////
1232
1233     globals->add_subsystem("input", new FGInput);
1234
1235
1236     ////////////////////////////////////////////////////////////////////
1237     // Initialize the replay subsystem
1238     ////////////////////////////////////////////////////////////////////
1239     globals->add_subsystem("replay", new FGReplay);
1240
1241 #ifdef ENABLE_AUDIO_SUPPORT
1242     ////////////////////////////////////////////////////////////////////
1243     // Initialize the sound-effects subsystem.
1244     ////////////////////////////////////////////////////////////////////
1245     globals->add_subsystem("voice", new FGVoiceMgr, SGSubsystemMgr::DISPLAY);
1246 #endif
1247
1248     ////////////////////////////////////////////////////////////////////
1249     // Initialize the lighting subsystem.
1250     ////////////////////////////////////////////////////////////////////
1251
1252     globals->add_subsystem("lighting", new FGLight, SGSubsystemMgr::DISPLAY);
1253     
1254     // ordering here is important : Nasal (via events), then models, then views
1255     globals->add_subsystem("events", globals->get_event_mgr(), SGSubsystemMgr::DISPLAY);
1256     
1257     FGAircraftModel* acm = new FGAircraftModel;
1258     globals->set_aircraft_model(acm);
1259     globals->add_subsystem("aircraft-model", acm, SGSubsystemMgr::DISPLAY);
1260
1261     FGModelMgr* mm = new FGModelMgr;
1262     globals->set_model_mgr(mm);
1263     globals->add_subsystem("model-manager", mm, SGSubsystemMgr::DISPLAY);
1264
1265     FGViewMgr *viewmgr = new FGViewMgr;
1266     globals->set_viewmgr( viewmgr );
1267     globals->add_subsystem("view-manager", viewmgr, SGSubsystemMgr::DISPLAY);
1268
1269     globals->add_subsystem("tile-manager", globals->get_tile_mgr(), 
1270       SGSubsystemMgr::DISPLAY);
1271       
1272     ////////////////////////////////////////////////////////////////////
1273     // Bind and initialize subsystems.
1274     ////////////////////////////////////////////////////////////////////
1275
1276     globals->get_subsystem_mgr()->bind();
1277     globals->get_subsystem_mgr()->init();
1278
1279     ////////////////////////////////////////////////////////////////////////
1280     // Initialize the Nasal interpreter.
1281     // Do this last, so that the loaded scripts see initialized state
1282     ////////////////////////////////////////////////////////////////////////
1283     FGNasalSys* nasal = new FGNasalSys();
1284     globals->add_subsystem("nasal", nasal, SGSubsystemMgr::INIT);
1285     nasal->init();
1286
1287     // initialize methods that depend on other subsystems.
1288     globals->get_subsystem_mgr()->postinit();
1289
1290     ////////////////////////////////////////////////////////////////////////
1291     // End of subsystem initialization.
1292     ////////////////////////////////////////////////////////////////////
1293
1294     fgSetBool("/sim/crashed", false);
1295     fgSetBool("/sim/initialized", true);
1296
1297     SG_LOG( SG_GENERAL, SG_INFO, endl);
1298
1299                                 // Save the initial state for future
1300                                 // reference.
1301     globals->saveInitialState();
1302     
1303     return true;
1304 }
1305
1306 // Reset: this is what the 'reset' command (and hence, GUI) is attached to
1307 void fgReInitSubsystems()
1308 {
1309     static const SGPropertyNode *master_freeze
1310         = fgGetNode("/sim/freeze/master");
1311
1312     SG_LOG( SG_GENERAL, SG_INFO, "fgReInitSubsystems()");
1313
1314 // setup state to begin re-init
1315     bool freeze = master_freeze->getBoolValue();
1316     if ( !freeze ) {
1317         fgSetBool("/sim/freeze/master", true);
1318     }
1319     
1320     fgSetBool("/sim/signals/reinit", true);
1321     fgSetBool("/sim/crashed", false);
1322
1323 // do actual re-init steps
1324     globals->get_subsystem("flight")->unbind();
1325     
1326   // reset control state, before restoring initial state; -set or config files
1327   // may specify values for flaps, trim tabs, magnetos, etc
1328     globals->get_controls()->reset_all();
1329         
1330     globals->restoreInitialState();
1331
1332     // update our position based on current presets
1333     fgInitPosition();
1334     
1335     // Force reupdating the positions of the ai 3d models. They are used for
1336     // initializing ground level for the FDM.
1337     globals->get_subsystem("ai-model")->reinit();
1338
1339     // Initialize the FDM
1340     globals->get_subsystem("flight")->reinit();
1341
1342     // reset replay buffers
1343     globals->get_subsystem("replay")->reinit();
1344     
1345     // reload offsets from config defaults
1346     globals->get_viewmgr()->reinit();
1347
1348     globals->get_subsystem("time")->reinit();
1349
1350     // need to bind FDMshell again, since we manually unbound it above...
1351     globals->get_subsystem("flight")->bind();
1352
1353 // setup state to end re-init
1354     fgSetBool("/sim/signals/reinit", false);
1355     if ( !freeze ) {
1356         fgSetBool("/sim/freeze/master", false);
1357     }
1358     fgSetBool("/sim/sceneryloaded",false);
1359 }
1360
1361
1362 ///////////////////////////////////////////////////////////////////////////////
1363 // helper object to implement the --show-aircraft command.
1364 // resides here so we can share the fgFindAircraftInDir template above,
1365 // and hence ensure this command lists exectly the same aircraft as the normal
1366 // loading path.
1367 class ShowAircraft 
1368 {
1369 public:
1370   ShowAircraft()
1371   {
1372     _minStatus = getNumMaturity(fgGetString("/sim/aircraft-min-status", "all"));
1373   }
1374   
1375   
1376   void show(const SGPath& path)
1377   {
1378     fgFindAircraftInDir(path, this, &ShowAircraft::processAircraft);
1379   
1380     std::sort(_aircraft.begin(), _aircraft.end(), ciLessLibC());
1381     SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on Windows
1382     cout << "Available aircraft:" << endl;
1383     for ( unsigned int i = 0; i < _aircraft.size(); i++ ) {
1384         cout << _aircraft[i] << endl;
1385     }
1386   }
1387   
1388 private:
1389   bool processAircraft(const SGPath& path)
1390   {
1391     SGPropertyNode root;
1392     try {
1393        readProperties(path.str(), &root);
1394     } catch (sg_exception& ) {
1395        return false;
1396     }
1397   
1398     int maturity = 0;
1399     string descStr("   ");
1400     descStr += path.file();
1401   // trim common suffix from file names
1402     int nPos = descStr.rfind("-set.xml");
1403     if (nPos == (int)(descStr.size() - 8)) {
1404       descStr.resize(nPos);
1405     }
1406     
1407     SGPropertyNode *node = root.getNode("sim");
1408     if (node) {
1409       SGPropertyNode* desc = node->getNode("description");
1410       // if a status tag is found, read it in
1411       if (node->hasValue("status")) {
1412         maturity = getNumMaturity(node->getStringValue("status"));
1413       }
1414       
1415       if (desc) {
1416         if (descStr.size() <= 27+3) {
1417           descStr.append(29+3-descStr.size(), ' ');
1418         } else {
1419           descStr += '\n';
1420           descStr.append( 32, ' ');
1421         }
1422         descStr += desc->getStringValue();
1423       }
1424     } // of have 'sim' node
1425     
1426     if (maturity < _minStatus) {
1427       return false;
1428     }
1429
1430     _aircraft.push_back(descStr);
1431     return false;
1432   }
1433
1434
1435   int getNumMaturity(const char * str) 
1436   {
1437     // changes should also be reflected in $FG_ROOT/data/options.xml & 
1438     // $FG_ROOT/data/Translations/string-default.xml
1439     const char* levels[] = {"alpha","beta","early-production","production"}; 
1440
1441     if (!strcmp(str, "all")) {
1442       return 0;
1443     }
1444
1445     for (size_t i=0; i<(sizeof(levels)/sizeof(levels[0]));i++) 
1446       if (strcmp(str,levels[i])==0)
1447         return i;
1448
1449     return 0;
1450   }
1451
1452   // recommended in Meyers, Effective STL when internationalization and embedded
1453   // NULLs aren't an issue.  Much faster than the STL or Boost lex versions.
1454   struct ciLessLibC : public std::binary_function<string, string, bool>
1455   {
1456     bool operator()(const std::string &lhs, const std::string &rhs) const
1457     {
1458       return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ? 1 : 0;
1459     }
1460   };
1461
1462   int _minStatus;
1463   string_list _aircraft;
1464 };
1465
1466 void fgShowAircraft(const SGPath &path)
1467 {
1468     ShowAircraft s;
1469     s.show(path);
1470         
1471 #ifdef _MSC_VER
1472     cout << "Hit a key to continue..." << endl;
1473     cin.get();
1474 #endif
1475 }
1476
1477