/**
   * Internal helper method to aid in the subclass architecture. Overwrites the superclass method
   * and calls it internally.
   *
   * @param header
   * @param s
   */
  protected void sentenceChooser(String header, String s) {
    if (header.equals(RMCSentence.HEADER)) {
      rmcSentence.setSentence(s);
      notifyListeners(this.rmcSentence);
    } else if (header.equals(GSVSentence.HEADER)) {
      // TODO: I wonder what happens if say 2 of 4 are received and parse is called?
      // Because 2 would be new data, 2 would be old data.
      // Can't happen because parse() only called when not null.
      // BUT what if it is in the middle of parsing and new data comes in?
      // Solution: Sync GSVSentence.parse()? checkRefresh() is already synced though.

      // 0. Get StringTokenizer to read info from NMEASentence:
      StringTokenizer st = new StringTokenizer(s, ",");
      st.nextToken(); // Skip header $GPGSV
      // 1.1 Find out how many sentences in sequence.
      gsvSentenceTotal = Integer.parseInt(st.nextToken());
      // 1.2 Find out which sentence this is.
      gsvSentenceNumber = Integer.parseInt(st.nextToken());
      // 2. Assign sentence to GSVSentence in order.
      gsvSentence.setSentence(s, gsvSentenceNumber, gsvSentenceTotal);
      // 3. If last sentence:
      if (gsvSentenceTotal == gsvSentenceNumber) {
        // 3a. setSentence() to last one so it is not null
        gsvSentence.setSentence(s);
        // 3b. Notify GPSListener
        notifyListeners(this.gsvSentence);
      }
    } else super.sentenceChooser(header, s); // Check superclass sentences.
  }
  public Location getLocation(int timeout) throws LocationException, InterruptedException {
    /* TODO The timeout might play to the fact that it is still acquiring satellites?
     * I was wondering about that before. Maybe it makes sense to have timeout in SimpleGPS?
     * TODO: Solution! Keep asking for altitude until is positive? (longitude can be negative)
     * Or perhaps just until speed positive? (set those after)
     * TODO: -1 in timeout is supposed to represent the default timeout (GPSListener?)
     * TODO: I don't know if this is supposed to wait for the GPS to provide a new
     * coordinate data or if it is okay to pass the latest cached GPS coordinates.
     * Is the purpose of the timeout that it gets a new updated location that
     * is not the previously returned or cached one?
     */

    if (timeout == 0) throw new IllegalArgumentException("timeout cannot equal 0");

    // Timeout results in LocationException:
    long startTime = System.currentTimeMillis();

    // TODO: Perhaps initialize and test for NaN instead.
    while (gps.getLatitude() == 0 & gps.getLongitude() == 0) {
      if (timeout != -1 & System.currentTimeMillis() - startTime > (timeout * 1000))
        throw new LocationException("GPS timed out");
      Thread.sleep(100); /* NOTE: This might very occasionally cause an error because
			* Thread.yield() seems to cause sentence parsing to start too soon.
			* (try changing sleep() to yield() to see what happens)
			* Perhaps something needs to be synchronized? */
    }

    QualifiedCoordinates qc =
        new QualifiedCoordinates(
            gps.getLatitude(),
            gps.getLongitude(),
            gps.getAltitude(),
            (gps.getHDOP() * 6),
            (gps.getVDOP() * 6));
    Location loc =
        new Location(
            qc,
            gps.getSpeed(),
            gps.getCourse(),
            gps.getTimeStamp(),
            0,
            null); // TODO: Implement location method and extraInfo (0 and null for now)

    return loc;
  }
  protected BTGPSLocationProvider() throws LocationException {

    // TODO: Move this to searchConnect method?
    // TODO: The problem here is that it searches every time. Slow. Need to try Properties?
    // TODO: BIG ONE: Should only connect to GPS that isPaired() (from menu). Will
    // allow some degree of control over which GPS is connects to in classroom.
    try {
      da = LocalDevice.getLocalDevice().getDiscoveryAgent();
      da.startInquiry(DiscoveryAgent.GIAC, this);
    } catch (BluetoothStateException e) {
      throw new LocationException(e.getMessage());
    }

    while (!doneInq) {
      Thread.yield();
    }

    if (btDevice == null) throw new LocationException("No device found");

    String address = btDevice.getBluetoothAddress();
    String btaddy = "btspp://" + address;

    try {
      StreamConnectionNotifier scn = (StreamConnectionNotifier) Connector.open(btaddy);

      if (scn == null) throw new LocationException("Bad BT address");
      StreamConnection c = scn.acceptAndOpen();

      /* This problem below occurred one time for my Holux GPS. The solution was to
       * remove the device from the Bluetooth menu, then find and pair again.
       */
      if (c == null) throw new LocationException("Failed. Try pairing at menu again");
      InputStream in = c.openInputStream();

      if (in != null) {
        gps = new SimpleGPS(in);
        // c.close(); // TODO: Clean up when done. HOW TO HANDLE IN LOCATION?
      }
    } catch (IOException e) {
      throw new LocationException(e.getMessage());
    }
    // Add itself to SimpleGPS as listener
    SimpleGPS.addListener(this);
  }
  public void setLocationListener(
      LocationListener listener, int interval, int timeout, int maxAge) {

    // * Stop all previous listener threads *
    listenerRunning = false;
    if (listyThread != null) {
      while (listyThread.isAlive()) {
        Thread.yield();
      } // End old thread
      listyThread = null; // Discard the listener thread instance
    }

    // * Remove any listeners from GPSListener *
    if (listener == null) {
      // Remove current listener from SimpleGPS
      SimpleGPS.removeListener(gpsl);
      gpsl = null;
      return; // No listener provided, so return now so it dosn't make a new one
    }

    // * Inner classes need final variables *
    final int to = timeout;
    final LocationListener l = listener;
    final LocationProvider lp = this;
    final int delay = interval * 1000; // Oddly interval is in seconds, and not float

    // Make new thread here and start it if interval > 0, else if -1
    // then use the GPSListener interface.
    if (interval > 0) { // Notify according to interval by user
      listyThread =
          new Thread() {
            public void run() {
              while (listenerRunning) {
                try {
                  // TODO: Probably only notify if location changed? Need to compare to old.
                  // TODO: Make helper method since this is used below too.
                  l.locationUpdated(lp, lp.getLocation(to));
                  Thread.sleep(delay);
                } catch (LocationException e) {
                  // TODO Auto-generated catch block
                } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                }
              }
            }
          };
      listyThread.setDaemon(true); // so JVM exits if thread is still running
      listenerRunning = true;
      listyThread.start();
    } else if (interval < 0) { // If interval is -1, use default update interval
      // In our case, update as soon as new coordinates are available from GPS (via GPSListener)
      // TODO: Alternate method: Use GPSListener for ProximityListener and this.
      gpsl =
          new GPSListener() {
            public void sentenceReceived(NMEASentence sen) {
              // Check if GGASentence. Means that new location info is ready
              if (sen.getHeader().equals(GGASentence.HEADER)) {
                try {
                  // TODO: Probably only notify if location changed? Need to compare to old.
                  l.locationUpdated(lp, lp.getLocation(to));
                } catch (LocationException e) {
                  // TODO Auto-generated catch block
                } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                }
              }
            }
          };
      SimpleGPS.addListener(gpsl);
    }

    // TODO: Need to implement LocationListener.providerStateChanged()
  }