@Override
  public List<SignalMetadata> getAllSignalListAvg() {
    PersistenceManager manager = PMF.getManager();
    try {
      ArrayList<SignalMetadata> signalInfo = new ArrayList<SignalMetadata>();
      Extent<SignalInfoAvg> allSignalInfoAvg = manager.getExtent(SignalInfoAvg.class);

      for (SignalInfoAvg s : allSignalInfoAvg) {
        signalInfo.add(s.getSignalMetadata());
      }

      return signalInfo;

    } finally {
      manager.close();
    }
  }
  @Override
  public List<SignalMetadata> getSignalList(
      Double minLatitude,
      Double minLongitude,
      Double maxLatitude,
      Double maxLongitude,
      List<String> carrierParams,
      List<String> phoneTypes,
      String clientId) {
    PersistenceManager manager = PMF.getManager();

    // If no carrier is specified, show points from all carriers
    if (carrierParams == null) {
      String[] carrierList = {"att", "verizon", "tmobile", "sprint"};
      carrierParams = Arrays.asList(carrierList);
    }

    // If no phoneType is specified, show points from all phoneTypes
    if (phoneTypes == null) {
      String[] phoneList = {"0", "1", "2", "3"};
      phoneTypes = Arrays.asList(phoneList);
    }

    // If user requests data for a region of size larger than 1.0000 by 1.0000 (about 11km by 11km),
    // only the center 1.0000 by 1.0000 of data will be returned
    if (maxLatitude - minLatitude > 1.0) {
      Double center = (maxLatitude + minLatitude) / 2.0;
      maxLatitude = center + .5;
      minLatitude = center - .5;
    }
    if (maxLongitude - minLongitude > 1.0) {
      Double centerl = (maxLongitude + minLongitude) / 2.0;
      maxLongitude = centerl + .5;
      minLongitude = centerl - .5;
    }

    try {
      ArrayList<SignalMetadata> signalInfo = new ArrayList<SignalMetadata>();

      // If clientId is absent, returns data within the given geographic box
      // for the given phoneType and carrier from the consolidated datastore
      if (clientId == null) {
        Query q = manager.newQuery(SignalInfoAvg.class);
        q.declareImports("import java.util.List");
        Object[] parameters = {minLatitude, maxLatitude, carrierParams, phoneTypes};
        q.declareParameters(
            "Double minLatitude, Double maxLatitude, List carrierParams, List phoneTypes");
        q.setFilter(
            "latitude >= minLatitude && latitude <= maxLatitude && carrierParams.contains(carrier) && phoneTypes.contains(phoneType)");

        List<SignalInfoAvg> allSignalInfo = (List<SignalInfoAvg>) q.executeWithArray(parameters);
        // Extent<SignalInfo> allSignalInfo = manager.getExtent(SignalInfo.class);

        ArrayList<SignalInfoAvg> filtered = new ArrayList<SignalInfoAvg>();
        for (SignalInfoAvg savg : allSignalInfo) {
          if (savg.getLongitude() >= minLongitude && savg.getLongitude() <= maxLongitude) {
            filtered.add(savg);
          }
        }

        for (SignalInfoAvg s : filtered) {
          signalInfo.add(s.getSignalMetadata());
        }

      } else {
        // If clientId is present, returns raw data of the given clientId,
        // phoneType, and carrier within the given geographic box
        Query q = manager.newQuery(SignalInfo.class);
        q.declareImports("import java.util.List");
        Object[] parameters = {minLatitude, maxLatitude, carrierParams, phoneTypes, clientId};
        q.declareParameters(
            "Double minLatitude, Double maxLatitude, List<String> carrierParams, List<String> phoneTypes, String myClientId");
        q.setFilter(
            "clientId == myClientId && latitude >= minLatitude && latitude <= maxLatitude && carrier == carrierParams && phoneType == phoneTypes");

        List<SignalInfo> allSignalInfo = (List<SignalInfo>) q.executeWithArray(parameters);
        // Extent<SignalInfo> allSignalInfo = manager.getExtent(SignalInfo.class);

        ArrayList<SignalInfo> filtered = new ArrayList<SignalInfo>();
        for (SignalInfo s : allSignalInfo) {
          if (s.getLongitude() >= minLongitude && s.getLongitude() <= maxLongitude) {
            filtered.add(s);
          }
        }

        for (SignalInfo s : filtered) {
          signalInfo.add(s.getSignalMetadata());
        }
      }

      return signalInfo;
    } finally {
      manager.close();
    }
  }