diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx
index f838d17..9f9f65e 100644
--- a/src/Airports/simple.cxx
+++ b/src/Airports/simple.cxx
@@ -321,24 +321,42 @@ FGAirport* FGAirportList::search( const string& id)
     return (itr == airports_by_id.end() ? NULL : itr->second);
 }
 
+// wrap an FGIdentOrdering in an STL-compatible functor. not the most
+// efficent / pretty thing in the world, but avoids template nastiness in the 
+// headers, and we're only doing O(log(N)) comparisoms per search
+class orderingFunctor
+{
+public:
+  orderingFunctor(FGIdentOrdering* aOrder) :
+    mOrdering(aOrder)
+  { assert(aOrder); }
+  
+  bool operator()(const airport_map::value_type& aA, const std::string& aB) const
+  {
+    return mOrdering->compare(aA.first,aB);
+  }
+  
+private:
+  FGIdentOrdering* mOrdering;
+};
 
-// search for first subsequent alphabetically to supplied id
-const FGAirport* FGAirportList::findFirstById( const string& id, bool exact )
+const FGAirport* FGAirportList::findFirstById(const std::string& aIdent, FGIdentOrdering* aOrder)
 {
-    airport_map_iterator itr;
-    if (exact) {
-        itr = airports_by_id.find(id);
-    } else {
-        itr = airports_by_id.lower_bound(id);
-    }
-    if (itr == airports_by_id.end()) {
-        return (NULL);
-    } else {
-        return (itr->second);
-    }
+  airport_map_iterator itr;
+  if (aOrder) {
+    orderingFunctor func(aOrder);
+    itr = std::lower_bound(airports_by_id.begin(),airports_by_id.end(), aIdent, func);
+  } else {
+    itr = airports_by_id.lower_bound(aIdent);
+  }
+  
+  if (itr == airports_by_id.end()) {
+    return NULL;
+  }
+  
+  return itr->second;
 }
 
-
 // search for the airport nearest the specified position
 FGAirport* FGAirportList::search(double lon_deg, double lat_deg, double max_range)
 {
@@ -354,6 +372,7 @@ FGAirport* FGAirportList::search(double lon_deg, double lat_deg,
         FGAirportSearchFilter& filter)
 {
     double min_dist = max_range;
+
     airport_list_iterator it = airports_array.begin();
     airport_list_iterator end = airports_array.end();
     airport_list_iterator closest = end;
diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx
index d9f4cdd..8e16c30 100644
--- a/src/Airports/simple.hxx
+++ b/src/Airports/simple.hxx
@@ -117,6 +117,14 @@ public:
     virtual bool pass(FGAirport*) { return true; }
 };
 
+class FGIdentOrdering {
+public:
+  virtual ~FGIdentOrdering()
+  { ; }
+  
+  virtual bool compare(const std::string& aA, const std::string& aB) const
+  { return aA < aB; }
+};
 
 typedef std::map < std::string, FGAirport* > airport_map;
 typedef airport_map::iterator airport_map_iterator;
@@ -152,11 +160,11 @@ public:
 
     // Search for the next airport in ASCII sequence to the supplied id.
     // eg. id = "KDC" or "KDCA" would both return "KDCA".
-    // If exact = true then only exact matches are returned.
     // NOTE: Numbers come prior to A-Z in ASCII sequence so id = "LD" would return "LD57", not "LDDP"
+    // optional ordering can make letters coe before numbers
     // Implementation assumes airport codes are unique.
     // Returns NULL if unsucessfull.
-    const FGAirport* findFirstById( const std::string& id, bool exact = false );
+    const FGAirport* findFirstById(const std::string& aIdent, FGIdentOrdering* aOrder = NULL);
 
     // search for the airport closest to the specified position
     // (currently a linear inefficient search so it's probably not
diff --git a/src/Instrumentation/KLN89/kln89_page_fpl.cxx b/src/Instrumentation/KLN89/kln89_page_fpl.cxx
index 2ea0fa2..2929043 100644
--- a/src/Instrumentation/KLN89/kln89_page_fpl.cxx
+++ b/src/Instrumentation/KLN89/kln89_page_fpl.cxx
@@ -940,21 +940,21 @@ void KLN89FplPage::Knob2Left1() {
 				_bEntWp = true;
 				_fp0SelWpId.clear();	// Waypoints don't become the DTO default whilst being entered.
 				
-				bool multi;
-				const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false);
+        GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1));
 				if(NULL == wp) {
 					// no-op
 				} else {
-					if(_entWp == NULL) {
-						_entWp = new GPSWaypoint;
-						if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
+					if(_entWp) {
+            *_entWp = *wp; // copy
+            delete wp;
+          } else {
+            _entWp = wp;
+            if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
 							_kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
 						} else {
 							_kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);
 						}
-					}
-					// copy
-					*_entWp = *wp;
+          }
 				}
 			}
 		}
