private InvAccess getImageAccess(
      InvDataset invDataset, ucar.nc2.util.CancelTask task, Result result) {

    List<InvAccess> accessList =
        new ArrayList<InvAccess>(invDataset.getAccess()); // a list of all the accesses
    while (accessList.size() > 0) {
      InvAccess access = chooseImageAccess(accessList);
      if (access != null) return access;

      // next choice is resolver type.
      access = invDataset.getAccess(ServiceType.RESOLVER);

      // no valid access
      if (access == null) {
        result.errLog.format("No access that could be used for Image Type %s %n", invDataset);
        return null;
      }

      // deal with RESOLVER type
      String datasetLocation = access.getStandardUrlName();
      InvDatasetImpl rds = openResolver(datasetLocation, task, result);
      if (rds == null) return null;

      // use the access list from the resolved dataset
      accessList = new ArrayList<InvAccess>(invDataset.getAccess());
    } // loop over accesses

    return null;
  }
  private NetcdfDataset openDataset(
      InvDataset invDataset, boolean acquire, ucar.nc2.util.CancelTask task, Result result)
      throws IOException {

    IOException saveException = null;

    List<InvAccess> accessList =
        new ArrayList<InvAccess>(invDataset.getAccess()); // a list of all the accesses
    while (accessList.size() > 0) {
      InvAccess access = chooseDatasetAccess(accessList);

      // no valid access
      if (access == null) {
        result.errLog.format("No access that could be used in dataset %s %n", invDataset);
        if (saveException != null) throw saveException;
        return null;
      }

      String datasetLocation = access.getStandardUrlName();
      ServiceType serviceType = access.getService().getServiceType();
      if (debugOpen)
        System.out.println("ThreddsDataset.openDataset try " + datasetLocation + " " + serviceType);

      // deal with RESOLVER type
      if (serviceType == ServiceType.RESOLVER) {
        InvDatasetImpl rds = openResolver(datasetLocation, task, result);
        if (rds == null) return null;
        accessList = new ArrayList<InvAccess>(rds.getAccess());
        continue;
      }

      // ready to open it through netcdf API
      NetcdfDataset ds;

      // try to open
      try {
        ds = openDataset(access, acquire, task, result);

      } catch (IOException e) {
        result.errLog.format("Cant open %s %n err=%s%n", datasetLocation, e.getMessage());
        if (debugOpen) {
          System.out.println("Cant open= " + datasetLocation + " " + serviceType);
          e.printStackTrace();
        }

        accessList.remove(access);
        saveException = e;
        continue;
      }

      result.accessUsed = access;
      return ds;
    } // loop over accesses

    if (saveException != null) throw saveException;
    return null;
  }
  /**
   * Find the "best" access in case theres more than one, based on what the CDM knows how to open
   * and use.
   *
   * @param accessList choose from this list.
   * @return best access method.
   */
  public InvAccess chooseDatasetAccess(List<InvAccess> accessList) {
    if (accessList.size() == 0) return null;

    InvAccess access = null;
    if (preferCdm) access = findAccessByServiceType(accessList, ServiceType.CdmRemote);

    if (access == null)
      access =
          findAccessByServiceType(
              accessList, ServiceType.FILE); // should mean that it can be opened through netcdf API
    if (access == null)
      access =
          findAccessByServiceType(
              accessList, ServiceType.NETCDF); //  ServiceType.NETCDF is deprecated, use FILE
    if (access == null) access = findAccessByServiceType(accessList, ServiceType.DODS);
    if (access == null) access = findAccessByServiceType(accessList, ServiceType.OPENDAP);
    if (access == null) access = findAccessByServiceType(accessList, ServiceType.CdmRemote);

    // look for HTTP with format we can read
    if (access == null) {
      InvAccess tryAccess = findAccessByServiceType(accessList, ServiceType.HTTPServer);
      if (tryAccess == null)
        tryAccess =
            findAccessByServiceType(
                accessList, ServiceType.HTTP); //  ServiceType.HTTP should be HTTPServer

      if (tryAccess != null) {
        DataFormatType format = tryAccess.getDataFormatType();

        // these are the file types we can read
        if ((DataFormatType.BUFR == format)
            || (DataFormatType.GINI == format)
            || (DataFormatType.GRIB1 == format)
            || (DataFormatType.GRIB2 == format)
            || (DataFormatType.HDF5 == format)
            || (DataFormatType.NCML == format)
            || (DataFormatType.NETCDF == format)
            || (DataFormatType.NEXRAD2 == format)
            || (DataFormatType.NIDS == format)) access = tryAccess;
      }
    }

    // ADDE
    if (access == null) access = findAccessByServiceType(accessList, ServiceType.ADDE);

    // RESOLVER
    if (access == null) {
      access = findAccessByServiceType(accessList, ServiceType.RESOLVER);
    }

    return access;
  }
  private InvAccess chooseImageAccess(List<InvAccess> accessList) {
    InvAccess access;

    access = findAccessByDataFormatType(accessList, DataFormatType.JPEG);
    if (access != null) return access;

    access = findAccessByDataFormatType(accessList, DataFormatType.GIF);
    if (access != null) return access;

    access = findAccessByDataFormatType(accessList, DataFormatType.TIFF);
    if (access != null) return access;

    access = findAccessByServiceType(accessList, ServiceType.ADDE);
    if (access != null) {
      String datasetLocation = access.getStandardUrlName();
      if (datasetLocation.indexOf("image") > 0) return access;
    }

    return access;
  }
  /**
   * Open a FeatureDataset from an InvAccess object.
   *
   * @param access use this InvAccess.
   * @param task may be null
   * @return ThreddsDataFactory.Result check fatalError for validity
   * @throws IOException on read error
   */
  public ThreddsDataFactory.Result openFeatureDataset(
      InvAccess access, ucar.nc2.util.CancelTask task) throws IOException {
    InvDataset invDataset = access.getDataset();
    ThreddsDataFactory.Result result = new Result();
    if (invDataset.getDataType() == null) {
      result.errLog.format("InvDatasert must specify a FeatureType%n");
      result.fatalError = true;
      return result;
    }

    return openFeatureDataset(invDataset.getDataType(), access, task, result);
  }
  private ThreddsDataFactory.Result openFeatureDataset(
      FeatureType wantFeatureType, InvAccess access, ucar.nc2.util.CancelTask task, Result result)
      throws IOException {
    result.featureType = wantFeatureType;
    result.accessUsed = access;

    // special handling for IMAGE
    if (result.featureType == FeatureType.IMAGE) {
      result.imageURL = access.getStandardUrlName();
      result.location = result.imageURL;
      return result;
    }

    if (access.getService().getServiceType() == ServiceType.CdmrFeature) {
      result.featureDataset =
          CdmrFeatureDataset.factory(wantFeatureType, access.getStandardUrlName());

    } else {

      // all other datatypes
      NetcdfDataset ncd = openDataset(access, true, task, result);
      if (null != ncd) {
        result.featureDataset =
            FeatureDatasetFactoryManager.wrap(result.featureType, ncd, task, result.errLog);
      }
    }

    if (null == result.featureDataset) result.fatalError = true;
    else {
      result.location = result.featureDataset.getLocation();
      if ((result.featureType == null) && (result.featureDataset != null))
        result.featureType = result.featureDataset.getFeatureType();
    }

    return result;
  }
 private InvAccess findAccessByDataFormatType(List<InvAccess> accessList, DataFormatType type) {
   for (InvAccess a : accessList) {
     if (type.toString().equalsIgnoreCase(a.getDataFormatType().toString())) return a;
   }
   return null;
 }
 private InvAccess findAccessByServiceType(List<InvAccess> accessList, ServiceType type) {
   for (InvAccess a : accessList) {
     if (type.toString().equalsIgnoreCase(a.getService().getServiceType().toString())) return a;
   }
   return null;
 }
  private NetcdfDataset openDataset(
      InvAccess access, boolean acquire, ucar.nc2.util.CancelTask task, Result result)
      throws IOException {
    InvDataset invDataset = access.getDataset();
    String datasetId = invDataset.getID();
    String title = invDataset.getName();

    String datasetLocation = access.getStandardUrlName();
    ServiceType serviceType = access.getService().getServiceType();
    if (debugOpen) System.out.println("ThreddsDataset.openDataset= " + datasetLocation);

    // deal with RESOLVER type
    if (serviceType == ServiceType.RESOLVER) {
      InvDatasetImpl rds = openResolver(datasetLocation, task, result);
      if (rds == null) return null;
      return openDataset(rds, acquire, task, result);
    }

    // ready to open it through netcdf API
    NetcdfDataset ds;

    // open DODS type
    if ((serviceType == ServiceType.OPENDAP) || (serviceType == ServiceType.DODS)) {
      String curl = DODSNetcdfFile.canonicalURL(datasetLocation);
      ds =
          acquire
              ? NetcdfDataset.acquireDataset(curl, enhanceMode, task)
              : NetcdfDataset.openDataset(curl, enhanceMode, task);
    }

    // open CdmRemote
    else if (serviceType == ServiceType.CdmRemote) {
      String curl = CdmRemote.canonicalURL(datasetLocation);
      ds =
          acquire
              ? NetcdfDataset.acquireDataset(curl, enhanceMode, task)
              : NetcdfDataset.openDataset(curl, enhanceMode, task);
    }

    /* open ADDE type
    else if (serviceType == ServiceType.ADDE) {
      try {
        ds = ucar.nc2.adde.AddeDatasetFactory.openDataset(access, task);

      } catch (IOException e) {
        log.append("Cant open as ADDE dataset= "+datasetLocation);
        accessList.remove( access);
        continue;
      }
    } */

    else {
      // open through NetcdfDataset API
      ds =
          acquire
              ? NetcdfDataset.acquireDataset(datasetLocation, enhanceMode, task)
              : NetcdfDataset.openDataset(datasetLocation, enhanceMode, task);
    }

    if (ds != null) {
      ds.setId(datasetId);
      ds.setTitle(title);
      annotate(invDataset, ds);
    }

    // see if there's metadata LOOK whats this
    List list = invDataset.getMetadata(MetadataType.NcML);
    if (list.size() > 0) {
      InvMetadata ncmlMetadata = (InvMetadata) list.get(0);
      NcMLReader.wrapNcML(ds, ncmlMetadata.getXlinkHref(), null);
    }

    result.accessUsed = access;
    return ds;
  }
  public ThreddsDataFactory.Result openFeatureDataset(
      FeatureType wantFeatureType,
      InvDataset invDataset,
      ucar.nc2.util.CancelTask task,
      Result result)
      throws IOException {

    result.featureType = invDataset.getDataType();
    if (result.featureType == null) result.featureType = wantFeatureType;

    // look for remote FeatureDataset
    if ((result.featureType != null) && result.featureType.isPointFeatureType()) {
      InvAccess access = findAccessByServiceType(invDataset.getAccess(), ServiceType.CdmrFeature);
      if (access != null) return openFeatureDataset(result.featureType, access, task, result);
    }

    // special handling for images
    if (result.featureType == FeatureType.IMAGE) {
      InvAccess access = getImageAccess(invDataset, task, result);
      if (access != null) {
        return openFeatureDataset(result.featureType, access, task, result);
      } else result.fatalError = true;
      return result;
    }

    // special handling for DQC
    InvAccess qc = invDataset.getAccess(ServiceType.QC);
    if (qc != null) {
      String dqc_location = qc.getStandardUrlName();

      if (result.featureType == FeatureType.STATION) {

        /* DqcFactory dqcFactory = new DqcFactory(true);
        QueryCapability dqc = dqcFactory.readXML(dqc_location);
        if (dqc.hasFatalError()) {
          result.errLog.append(dqc.getErrorMessages());
          result.fatalError = true;
        } */

        result.featureDataset =
            null; // LOOK FIX ucar.nc2.thredds.DqcStationObsDataset.factory(invDataset,
                  // dqc_location, result.errLog);
        result.fatalError = (result.featureDataset == null);

      } else {
        result.errLog.format("DQC must be station DQC, dataset = %s %n", invDataset.getName());
        result.fatalError = true;
      }

      return result;
    }

    NetcdfDataset ncd = openDataset(invDataset, true, task, result.errLog);
    if (null != ncd)
      result.featureDataset =
          FeatureDatasetFactoryManager.wrap(result.featureType, ncd, task, result.errLog);

    if (null == result.featureDataset) result.fatalError = true;
    else {
      result.location = result.featureDataset.getLocation();
      if ((result.featureType == null) && (result.featureDataset != null))
        result.featureType = result.featureDataset.getFeatureType();
    }

    return result;
  }