/**
  * Loads a route from the database from its ID
  * @param int $id Route ID to load
  * @param Walkable $w Walk to attach this route to, if the object already exists. A new one will be created if not.
  * @throws InvalidArgumentException If walkable passed in does not match walkable set in database
  */
 public static function loadSingle($id, Walkable $w = null)
 {
     $id = (int) $id;
     $db =& JFactory::getDBO();
     // First, get the route's general data
     $query = $db->getQuery(true);
     $query->select("*");
     $query->from("routes");
     $query->where(array("routeid = " . $id));
     $db->setQuery($query);
     $res = $db->query();
     if ($db->getNumRows($res) == 0) {
         return null;
     }
     $dbArr = $db->loadAssoc();
     $wiFactory = SWG::walkInstanceFactory();
     // If we've been given a Walkable, make sure it matches the one on the route
     // It's OK to load a route for a WalkInstance on a Walk, and vice-versa
     if ($w != null) {
         if ($w instanceof Walk) {
             if ($dbArr['walkid'] != $w->id) {
                 // Try to load a matching walkInstance
                 if (!empty($dbArr['walkinstanceid'])) {
                     $wi = $wiFactory->getSingle($dbArr['walkinstanceid']);
                     if ($wi->walkid != $w->id) {
                         throw new InvalidArgumentException("Loaded route is for WalkInstance " . $wi->id . ", Walk " . $wi->walkid . " (does not match Walk " . $w->id . ")");
                     }
                 } else {
                     throw new InvalidArgumentException("Loaded route is for Walk " . $dbArr['walkid'] . " (does not match Walk " . $w->id . ")");
                 }
             }
         } else {
             if ($dbArr['walkinstanceid'] != $w->id && $dbArr['walkid'] != $w->walkid) {
                 throw new InvalidArgumentException("Loaded route is not for given WalkInstance");
             }
         }
     } else {
         // Load the Walkable
         if (empty($dbArr['walkinstanceid'])) {
             // A Walk
             $w = Walk::getSingle($dbArr['walkid']);
         } else {
             // A WalkInstance
             $w = $wiFactory->getSingle($dbArr['walkinstanceid']);
         }
     }
     // Create the route object
     $rt = new Route($w);
     // TODO: uploadedby/time, length, ascent
     // Load the basic route properties
     $rt->id = $id;
     $rt->distance = $dbArr['length'];
     $rt->ascent = $dbArr['ascent'];
     $rt->uploadedBy = $dbArr['uploadedby'];
     // TODO: Load the actual user? Also, uploadedby should be a Joomla user, not a Leader
     $rt->uploadedDateTime = strtotime($dbArr['uploadeddatetime']);
     $rt->visibility = (int) $dbArr['visibility'];
     $rt->type = (int) $dbArr['type'];
     // Set all the waypoints
     $query = $db->getQuery(true);
     $query->select('*');
     $query->from("routepoints");
     $query->where(array("routeid = " . $id));
     $query->order("sequenceid ASC");
     $db->setQuery($query);
     $res = $db->query();
     // Joomla can't be arsed to support/provide documentation for fetching individual rows like EVERYTHING ELSE DOES
     $megaArray = $db->loadAssocList("sequenceid");
     foreach ($megaArray as $i => $dbArr) {
         $wp = new Waypoint();
         $wp->osRef = new OSRef($dbArr['easting'], $dbArr['northing']);
         $wp->altitude = $dbArr['altitude'];
         $wp->time = $dbArr['datetime'];
         $rt->setWaypoint($i, $wp);
     }
     return $rt;
 }