@@ -1013,21 +1013,21 @@ void KLN89FplPage::Knob2Right1() {
 				_bEntWp = true;
 				_fp0SelWpId.clear();	// Waypoints don't become the DTO default whilst being entered.
 				
-				bool multi;
-				const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false);
+        GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1));
 				if(NULL == wp) {
 					// no-op
 				} else {
-					if(_entWp == NULL) {
-						_entWp = new GPSWaypoint;
-						if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
+					if(_entWp) {
+            *_entWp = *wp; // copy
+            delete wp;
+          } else {
+            _entWp = wp;
+            if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
 							_kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
 						} else {
 							_kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);
 						}
-					}
-					// copy
-					*_entWp = *wp;
+          }
 				}
 			}
 		}
diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx
index 5454d6a..0510b6a 100644
--- a/src/Instrumentation/dclgps.cxx
+++ b/src/Instrumentation/dclgps.cxx
@@ -119,6 +119,15 @@ GPSWaypoint::GPSWaypoint() {
     appType = GPS_APP_NONE;
 }
 
+GPSWaypoint::GPSWaypoint(const std::string& aIdent, float aLat, float aLon, GPSWpType aType) :
+  id(aIdent),
+  lat(aLat),
+  lon(aLon),
+  type(aType),
+  appType(GPS_APP_NONE)
+{
+}
+
 GPSWaypoint::~GPSWaypoint() {}
 
 string GPSWaypoint::GetAprId() {
@@ -129,6 +138,33 @@ string GPSWaypoint::GetAprId() {
 	else return(id);
 }
 
+GPSWaypoint* GPSWaypoint::createFromFix(const FGFix* aFix)
+{
+  assert(aFix);
+  return new GPSWaypoint(aFix->get_ident(), 
+    aFix->get_lat() * SG_DEGREES_TO_RADIANS,
+    aFix->get_lon() * SG_DEGREES_TO_RADIANS,
+    GPS_WP_INT);
+}
+
+GPSWaypoint* GPSWaypoint::createFromNav(const FGNavRecord* aNav)
+{
+  assert(aNav);
+  return new GPSWaypoint(aNav->get_ident(), 
+    aNav->get_lat() * SG_DEGREES_TO_RADIANS,
+    aNav->get_lon() * SG_DEGREES_TO_RADIANS,
+    (aNav->get_fg_type() == FG_NAV_VOR ? GPS_WP_VOR : GPS_WP_NDB));
+}
+
+GPSWaypoint* GPSWaypoint::createFromAirport(const FGAirport* aApt)
+{
+  assert(aApt);
+  return new GPSWaypoint(aApt->getId(), 
+    aApt->getLatitude() * SG_DEGREES_TO_RADIANS,
+    aApt->getLongitude() * SG_DEGREES_TO_RADIANS,
+    GPS_WP_APT);
+}
+
 ostream& operator << (ostream& os, GPSAppWpType type) {
 	switch(type) {
 		case(GPS_IAF):       return(os << "IAF");
@@ -301,12 +337,7 @@ DCLGPS::DCLGPS(RenderArea2D* instrument) {
 
 DCLGPS::~DCLGPS() {
 	delete _time;
-	for(gps_waypoint_map_iterator itr = _waypoints.begin(); itr != _waypoints.end(); ++itr) {
-		for(unsigned int i = 0; i < (*itr).second.size(); ++i) {
-			delete(((*itr).second)[i]);
-		}
-	}
-	delete _approachFP;		// Don't need to delete the waypoints inside since they point to
+  delete _approachFP;		// Don't need to delete the waypoints inside since they point to
 							// the waypoints in the approach database.
 	// TODO - may need to delete the approach database!!
 }
@@ -329,332 +360,9 @@ void DCLGPS::init() {
 	globals->get_commands()->addCommand("kln89_knob1right1", do_kln89_knob1right1);
 	globals->get_commands()->addCommand("kln89_knob2left1", do_kln89_knob2left1);
 	globals->get_commands()->addCommand("kln89_knob2right1", do_kln89_knob2right1);
-	
-	// Build the GPS-specific databases.
-	// TODO - consider splitting into real life GPS database regions - eg Americas, Europe etc.
-	// Note that this needs to run after FG's airport and nav databases are up and running
-	_waypoints.clear();
-	const airport_list* apts = globals->get_airports()->getAirportList();
-	for(unsigned int i = 0; i < apts->size(); ++i) {
-		FGAirport* a = (*apts)[i];
-		GPSWaypoint* w = new GPSWaypoint;
-		w->id = a->getId();
-		w->lat = a->getLatitude() * SG_DEGREES_TO_RADIANS;
-		w->lon = a->getLongitude() * SG_DEGREES_TO_RADIANS;
-		w->type = GPS_WP_APT;
-		gps_waypoint_map_iterator wtr = _waypoints.find(a->getId());
-		if(wtr == _waypoints.end()) {
-			gps_waypoint_array arr;
-			arr.push_back(w);
-			_waypoints[w->id] = arr;
-		} else {
-			wtr->second.push_back(w);
-		}
-	}
-	nav_map_type navs = globals->get_navlist()->get_navaids();
-	for(nav_map_iterator itr = navs.begin(); itr != navs.end(); ++itr) {
-		nav_list_type nlst = itr->second;
-		for(unsigned int i = 0; i < nlst.size(); ++i) {
-			FGNavRecord* n = nlst[i];
-			if(n->get_fg_type() == FG_NAV_VOR || n->get_fg_type() == FG_NAV_NDB) {	// We don't bother with ILS etc.
-				GPSWaypoint* w = new GPSWaypoint;
-				w->id = n->get_ident();
-				w->lat = n->get_lat() * SG_DEGREES_TO_RADIANS;
-				w->lon = n->get_lon() * SG_DEGREES_TO_RADIANS;
-				w->type = (n->get_fg_type() == FG_NAV_VOR ? GPS_WP_VOR : GPS_WP_NDB);
-				gps_waypoint_map_iterator wtr = _waypoints.find(n->get_ident());
-				if(wtr == _waypoints.end()) {
-					gps_waypoint_array arr;
-					arr.push_back(w);
-					_waypoints[w->id] = arr;
-				} else {
-					wtr->second.push_back(w);
-				}
-			}
-		}
-	}
-	const fix_map_type* fixes = globals->get_fixlist()->getFixList();
-	for(fix_map_const_iterator itr = fixes->begin(); itr != fixes->end(); ++itr) {
-		FGFix f = itr->second;
-		GPSWaypoint* w = new GPSWaypoint;
-		w->id = f.get_ident();
-		w->lat = f.get_lat() * SG_DEGREES_TO_RADIANS;
-		w->lon = f.get_lon() * SG_DEGREES_TO_RADIANS;
-		w->type = GPS_WP_INT;
-		gps_waypoint_map_iterator wtr = _waypoints.find(f.get_ident());
-		if(wtr == _waypoints.end()) {
-			gps_waypoint_array arr;
-			arr.push_back(w);
-			_waypoints[w->id] = arr;
-		} else {
-			wtr->second.push_back(w);
-		}
-	}
-	// TODO - add USR waypoints as well.
-	
+		
 	// Not sure if this should be here, but OK for now.
 	CreateDefaultFlightPlans();
-	
-	// Hack - hardwire some instrument approaches for testing.
-	// TODO - read these from file - either all at startup or as needed.
-	FGNPIAP* iap = new FGNPIAP;
-	iap->_id = "KHWD";
-	iap->_name = "VOR/DME OR GPS-B";
-	iap->_abbrev = "VOR/D";
-	iap->_rwyStr = "B";
-	iap->_IAF.clear();
-	iap->_IAP.clear();
-	iap->_MAP.clear();
-	// -------
-	GPSWaypoint* wp = new GPSWaypoint;
-	wp->id = "SUNOL";
-	bool multi;
-	// Nasty using the find any function here, but it saves converting data from FGFix etc. 
-	const GPSWaypoint* fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAF;
-	iap->_IAF.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "MABRY";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAF;
-	iap->_IAF.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "IMPLY";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAP;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "DECOT";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_FAF;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "MAPVV";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_MAP;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "OAK";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_MAHP;
-	iap->_MAP.push_back(wp);
-	// -------
-	_np_iap[iap->_id].push_back(iap);
-	// -----------------------
-	// -----------------------
-	iap = new FGNPIAP;
-	iap->_id = "KHWD";
-	iap->_name = "VOR OR GPS-A";
-	iap->_abbrev = "VOR-";
-	iap->_rwyStr = "A";
-	iap->_IAF.clear();
-	iap->_IAP.clear();
-	iap->_MAP.clear();
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "SUNOL";
-	// Nasty using the find any function here, but it saves converting data from FGFix etc. 
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAF;
-	iap->_IAF.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "MABRY";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAF;
-	iap->_IAF.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "IMPLY";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAP;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "DECOT";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_FAF;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "MAPVV";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_MAP;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "OAK";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_MAHP;
-	iap->_MAP.push_back(wp);
-	// -------
-	_np_iap[iap->_id].push_back(iap);
-	// ------------------
-	// ------------------
-	/*
-	// Ugh - don't load this one - the waypoints required aren't in fix.dat.gz - result: program crash!
-	// TODO - make the IAP loader robust to absent waypoints.
-	iap = new FGNPIAP;
-	iap->_id = "KHWD";
-	iap->_name = "GPS RWY 28L";
-	iap->_abbrev = "GPS";
-	iap->_rwyStr = "28L";
-	iap->_IAF.clear();
-	iap->_IAP.clear();
-	iap->_MAP.clear();
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "SUNOL";
-	// Nasty using the find any function here, but it saves converting data from FGFix etc. 
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAF;
-	iap->_IAF.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "SJC";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAF;
-	iap->_IAF.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "JOCPI";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_IAP;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "SUDGE";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_FAF;
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "RW28L";
-	wp->appType = GPS_MAP;
-	if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) {
-		// Assume that this is a missed-approach point based on the runway number
-		// Get the runway threshold location etc
-	} else {
-		fp = FindFirstById(wp->id, multi, true);
-		if(fp == NULL) {
-			cout << "Failed to find waypoint " << wp->id << " in database...\n";
-		} else {
-			*wp = *fp;
-		}
-	}
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "OAK";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_MAHP;
-	iap->_MAP.push_back(wp);
-	// -------
-	_np_iap[iap->_id].push_back(iap);
-	*/
-	iap = new FGNPIAP;
-	iap->_id = "C83";
-	iap->_name = "GPS RWY 30";
-	iap->_abbrev = "GPS";
-	iap->_rwyStr = "30";
-	iap->_IAF.clear();
-	iap->_IAP.clear();
-	iap->_MAP.clear();
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "MAXNI";
-	// Nasty using the find any function here, but it saves converting data from FGFix etc. 
-	fp = FindFirstById(wp->id, multi, true);
-	if(fp) {
-		*wp = *fp;
-		wp->appType = GPS_IAF;
-		iap->_IAF.push_back(wp);
-	}
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "PATYY";
-	fp = FindFirstById(wp->id, multi, true);
-	if(fp) {
-		*wp = *fp;
-		wp->appType = GPS_IAF;
-		iap->_IAF.push_back(wp);
-	}
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "TRACY";
-	fp = FindFirstById(wp->id, multi, true);
-	if(fp) {
-		*wp = *fp;
-		wp->appType = GPS_IAF;
-		iap->_IAF.push_back(wp);
-	}
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "TRACY";
-	fp = FindFirstById(wp->id, multi, true);
-	if(fp) {
-		*wp = *fp;
-		wp->appType = GPS_IAP;
-		iap->_IAP.push_back(wp);
-	}
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "BABPI";
-	fp = FindFirstById(wp->id, multi, true);
-	if(fp) {
-		*wp = *fp;
-		wp->appType = GPS_FAF;
-		iap->_IAP.push_back(wp);
-	}
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "AMOSY";
-	wp->appType = GPS_MAP;
-	if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) {
-		// Assume that this is a missed-approach point based on the runway number
-		// TODO: Get the runway threshold location etc
-		cout << "TODO - implement missed-approach point based on rwy no.\n";
-	} else {
-		fp = FindFirstById(wp->id, multi, true);
-		if(fp == NULL) {
-			cout << "Failed to find waypoint " << wp->id << " in database...\n";
-		} else {
-			*wp = *fp;
-			wp->appType = GPS_MAP;
-		}
-	}
-	iap->_IAP.push_back(wp);
-	// -------
-	wp = new GPSWaypoint;
-	wp->id = "HAIRE";
-	fp = FindFirstById(wp->id, multi, true); 
-	*wp = *fp;
-	wp->appType = GPS_MAHP;
-	iap->_MAP.push_back(wp);
-	// -------
-	_np_iap[iap->_id].push_back(iap);
 }
 
 void DCLGPS::bind() {
@@ -962,8 +670,7 @@ double DCLGPS::GetCDIDeflection() const {
 
 void DCLGPS::DtoInitiate(const string& s) {
 	//cout << "DtoInitiate, s = " << s << '\n';
-	bool multi;
-	const GPSWaypoint* wp = FindFirstById(s, multi, true);
+	const GPSWaypoint* wp = FindFirstByExactId(s);
 	if(wp) {
 		//cout << "Waypoint found, starting dto operation!\n";
 		_dto = true;
@@ -972,6 +679,7 @@ void DCLGPS::DtoInitiate(const string& s) {
 		_fromWaypoint.lon = _gpsLon;
 		_fromWaypoint.type = GPS_WP_VIRT;
 		_fromWaypoint.id = "DTOWP";
+    delete wp;
 	} else {
 		//cout << "Waypoint not found, ignoring dto request\n";
 		// Should bring up the user waypoint page, but we're not implementing that yet.
@@ -1105,10 +813,10 @@ double DCLGPS::GetTimeToWaypoint(const string& id) {
 	} else if(id == _activeWaypoint.id) {
 		return(_eta);
 	} else {
-		bool multi;
-		const GPSWaypoint* wp = FindFirstById(id, multi, true);
+		const GPSWaypoint* wp = FindFirstByExactId(id);
 		if(wp == NULL) return(-1.0);
 		double distm = GetGreatCircleDistance(_gpsLat, _gpsLon, wp->lat, wp->lon);
+    delete wp;
 		return(distm / _groundSpeed_ms);
 	}
 	return(-1.0);	// Hopefully we never get here!
@@ -1312,79 +1020,116 @@ void DCLGPS::CreateFlightPlan(GPSFlightPlan* fp, vector<string> ids, vector<GPSW
 
 /***************************************/
 
-const GPSWaypoint* DCLGPS::ActualFindFirstById(const string& id, bool exact) {
-    gps_waypoint_map_const_iterator itr;
-    if(exact) {
-        itr = _waypoints.find(id);
-    } else {
-        itr = _waypoints.lower_bound(id);
-    }
-    if(itr == _waypoints.end()) {
-        return(NULL);
-    } else {
-		// TODO - don't just return the first one - either return all or the nearest one.
-        return((itr->second)[0]);
+/**
+ * STL functor for use with algorithms. This comapres strings according to
+ * the KLN-89's notion of ordering, with digits after letters.
+ * Also implements FGIdentOrdering so it can be passed into the various list
+ * find helpers.
+ */
+ 
+class stringOrderKLN89 : public FGIdentOrdering
+{
+public:
+  bool operator()(const gps_waypoint_map::value_type& aA, const std::string& aB) const
+  {
+    return compare(aA.first, aB);
+  }
+  
+  bool operator()(const std::string& aS1, const std::string& aS2) const
+  {
+    return compare(aS1, aS2);
+  }
+  
+  virtual bool compare(const std::string& aS1, const std::string& aS2) const
+  {
+    if (aS1.empty()) return true;
+    if (aS2.empty()) return false;
+    
+    char* a = (char*) aS1.c_str();
+    char* b = (char*) aS2.c_str();
+    
+    for ( ; *a && *b; ++a, ++b) {
+      if (*a == *b) continue;
+      
+      bool aDigit = isdigit(*a);
+      bool bDigit = isdigit(*b);
+      
+      if (aDigit == bDigit) {
+        return (*a < *b); // we already know they're not equal
+      }
+      
+      // digit-ness differs
+      if (aDigit) return false; // s1 = KS9 goes *after* s2 = KSA
+      assert(bDigit);
+      return true; // s1 = KSF, s2 = KS5, s1 is indeed < s2
     }
-}
-
-const GPSWaypoint* DCLGPS::FindFirstById(const string& id, bool &multi, bool exact) {
-	multi = false;
-	if(exact) return(ActualFindFirstById(id, exact));
-	
-	// OK, that was the easy case, now the fuzzy case
-	const GPSWaypoint* w1 = ActualFindFirstById(id);
-	if(w1 == NULL) return(w1);
-	
-	// The non-trivial code from here to the end of the function is all to deal with the fact that
-	// the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters).
-	string id2 = id;
-	//string id3 = id+'0';
-	string id4 = id+'A';
-	// Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-	//bool alfa = isalpha(id2[id2.size() - 1]);
-	id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-	const GPSWaypoint* w2 = ActualFindFirstById(id2);
-	//FGAirport* a3 = globals->get_airports()->findFirstById(id3);
-	const GPSWaypoint* w4 = ActualFindFirstById(id4);
-	//cout << "Strings sent were " << id << ", " << id2 << " and " << id4 << '\n';
-	//cout << "Airports returned were (a1, a2, a4): " << a1->getId() << ", " << a2->getId() << ", " << a4->getId() << '\n';
-	//cout << "Pointers were " << a1 << ", " << a2 << ", " << a4 << '\n';
-	
-	// TODO - the below handles the imediately following char OK
-	// eg id = "KD" returns "KDAA" instead of "KD5"
-	// but it doesn't handle numbers / letters further down the string,
-	// eg - id = "I" returns "IA01" instead of "IAN"
-	// We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string.
-	// (Currenly fixed with recursion).
-	
-	if(w4 != w2) { // A-Z match - preferred
-		//cout << "A-Z match!\n";
-		if(w4->id.size() - id.size() > 2) {
-			// Check for numbers further on
-			for(unsigned int i=id.size(); i<w4->id.size(); ++i) {
-				if(!isalpha(w4->id[i])) {
-					//cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n';
-					return(FindFirstById(w4->id.substr(0, i), multi, exact));
-				}
-			}
-		}
-		return(w4);
-	} else if(w1 != w2) {  // 0-9 match
-		//cout << "0-9 match!\n";
-		if(w1->id.size() - id.size() > 2) {
-			// Check for numbers further on
-			for(unsigned int i=id.size(); i<w1->id.size(); ++i) {
-				if(!isalpha(w1->id[i])) {
-					//cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n';
-					return(FindFirstById(w1->id.substr(0, i), multi, exact));
-				}
-			}
-		}
-		return(w1);
-	} else {  // No match
-		return(NULL);
-	}
-	return NULL;
+    
+    if (*b) return true; // *a == 0, s2 is longer
+    return false; // s1 is longer, or strings are equal
+  }
+};
+
+GPSWaypoint* DCLGPS::FindFirstById(const string& id) const
+{
+  stringOrderKLN89 ordering;
+  nav_list_type vors = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, false);
+  nav_list_type ndbs = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, false);
+  const FGFix* fix = globals->get_fixlist()->findFirstByIdent(id, &ordering);
+  const FGAirport* apt = globals->get_airports()->findFirstById(id, &ordering);
+  // search local gps waypoints (USR)
+
+// pick the best - ugly logic, sorry. This is a temporary fix to getting rid
+// of the huge local waypoint table, it'll die when there's a way to query
+// this stuff centrally.
+// what we're doing is using map inserts to order the result, then using
+// the first entry (begin()) as the lowest, hence best, match
+  map<string, GPSWpType, stringOrderKLN89> sorter;
+  if (fix) sorter[fix->get_ident()] = GPS_WP_INT;
+  if (apt) sorter[apt->getId()] = GPS_WP_APT;
+  if (!vors.empty()) sorter[vors.front()->get_ident()] = GPS_WP_VOR;
+  if (!ndbs.empty()) sorter[ndbs.front()->get_ident()] = GPS_WP_NDB;
+
+  if (sorter.empty()) return NULL; // no results at all
+  GPSWpType ty = sorter.begin()->second;
+  
+  switch (ty) {
+  case GPS_WP_INT: 
+    return GPSWaypoint::createFromFix(fix);
+  
+  case GPS_WP_APT:
+    return GPSWaypoint::createFromAirport(apt);
+  
+  case GPS_WP_VOR:
+    return GPSWaypoint::createFromNav(vors.front());
+    
+  case GPS_WP_NDB:
+    return GPSWaypoint::createFromNav(ndbs.front());
+  default:
+    return NULL; // can't happen
+  }
+}
+
+GPSWaypoint* DCLGPS::FindFirstByExactId(const string& id) const
+{
+  if (const FGAirport* apt = globals->get_airports()->search(id)) {
+    return GPSWaypoint::createFromAirport(apt);
+  }
+  
+  if (const FGFix* fix = globals->get_fixlist()->search(id)) {
+    return GPSWaypoint::createFromFix(fix);
+  }
+  
+  nav_list_type vors = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, true);
+  if (!vors.empty()) {
+    return GPSWaypoint::createFromNav(vors.front());
+  }
+  
+  nav_list_type ndbs = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, true);
+  if (!ndbs.empty()) {
+    return GPSWaypoint::createFromNav(ndbs.front());
+  }
+  
+  return NULL;
 }
 
 // Host specific lookup functions
@@ -1407,55 +1152,6 @@ FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact)
 	}
 	return(NULL);	// Shouldn't get here!
 }
-#if 0
-Overlays::NAV* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact) {
-	// NOTE - at the moment multi is never set.
-	multi = false;
-	if(exact) return(_overlays->FindFirstVorById(id, exact));
-	
-	// OK, that was the easy case, now the fuzzy case
-	Overlays::NAV* n1 = _overlays->FindFirstVorById(id);
-	if(n1 == NULL) return(n1);
-	
-	string id2 = id;
-	string id3 = id+'0';
-	string id4 = id+'A';
-	// Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-	bool alfa = isalpha(id2[id2.size() - 1]);
-	id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-	Overlays::NAV* n2 = _overlays->FindFirstVorById(id2);
-	//Overlays::NAV* n3 = _overlays->FindFirstVorById(id3);
-	//Overlays::NAV* n4 = _overlays->FindFirstVorById(id4);
-	//cout << "Strings sent were " << id << ", " << id2 << ", " << id3 << ", " << id4 << '\n';
-	
-	
-	if(alfa) {
-		if(n1 != n2) { // match
-			return(n1);
-		} else {
-			return(NULL);
-		}
-	}
-	
-	/*
-	if(n1 != n2) {
-		// Something matches - the problem is the number/letter preference order is reversed between the GPS and the STL
-		if(n4 != n2) {
-			// There's a letter match - return that
-			return(n4);
-		} else {
-			// By definition we must have a number match
-			if(n3 == n2) cout << "HELP - LOGIC FLAW in find VOR!\n";
-			return(n3);
-		}
-	} else {
-		// No match
-		return(NULL);
-	}
-	*/
-	return NULL;
-}
-#endif //0
 
 // TODO - add the ASCII / alphabetical stuff from the Atlas version
 FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) {
@@ -1476,179 +1172,25 @@ FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact)
 	}
 	return(NULL);	// Shouldn't get here!
 }
