/**
   * Setup needed for all SingleTrajectoryObsDatatypes. Can only be called once.
   *
   * <p>Units of time varible must be udunits time units. Units of latitude variable must be
   * convertible to "degrees_north" by udunits. Units of longitude variable must be convertible to
   * "degrees_east" by udunits. Units of altitude variable must be convertible to "meters" by
   * udunits.
   *
   * @throws IllegalArgumentException if units of time, latitude, longitude, or altitude variables
   *     are not as required.
   * @throws IllegalStateException if this method has already been called.
   */
  public void setTrajectoryInfo(Config trajConfig) throws IOException {
    if (timeDim != null)
      throw new IllegalStateException("The setTrajectoryInfo() method can only be called once.");

    this.trajectoryId = trajConfig.getTrajectoryId();
    this.timeDim = trajConfig.getTimeDim();
    this.timeVar = trajConfig.getTimeVar();
    this.latVar = trajConfig.getLatVar();
    this.lonVar = trajConfig.getLonVar();
    this.elevVar = trajConfig.getElevVar();

    trajectoryNumPoint = this.timeDim.getLength();
    timeVarUnitsString = this.timeVar.findAttribute("units").getStringValue();

    // Check that time, lat, lon, elev units are acceptable.
    if (DateUnit.getStandardDate(timeVarUnitsString) == null) {
      throw new IllegalArgumentException(
          "Units of time variable <" + timeVarUnitsString + "> not a date unit.");
    }
    String latVarUnitsString = this.latVar.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(latVarUnitsString, "degrees_north")) {
      throw new IllegalArgumentException(
          "Units of lat var <" + latVarUnitsString + "> not compatible with \"degrees_north\".");
    }
    String lonVarUnitsString = this.lonVar.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(lonVarUnitsString, "degrees_east")) {
      throw new IllegalArgumentException(
          "Units of lon var <" + lonVarUnitsString + "> not compatible with \"degrees_east\".");
    }
    String elevVarUnitsString = this.elevVar.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(elevVarUnitsString, "meters")) {
      throw new IllegalArgumentException(
          "Units of elev var <" + elevVarUnitsString + "> not compatible with \"meters\".");
    }

    try {
      elevVarUnitsConversionFactor = getMetersConversionFactor(elevVarUnitsString);
    } catch (Exception e) {
      throw new IllegalArgumentException(
          "Exception on getMetersConversionFactor() for the units of elev var <"
              + elevVarUnitsString
              + ">.");
    }

    if (this.ncfile.hasUnlimitedDimension()
        && this.ncfile.getUnlimitedDimension().equals(timeDim)) {
      Object result = this.ncfile.sendIospMessage(NetcdfFile.IOSP_MESSAGE_ADD_RECORD_STRUCTURE);
      if ((result != null) && (Boolean) result)
        this.recordVar = (Structure) this.ncfile.getRootGroup().findVariable("record");
      else this.recordVar = new StructurePseudo(this.ncfile, null, "record", timeDim);
    } else {
      this.recordVar = new StructurePseudo(this.ncfile, null, "record", timeDim);
    }

    // @todo HACK, HACK, HACK - remove once addRecordStructure() deals with ncd attribute changes.
    Variable elevVarInRecVar = this.recordVar.findVariable(this.elevVar.getFullNameEscaped());
    if (!elevVarUnitsString.equals(elevVarInRecVar.findAttribute("units").getStringValue())) {
      elevVarInRecVar.addAttribute(new Attribute("units", elevVarUnitsString));
    }

    trajectoryVarsMap = new HashMap();
    // for ( Iterator it = this.recordVar.getVariables().iterator(); it.hasNext(); )
    for (Iterator it = this.ncfile.getRootGroup().getVariables().iterator(); it.hasNext(); ) {
      Variable curVar = (Variable) it.next();
      if (curVar.getRank() > 0
          && !curVar.equals(this.timeVar)
          && !curVar.equals(this.latVar)
          && !curVar.equals(this.lonVar)
          && !curVar.equals(this.elevVar)
          && (this.recordVar == null ? true : !curVar.equals(this.recordVar))) {
        MyTypedDataVariable typedVar = new MyTypedDataVariable(new VariableDS(null, curVar, true));
        dataVariables.add(typedVar);
        trajectoryVarsMap.put(typedVar.getShortName(), typedVar);
      }
    }

    trajectory =
        new SingleTrajectory(
            this.trajectoryId,
            trajectoryNumPoint,
            this.timeVar,
            timeVarUnitsString,
            this.latVar,
            this.lonVar,
            this.elevVar,
            dataVariables,
            trajectoryVarsMap);

    startDate = trajectory.getTime(0);
    endDate = trajectory.getTime(trajectoryNumPoint - 1);

    ((SingleTrajectory) trajectory).setStartDate(startDate);
    ((SingleTrajectory) trajectory).setEndDate(endDate);
  }
  public static boolean isValidFile(NetcdfDataset ds) {
    // Check that has a time dimension and a trajectory dimension.
    List list = ds.getRootGroup().getDimensions();
    if (list.size() != 2) return (false);
    Dimension d;
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }

    // Check that has a trajectory coordinate variable.
    Variable var = ds.getRootGroup().findVariable(trajVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 1) return (false);
    d = (Dimension) list.get(0);
    if (!d.getShortName().equals(trajDimNameDefault)) return (false);

    // Check that has a time coordinate variable with units that are udunits time
    var = ds.getRootGroup().findVariable(timeVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 1) return (false);
    d = (Dimension) list.get(0);
    if (!d.getShortName().equals(timeDimNameDefault)) return (false);
    String units = var.findAttribute("units").getStringValue();
    Date date = DateUnit.getStandardDate("0 " + units);
    if (date == null) return (false);

    // Check for variable latitude(time) with units of "deg".
    var = ds.getRootGroup().findVariable(latVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 2) return (false);
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }
    //    units = var.findAttribute( "units").getStringValue();
    //    if ( ! SimpleUnit.isCompatible( units, "degrees_north")) return( false);

    // Check for variable longitude(time) with units of "deg".
    var = ds.getRootGroup().findVariable(lonVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 2) return (false);
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }
    //    units = var.findAttribute( "units").getStringValue();
    //    if ( ! SimpleUnit.isCompatible( units, "degrees_east")) return( false);

    // Check for variable altitude(time) with units of "m".
    var = ds.getRootGroup().findVariable(elevVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 2) return (false);
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }
    units = var.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(units, "m")) return (false);

    return (true);
  }