/**
   * DO NOT USE DIRECTLY. public by accident. Calculate scale/offset/missing value info. This may
   * change the DataType.
   */
  public void enhance(Set<NetcdfDataset.Enhance> mode) {
    this.enhanceMode = EnumSet.copyOf(mode);
    boolean alreadyScaleOffsetMissing = false;
    boolean alreadyEnumConversion = false;

    // see if underlying variable has enhancements already applied
    if (orgVar != null && orgVar instanceof VariableDS) {
      VariableDS orgVarDS = (VariableDS) orgVar;
      EnumSet<NetcdfDataset.Enhance> orgEnhanceMode = orgVarDS.getEnhanceMode();
      if (orgEnhanceMode != null) {
        if (orgEnhanceMode.contains(NetcdfDataset.Enhance.ScaleMissing)) {
          alreadyScaleOffsetMissing = true;
          this.enhanceMode.add(
              NetcdfDataset.Enhance
                  .ScaleMissing); // Note: promote the enhancement to the wrapped variable
        }
        if (orgEnhanceMode.contains(NetcdfDataset.Enhance.ConvertEnums)) {
          alreadyEnumConversion = true;
          this.enhanceMode.add(
              NetcdfDataset.Enhance
                  .ConvertEnums); // Note: promote the enhancement to the wrapped variable
        }
      }
    }

    // do we need to calculate the ScaleMissing ?
    if (!alreadyScaleOffsetMissing
            && (dataType.isNumeric() || dataType == DataType.CHAR)
            && mode.contains(NetcdfDataset.Enhance.ScaleMissing)
        || mode.contains(NetcdfDataset.Enhance.ScaleMissingDefer)) {

      this.scaleMissingProxy = new EnhanceScaleMissingImpl(this);

      // promote the data type if ScaleMissing is set
      if (mode.contains(NetcdfDataset.Enhance.ScaleMissing)
          && scaleMissingProxy.hasScaleOffset()
          && (scaleMissingProxy.getConvertedDataType() != getDataType())) {
        setDataType(scaleMissingProxy.getConvertedDataType());
        removeAttributeIgnoreCase("_Unsigned");
      }

      // do we need to actually convert data ?
      needScaleOffsetMissing =
          mode.contains(NetcdfDataset.Enhance.ScaleMissing)
              && (scaleMissingProxy.hasScaleOffset() || scaleMissingProxy.getUseNaNs());
    }

    // do we need to do enum conversion ?
    if (!alreadyEnumConversion
        && mode.contains(NetcdfDataset.Enhance.ConvertEnums)
        && dataType.isEnum()) {
      this.needEnumConversion = true;

      // LOOK promote data type to STRING ????
      setDataType(DataType.STRING);
      removeAttributeIgnoreCase("_Unsigned");
    }
  }
 /**
  * public for debugging
  *
  * @param f put info here
  */
 public void showScaleMissingProxy(Formatter f) {
   f.format("use NaNs = %s%n", scaleMissingProxy.getUseNaNs());
   f.format("has missing = %s%n", scaleMissingProxy.hasMissing());
   if (scaleMissingProxy.hasMissing()) {
     Object mv = scaleMissingProxy.getFillValue(getDataType());
     String mvs =
         (mv instanceof String) ? (String) mv : java.lang.reflect.Array.get(mv, 0).toString();
     f.format(" missing data value = %s%n", mvs);
     f.format(" has missing value = %s%n", scaleMissingProxy.hasMissingValue());
     f.format(" has fill value = %s%n", scaleMissingProxy.hasFillValue());
     f.format(" has invalid value = %s%n", scaleMissingProxy.hasInvalidData());
     if (scaleMissingProxy.hasInvalidData())
       f.format(
           "   valid min/max = [%f,%f]%n",
           scaleMissingProxy.getValidMin(), scaleMissingProxy.getValidMax());
   }
   f.format("%nhas scale/offset = %s%n", scaleMissingProxy.hasScaleOffset());
   if (scaleMissingProxy.hasScaleOffset()) {
     double offset = scaleMissingProxy.convertScaleOffsetMissing(0.0);
     double scale = scaleMissingProxy.convertScaleOffsetMissing(1.0) - offset;
     f.format("   scale_factor = %f add_offset = %f%n", scale, offset);
   }
   f.format("original data type = %s%n", getDataType());
   f.format("converted data type = %s%n", scaleMissingProxy.getConvertedDataType());
 }
 /**
  * Return Array with missing data
  *
  * @param shape of this shape
  * @return Array with given shape
  */
 public Array getMissingDataArray(int[] shape) {
   Object data = scaleMissingProxy.getFillValue(getDataType());
   return Array.factoryConstant(dataType.getPrimitiveClassType(), shape, data);
 }
 public double convertScaleOffsetMissing(double value) {
   return scaleMissingProxy.convertScaleOffsetMissing(value);
 }
 public boolean getUseNaNs() {
   return scaleMissingProxy.getUseNaNs();
 }
 public void setUseNaNs(boolean useNaNs) {
   scaleMissingProxy.setUseNaNs(useNaNs);
 }
 public void setMissingDataIsMissing(boolean p0) {
   scaleMissingProxy.setMissingDataIsMissing(p0);
 }
 public void setFillValueIsMissing(boolean p0) {
   scaleMissingProxy.setFillValueIsMissing(p0);
 }
 public boolean isMissingValue(double p0) {
   return scaleMissingProxy.isMissingValue(p0);
 }
 public boolean isMissingFast(double val) {
   return scaleMissingProxy.isMissingFast(val);
 }
 public boolean isInvalidData(double p0) {
   return scaleMissingProxy.isInvalidData(p0);
 }
 public boolean hasScaleOffset() {
   return scaleMissingProxy.hasScaleOffset();
 }
 public boolean hasMissingValue() {
   return scaleMissingProxy.hasMissingValue();
 }
 public boolean hasInvalidData() {
   return scaleMissingProxy.hasInvalidData();
 }
 public double getValidMin() {
   return scaleMissingProxy.getValidMin();
 }
 // EnhanceScaleMissing interface
 public Array convertScaleOffsetMissing(Array data) {
   return scaleMissingProxy.convertScaleOffsetMissing(data);
 }