-#if 0
-Overlays::NAV* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) {
-	// NOTE - at the moment multi is never set.
-	multi = false;
-	if(exact) return(_overlays->FindFirstNDBById(id, exact));
-	
-	// OK, that was the easy case, now the fuzzy case
-	Overlays::NAV* n1 = _overlays->FindFirstNDBById(id);
-	if(n1 == NULL) return(n1);
-	
-	string id2 = id;
-	string id3 = id+'0';
-	string id4 = id+'A';
-	// Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-	bool alfa = isalpha(id2[id2.size() - 1]);
-	id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-	Overlays::NAV* n2 = _overlays->FindFirstNDBById(id2);
-	//Overlays::NAV* n3 = _overlays->FindFirstNDBById(id3);
-	//Overlays::NAV* n4 = _overlays->FindFirstNDBById(id4);
-	//cout << "Strings sent were " << id << ", " << id2 << ", " << id3 << ", " << id4 << '\n';
-	
-	
-	if(alfa) {
-		if(n1 != n2) { // match
-			return(n1);
-		} else {
-			return(NULL);
-		}
-	}
-	
-	/*
-	if(n1 != n2) {
-		// Something matches - the problem is the number/letter preference order is reversed between the GPS and the STL
-		if(n4 != n2) {
-			// There's a letter match - return that
-			return(n4);
-		} else {
-			// By definition we must have a number match
-			if(n3 == n2) cout << "HELP - LOGIC FLAW in find VOR!\n";
-			return(n3);
-		}
-	} else {
-		// No match
-		return(NULL);
-	}
-	*/
-	return NULL;
-}
-#endif //0
 
-// TODO - add the ASCII / alphabetical stuff from the Atlas version
 const FGFix* DCLGPS::FindFirstIntById(const string& id, bool &multi, bool exact) {
 	// NOTE - at the moment multi is never set, and indeed can't be
 	// since FG can only map one Fix per ID at the moment.
 	multi = false;
-	if(exact) return(globals->get_fixlist()->findFirstByIdent(id, exact));
-	
-	const FGFix* f1 = globals->get_fixlist()->findFirstByIdent(id, exact);
-	if(f1 == NULL) return(f1);
+	if (exact) return globals->get_fixlist()->search(id);
 	
-	// The non-trivial code from here to the end of the function is all to deal with the fact that
-	// the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters).
-	// It is copied from the airport version which is definately needed, but at present I'm not actually 
-	// sure if any fixes in FG or real-life have numbers in them!
-	string id2 = id;
-	//string id3 = id+'0';
-	string id4 = id+'A';
-	// Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-	//bool alfa = isalpha(id2[id2.size() - 1]);
-	id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-	const FGFix* f2 = globals->get_fixlist()->findFirstByIdent(id2);
-	//const FGFix* a3 = globals->get_fixlist()->findFirstByIdent(id3);
-	const FGFix* f4 = globals->get_fixlist()->findFirstByIdent(id4);
-	
-	// TODO - the below handles the imediately following char OK
-	// eg id = "KD" returns "KDAA" instead of "KD5"
-	// but it doesn't handle numbers / letters further down the string,
-	// eg - id = "I" returns "IA01" instead of "IAN"
-	// We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string.
-	// (Currenly fixed with recursion).
-	
-	if(f4 != f2) { // A-Z match - preferred
-		//cout << "A-Z match!\n";
-		if(f4->get_ident().size() - id.size() > 2) {
-			// Check for numbers further on
-			for(unsigned int i=id.size(); i<f4->get_ident().size(); ++i) {
-				if(!isalpha(f4->get_ident()[i])) {
-					//cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n';
-					return(FindFirstIntById(f4->get_ident().substr(0, i), multi, exact));
-				}
-			}
-		}
-		return(f4);
-	} else if(f1 != f2) {  // 0-9 match
-		//cout << "0-9 match!\n";
-		if(f1->get_ident().size() - id.size() > 2) {
-			// Check for numbers further on
-			for(unsigned int i=id.size(); i<f1->get_ident().size(); ++i) {
-				if(!isalpha(f1->get_ident()[i])) {
-					//cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n';
-					return(FindFirstIntById(f1->get_ident().substr(0, i), multi, exact));
-				}
-			}
-		}
-		return(f1);
-	} else {  // No match
-		return(NULL);
-	}
-		
-	return NULL;	// Don't think we can ever get here.
+  stringOrderKLN89 ordering;
+  return globals->get_fixlist()->findFirstByIdent(id, &ordering);
 }
 
 const FGAirport* DCLGPS::FindFirstAptById(const string& id, bool &multi, bool exact) {
 	// NOTE - at the moment multi is never set.
 	//cout << "FindFirstAptById, id = " << id << '\n';
 	multi = false;
-	if(exact) return(globals->get_airports()->findFirstById(id, exact));
-	
-	// OK, that was the easy case, now the fuzzy case
-	const FGAirport* a1 = globals->get_airports()->findFirstById(id);
-	if(a1 == NULL) return(a1);
+	if(exact) return(globals->get_airports()->search(id));
 	
-	// The non-trivial code from here to the end of the function is all to deal with the fact that
-	// the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters).
-	string id2 = id;
-	//string id3 = id+'0';
-	string id4 = id+'A';
-	// Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-	//bool alfa = isalpha(id2[id2.size() - 1]);
-	id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-	const FGAirport* a2 = globals->get_airports()->findFirstById(id2);
-	//FGAirport* a3 = globals->get_airports()->findFirstById(id3);
-	const FGAirport* a4 = globals->get_airports()->findFirstById(id4);
-	//cout << "Strings sent were " << id << ", " << id2 << " and " << id4 << '\n';
-	//cout << "Airports returned were (a1, a2, a4): " << a1->getId() << ", " << a2->getId() << ", " << a4->getId() << '\n';
-	//cout << "Pointers were " << a1 << ", " << a2 << ", " << a4 << '\n';
-	
-	// TODO - the below handles the imediately following char OK
-	// eg id = "KD" returns "KDAA" instead of "KD5"
-	// but it doesn't handle numbers / letters further down the string,
-	// eg - id = "I" returns "IA01" instead of "IAN"
-	// We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string.
-	// (Currenly fixed with recursion).
-	
-	if(a4 != a2) { // A-Z match - preferred
-		//cout << "A-Z match!\n";
-		if(a4->getId().size() - id.size() > 2) {
-			// Check for numbers further on
-			for(unsigned int i=id.size(); i<a4->getId().size(); ++i) {
-				if(!isalpha(a4->getId()[i])) {
-					//cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n';
-					return(FindFirstAptById(a4->getId().substr(0, i), multi, exact));
-				}
-			}
-		}
-		return(a4);
-	} else if(a1 != a2) {  // 0-9 match
-		//cout << "0-9 match!\n";
-		if(a1->getId().size() - id.size() > 2) {
-			// Check for numbers further on
-			for(unsigned int i=id.size(); i<a1->getId().size(); ++i) {
-				if(!isalpha(a1->getId()[i])) {
-					//cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n';
-					return(FindFirstAptById(a1->getId().substr(0, i), multi, exact));
-				}
-			}
-		}
-		return(a1);
-	} else {  // No match
-		return(NULL);
-	}
-		
-	return NULL;
+  stringOrderKLN89 ordering;
+  return globals->get_airports()->findFirstById(id, &ordering);
 }
 
 FGNavRecord* DCLGPS::FindClosestVor(double lat_rad, double lon_rad) {
diff --git a/src/Instrumentation/dclgps.hxx b/src/Instrumentation/dclgps.hxx
index 0820338..94c904a 100644
--- a/src/Instrumentation/dclgps.hxx
+++ b/src/Instrumentation/dclgps.hxx
@@ -91,6 +91,13 @@ ostream& operator << (ostream& os, GPSAppWpType type);
 
 struct GPSWaypoint {
     GPSWaypoint();
+  
+  GPSWaypoint(const std::string& aIdent, float lat, float lon, GPSWpType aType);
+  
+  static GPSWaypoint* createFromFix(const FGFix* aFix);
+  static GPSWaypoint* createFromNav(const FGNavRecord* aNav);
+  static GPSWaypoint* createFromAirport(const FGAirport* aApt);
+  
     ~GPSWaypoint();
 	string GetAprId();	// Returns the id with i, f, m or h added if appropriate. (Initial approach fix, final approach fix, etc)
 	string id;
@@ -407,14 +414,13 @@ protected:
 	// 
 	
 	// Data and lookup functions
-	// All waypoints mapped by id.
-	gps_waypoint_map _waypoints;
-private:
-	// Worker function for the below.
-	const GPSWaypoint* ActualFindFirstById(const string& id, bool exact = false);
+
+
 protected:
 	// Find first of any type of waypoint by id.  (TODO - Possibly we should return multiple waypoints here).
-	const GPSWaypoint* FindFirstById(const string& id, bool &multi, bool exact = false); 
+  GPSWaypoint* FindFirstById(const string& id) const;
+  GPSWaypoint* FindFirstByExactId(const string& id) const;
+   
 	FGNavRecord* FindFirstVorById(const string& id, bool &multi, bool exact = false);
 	FGNavRecord* FindFirstNDBById(const string& id, bool &multi, bool exact = false);
 	const FGAirport* FindFirstAptById(const string& id, bool &multi, bool exact = false);
diff --git a/src/Navaids/fixlist.cxx b/src/Navaids/fixlist.cxx
index 4731a51..b17ec00 100644
--- a/src/Navaids/fixlist.cxx
+++ b/src/Navaids/fixlist.cxx
@@ -30,6 +30,8 @@
 #include <simgear/math/sg_geodesy.hxx>
 
 #include "fixlist.hxx"
+#include "Airports/simple.hxx";
+
 using std::pair;
 
 
@@ -120,17 +122,45 @@ bool FGFixList::query_and_offset( const string& ident, double lon, double lat,
     return true;
 }
 
-const FGFix* FGFixList::findFirstByIdent( const string& ident, bool exact)
+const FGFix* FGFixList::search(const string& ident)
 {
-    fix_map_iterator itr;
-    if(exact) {
-        itr = fixlist.find(ident);
-    } else {
-        itr = fixlist.lower_bound(ident);
-    }
-    if(itr == fixlist.end()) {
-        return(NULL);
-    } else {
-        return(&(itr->second));
-    }
+  fix_map_iterator itr = fixlist.find(ident);
+  if (itr == fixlist.end()) {
+    return NULL;
+  }
+  
+  return &itr->second;
+}
+
+class orderingFunctor
+{
+public:
+  orderingFunctor(FGIdentOrdering* aOrder) :
+    mOrdering(aOrder)
+  { assert(aOrder); }
+  
+  bool operator()(const fix_map_type::value_type& aA, const std::string& aB) const
+  {
+    return mOrdering->compare(aA.first,aB);
+  }
+  
+private:
+  FGIdentOrdering* mOrdering;
+};
+
+const FGFix* FGFixList::findFirstByIdent( const string& ident, FGIdentOrdering* aOrder)
+{
+  fix_map_iterator itr;
+  if (aOrder) {
+    orderingFunctor func(aOrder);
+    itr = std::lower_bound(fixlist.begin(),fixlist.end(), ident, func);
+  } else {
+    itr = fixlist.lower_bound(ident);
+  }
+  
+  if (itr == fixlist.end()) {
+    return NULL;
+  }
+  
+  return &itr->second;
 }
diff --git a/src/Navaids/fixlist.hxx b/src/Navaids/fixlist.hxx
index 20b6f02..282cd1b 100644
--- a/src/Navaids/fixlist.hxx
+++ b/src/Navaids/fixlist.hxx
@@ -43,6 +43,8 @@ typedef multimap < string, FGFix > fix_map_type;
 typedef fix_map_type::iterator fix_map_iterator;
 typedef fix_map_type::const_iterator fix_map_const_iterator;
 
+class FGIdentOrdering; // FIXME, currently declared in Airports/simple.hxx
+
 class FGFixList {
 
     fix_map_type fixlist;
@@ -58,11 +60,13 @@ public:
     // query the database for the specified fix
     bool query( const string& ident, FGFix *f );
 
+    const FGFix* search(const string& ident);
+
     // Find fix of requested type with closest exact or following ident
     // (by ACSII values) to that supplied (ie. a lower-bound lookup).
     // Supplying true for exact forces only exact matches to be returned (similar to above function)
     // Returns NULL if no match found.
-    const FGFix* findFirstByIdent( const string& ident, bool exact = false );
+    const FGFix* findFirstByIdent( const string& ident, FGIdentOrdering* aOrder = NULL);
 
     // query the database for the specified fix, lon and lat are
     // in degrees, elev is in meters
