//
// DataUtility.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.util;

// General Java
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Comparator;
import java.util.Vector;
import java.util.StringTokenizer;

// RMI classes
import java.rmi.RemoteException;

import visad.java2d.DisplayImplJ2D;
import visad.java3d.DisplayImplJ3D;
import visad.java3d.TwoDDisplayRendererJ3D;

// GUI handling
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.*;

// VisAD packages
import visad.*;

/** A general utility class for VisAD Data objects */
public class DataUtility {

  private static boolean init = false;
  private static FunctionType simpleImageType;
  private static RealType radiance;
  private static RealTupleType imageDomain;
  private static RealType line;
  private static RealType element;

  private int num_lines, num_elements;

  private static synchronized void makeTypes()
          throws VisADException {
    if (!init) {
      init = true;
      simpleImageType = (FunctionType)
        MathType.stringToType("((ImageElement, ImageLine) -> ImageRadiance)");
      imageDomain = simpleImageType.getDomain();
      line = (RealType) imageDomain.getComponent(1);
      element = (RealType) imageDomain.getComponent(0);
      MathType range = simpleImageType.getRange();
      if (range instanceof RealType) {
        radiance = (RealType) range;
      }
      else {
        radiance = (RealType) ((RealTupleType) range).getComponent(0);
      }
    }
  }

  /** return a FlatField for a simple image from
      values[nlines][nelements] */
  public static FlatField makeImage(float[][] values)
         throws VisADException, RemoteException {
    if (values == null) return null;
    int nlines = values.length;
    int nelements = 0;
    for (int l=0; l nelements) nelements = values[l].length;
      }
    }
    if (!init) makeTypes();
    FlatField image = new FlatField(simpleImageType,
                new Integer2DSet(imageDomain, nelements, nlines));
    setPixels(image, values);
    return image;
  }

  /** set pixel values in a simple image,
      indexed as values[line][element] */
  public static void setPixels(FlatField image, float[][] values)
         throws VisADException, RemoteException {
    if (values == null) return;
    Integer2DSet set = (Integer2DSet) image.getDomainSet();
    int num_elements = set.getLength(0);
    int num_lines = set.getLength(1);
    float[][] vals = new float[1][num_lines * num_elements];
    for (int i=0; i= 0 && height >= 0)) break;
      try { Thread.sleep(100); } catch (InterruptedException e) { }
    }
    while (true);
    if (ih.badImage) throw new IOException("Not an image");

    // extract image pixels
    int numPixels = width * height;
    int[] words = new int[numPixels];

    PixelGrabber grabber = new PixelGrabber(
      image.getSource(), 0, 0, width, height, words, 0, width);

    try { grabber.grabPixels(); }
    catch (InterruptedException e) { }

    ColorModel cm = grabber.getColorModel();
    boolean doAlpha = cm.hasAlpha() && withAlpha;
    //System.out.println("do alpha: " + doAlpha);

    float[] red_pix = new float[numPixels];
    float[] green_pix = new float[numPixels];
    float[] blue_pix = new float[numPixels];
    float[] alpha_pix = null;

    for (int i=0; i((x, y) -> (r, g, b))
   * to an AWT Image. If reverse flag is set, image will be upside-down.
   */
  public static Image extractImage(FlatField field, boolean reverse) {
    try {
      GriddedSet set = (GriddedSet) field.getDomainSet();
      int[] wh = set.getLengths();
      int w = wh[0];
      int h = wh[1];
      double[][] samples = field.getValues();
      int[] pixels = new int[samples[0].length];
      if (samples.length == 3) {
        int len = samples[0].length;
        for (int i=0; itype.
   *                            If type is a RealTupleType, then
   *                            it is returned; otherwise, if type
   *                            is a RealType, then a RealTupleType
   *                            containing type as the
   *                            only component is returned; otherwise,
   *                            if type is a SetType, then
   *                            ((SetType)type).getDomain() is
   *                            returned.
   * @throws TypeException	type is the wrong type: it can't
   *				be converted into a RealTupleType.
   * @throws VisADException	Couldn't create necessary VisAD object.
   */
  public static RealTupleType
  ensureRealTupleType(MathType type)
    throws TypeException, VisADException
  {
    RealTupleType	result;
    if (type instanceof RealTupleType)
      result = (RealTupleType)type;
    else if (type instanceof RealType)
      result = new RealTupleType((RealType)type);
    else if (type instanceof SetType)
      result = ((SetType)type).getDomain();
    else
      throw new TypeException(
	DataUtility.class.getName() +
	".ensureRealTupleType(MathType): Can't convert MathType \"" +
	type + "\" into a RealTupleType");
    return result;
  }

  /**
   * Ensures that a MathType is a TupleType.  Converts if necessary.
   * @param type		The math type to be "converted" to a TupleType.
   * @return                    The TupleType version of type.
   *                            If type is a TupleType,
   *                            then it is returned; otherwise, if
   *                            type is a SetType, then
   *                            ((SetType)type).getDomain() is
   *                            returned; otherwise, a TupleType containing
   *                            type as the only component is
   *                            returned (if type is a RealType,
   *                            then the returned TupleType is a RealTupleType);
   * @throws VisADException	Couldn't create necessary VisAD object.
   */
  public static TupleType
  ensureTupleType(MathType type)
    throws VisADException
  {
    return
      type instanceof TupleType
	? (TupleType)type
	: type instanceof SetType
	  ? ((SetType)type).getDomain()		// actually a RealTupleType
	  : type instanceof RealType
	    ? new RealTupleType((RealType)type)
	    : new TupleType(new MathType[] {type});
  }

  /**
   * Ensures that a Data is a Tuple.  Creates a Tuple if necessary.
   * @param datum		The math type to be "converted" to a Tuple.
   * @return                    The Tuple version of datum.  If
   *                            datum is a Tuple, then it is
   *                            returned; otherwise, if datum is
   *                            a Real, then a RealTuple containing 
   *                            datum as the only component is returned;
   *                            otherwise, a Tuple containing datum
   *                            as the only component is returned.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static TupleIface
  ensureTuple(Data datum)
    throws VisADException, RemoteException
  {
    return
      datum instanceof TupleIface
	? (TupleIface)datum
	: datum instanceof Real
	    ? new RealTuple(new Real[] {(Real)datum})
	    : new Tuple(new Data[] {datum});
  }

  /**
   * Gets the MathType of the domain of a Set.
   * @param set			A set.
   * @return			The MathType of the domain of the Set.
   */
  public static RealTupleType
  getDomainType(Set set)
  {
    return ((SetType)set.getType()).getDomain();
  }

  /**
   * Gets the MathType of the domain of a Function.
   * @param function		A function.
   * @return			The MathType of the domain of the function.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static RealTupleType
  getDomainType(Function function)
    throws VisADException, RemoteException
  {
    return ((FunctionType)function.getType()).getDomain();
  }

  /**
   * Gets the MathType of the range of a Function.
   * @param function		A function.
   * @return			The MathType of the range of the function.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static MathType
  getRangeType(Function function)
    throws VisADException, RemoteException
  {
    return ((FunctionType)function.getType()).getRange();
  }

  /**
   * Gets the TupleType of the range of a Function.
   * @param function		A function.
   * @return			The TupleType of the range of the function.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static TupleType
  getRangeTupleType(Function function)
    throws VisADException, RemoteException
  {
    return ensureTupleType(getRangeType(function));
  }

  /**
   * Gets the MathType of the flat-range of a Function.
   * @param function		A function.
   * @return			The MathType of the flat-range of the function.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static RealTupleType
  getFlatRangeType(Function function)
    throws VisADException, RemoteException
  {
    return ((FunctionType)function.getType()).getFlatRange();
  }

  /**
   * Gets the number of components in the range of a Function.  NB: This differs
   * from visad.FlatField.getRangeDimension() in that it returns the number of
   * components in the actual range rather than the number of components in the
   * flat range.
   * @param function		A function.
   * @return			The number of components in the range of the
   *				function.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static int
  getRangeDimension(Function function)
    throws VisADException, RemoteException
  {
    return getRangeTupleType(function).getDimension();
  }

  /**
   * Gets the index of a component in a TupleType.  If the TupleType
   * contains multiple instances of the component, then it is unspecified
   * which component index is returned.  This method first looks for an
   * exact match via the equals(Object) method.  If none is
   * found, then this method looks for an approximate match based on the
   * equalsExceptNameButUnits(MathType) method.
   * @param tupleType		The type of the tuple.
   * @param componentType	The MathType of the component.
   * @return                    The index of the component in the tuple
   *                            or -1 if the component is not in the tuple.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static int
  getComponentIndex(TupleType tupleType, MathType componentType)
    throws VisADException, RemoteException
  {
    /*
     * Return first exact match if found.
     */
    for (int i = tupleType.getDimension(); --i >= 0; )
      if (componentType.equals(tupleType.getComponent(i)))
	return i;
    /*
     * Return the first convertible-units match if found.
     */
    for (int i = tupleType.getDimension(); --i >= 0; )
      if (componentType.equalsExceptNameButUnits(tupleType.getComponent(i)))
	return i;
    return -1;
  }

  /**
   * Gets the index of a component in a Set.  If the set contains multiple
   * instances of the component, then it is unspecified which component index is
   * returned.
   * @param set			The Set.
   * @param componentType	The MathType of the component.
   * @return			The index of the component in the set or -1 if
   *				the component is not in the set.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static int
  getComponentIndex(Set set, MathType componentType)
    throws VisADException, RemoteException
  {
    return
      getComponentIndex(((SetType)set.getType()).getDomain(), componentType);
  }

  /**
   * Gets the index of a component in the range of a Function.  If the range
   * contains multiple instances of the component, then it is unspecified
   * which component index is returned.
   * @param function		The Function.
   * @param componentType	The MathType of the component.
   * @return                    The index of the component in the range of the
   *                            field or -1 if the component is not in the range
   *                            of the field (NB: this is not the flat-range
   *                            index).
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static int
  getComponentIndex(Function function, MathType componentType)
    throws VisADException, RemoteException
  {
    return getComponentIndex(getRangeTupleType(function), componentType);
  }

  /**
   * Ensures that the range of a Field is a given type.  Extracts from
   * the input field only if necessary.
   * @param field		The input field.
   * @param newRangeType	The desired type of range for the resulting
   *				field.
   * @return			A field with the desired range type.  The range
   *				data will be missing, however, if all
   *				of it couldn't be extracted from the input
   *				Field (i.e.
   *				RETURN_VALUE.isMissing() will be
   *				true.
   * @throws UnimplementedException
   *				The desired range type is a TupleType and not
   *				a RealTupleType.
   * @throws TypeException	The new range type cannot be the range of a
   *				field.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static Field
  ensureRange(Field field, MathType newRangeType)
    throws UnimplementedException, TypeException, VisADException,
      RemoteException
  {
    Field	result;
    if (newRangeType.equals(getRangeType(field)))
    {
      result = field;
    }
    else if (newRangeType instanceof RealType)
    {
      int	componentIndex = getComponentIndex(field, newRangeType);
      if (componentIndex >= 0)
      {
	result = field.extract(componentIndex);
      }
      else
      {
	result =
	  new FlatField(
	    new FunctionType(getDomainType(field), newRangeType),
	    field.getDomainSet());
      }
    }
    else if (newRangeType instanceof RealTupleType)
    {
      int	realTupleIndex = getComponentIndex(field, newRangeType);
      if (realTupleIndex >= 0)
      {
	/*
	 * The desired RealTuple range is a component of the input Field.
	 */
	result = (FlatField)field.extract(realTupleIndex);
      }
      else
      {
	/*
	 * The desired RealTuple range is not a component of the input Field.
	 * Extract each component of the desired RealTuple into a separate
	 * Field and then combine the Field-s.
	 */
	RealTupleType	newRangeRealTupleType = (RealTupleType)newRangeType;
	int		componentCount = newRangeRealTupleType.getDimension();
	ArrayList	flatFields = new ArrayList(componentCount);
	for (int i = 0; i < componentCount; ++i)
	{
	  int	componentIndex =
	    getComponentIndex(field, newRangeRealTupleType.getComponent(i));
	  if (componentIndex >= 0)
	    flatFields.add(field.extract(componentIndex));
	}
	if (flatFields.size() != componentCount)
	{
	  /* Not all desired components exist in the range of the input Field */
	  result =
	    new FlatField(
	      new FunctionType(getDomainType(field), newRangeType),
	      field.getDomainSet());
	}
	else
	{
	  /* All desired components exist in the range of the input Field */
	  result =
	    (FlatField)FieldImpl.combine(
	      (FlatField[])flatFields.toArray(new FlatField[componentCount]));
	}
      }
    }
    else if (newRangeType instanceof TupleType)
    {
      throw new UnimplementedException(
	"Can't yet create Field with range " + newRangeType +
	" from existing Field");
    }
    else
    {
      throw new TypeException("Can't create Field with range " + newRangeType);
    }
    return result;
  }

  /**
   * Provides support for comparing RealTuple-s of the same RealTupleType.
   *
   * @author Steven R. Emmerson
   */
  public static final class
  RealTupleComparator
    implements Comparator
  {
    /**
     * The single instance.
     */
    public static final RealTupleComparator	INSTANCE =
      new RealTupleComparator();

    /**
     * Constructs from nothing.
     */
    private
    RealTupleComparator()
    {}

    /**
     * Compares two RealTuple-s of the same RealTupleType.
     *
     * @param obj1		The first RealTuple.
     * @param obj2		The second RealTuple.  It shall have the same
     *				RealTupleType as the first RealTuple.
     * @return			A negative integer, zero, or a positive integer
     *				as the first RealTuple is less than, equal to,
     *				or greater than the second RealTuple.
     * @throws ClassCastException
     *                          The types of the arguments prevent this
     *                          comparator from comparing them.
     */
    public int
    compare(Object obj1, Object obj2)
      throws ClassCastException
    {
      RealTuple	realTuple1 = (RealTuple)obj1;
      RealTuple	realTuple2 = (RealTuple)obj2;
      try
      {
	int	rank = realTuple1.getDimension();
	int	comp = 0;
	/*
	 * Because Set rasterization has the last component as the outermost
	 * dimension, the last tuple component is treated as the grossest one
	 * for the purpose of comparison.  Hence, components are compared in
	 * decreasing order.
	 */
	for (int i = rank; --i >= 0 && comp == 0; )
	  comp = ((Real)realTuple1.getComponent(i)).compareTo(
	    ((Real)realTuple2.getComponent(i)));
	return comp;
      }
      catch (Exception e)
      {
	/*
	 * This is the only checked exception a Comparator is allowed to throw.
	 * The original exception could be either a visad.VisADException or a
	 * java.rmi.RemoteException.
	 */
	String	reason = e.getMessage();
	throw new ClassCastException("Can't compare RealTuple-s" +
	  (reason == null ? "" : ": " + reason));
      }
    }
  }

  /**
   * Provides support for comparing domain points that are reference to a
   * particular Field.
   */
  private static class
  ReferencedDomainPoint
    implements Comparable
  {
    protected final RealTuple	sample;
    protected final Field	field;
    public ReferencedDomainPoint(RealTuple sample, Field field)
    {
      this.sample = sample;
      this.field = field;
    }
    public int compareTo(Object obj)
    {
      return
	RealTupleComparator.INSTANCE.compare(
	  sample, ((ReferencedDomainPoint)obj).sample);
    }
  }

  /**
   * Consolidates fields.
   * @param fields		The fields to consolidate.  Each field shall
   *				have the same FunctionType.
   * @return                    The input Fields consolidated into one Field.
   *                            The domain shall be a GriddedSet comprising the
   *                            union of the sample points of the fields.  The
   *                            FunctionType shall be the same as that of the
   *                            input Field-s.  When more than one input Field
   *                            has valid range data for the same domain point,
   *                            it is unspecified which range datum is used for
   *                            the output Field.
   * @throws FieldException	The Field array has zero length.
   * @throws TypeException	Input Field-s not all same type.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static Field
  consolidate(Field[] fields)
    throws FieldException, TypeException, VisADException, RemoteException
  {
    /*
     * Identify valid fields.
     */
    ArrayList	validFields = new ArrayList(fields.length);
    for (int i = 0; i < fields.length; ++i)
    {
      Field	field = fields[i];
      if (!field.isMissing())
	validFields.add(field);
    }
    if (validFields.size() == 0)
      throw new FieldException(
	DataUtility.class.getName() + "(Field[]): Zero fields to consolidate");

    /*
     * Determine the consolidated domain.
     */
    FunctionType		funcType = (FunctionType)fields[0].getType();
    TreeSet	consolidatedDomainTuples = new TreeSet();
    for (Iterator iter = validFields.iterator(); iter.hasNext(); )
    {
      Field	field = (Field)iter.next();
      if (!field.getType().equals(funcType))
	throw new TypeException("Field type mismatch");
      for (Enumeration en = field.domainEnumeration();
	  en.hasMoreElements(); )
      {
	consolidatedDomainTuples.add(
	  new ReferencedDomainPoint((RealTuple)en.nextElement(), field));
      }
    }

    /*
     * Create the consolidated field (with no range data).
     */
    Field	field = fields[0];
    float[][]	domainFloats =
      new float[field.getDomainDimension()][consolidatedDomainTuples.size()];
    Unit[]	domainUnits = field.getDomainUnits();
    int		sampleIndex = 0;
    for (Iterator iter = consolidatedDomainTuples.iterator();
	iter.hasNext();
	++sampleIndex)
    {
      RealTuple	domainTuple = ((ReferencedDomainPoint)iter.next()).sample;
      for (int i = domainFloats.length; --i >= 0; )
	domainFloats[i][sampleIndex] =
	  (float)((Real)domainTuple.getComponent(i)).getValue(domainUnits[i]);
    }
    SampledSet	consolidatedDomain =
      domainFloats.length == 1
	? (SampledSet)new Gridded1DSet(
	    getDomainType(field), domainFloats, domainFloats[0].length,
	    (CoordinateSystem)null, field.getDomainUnits(),
	    (ErrorEstimate[])null)
	: domainFloats.length == 2
	  ? (SampledSet)new Irregular2DSet(
	      getDomainType(field), domainFloats, (CoordinateSystem)null,
	      field.getDomainUnits(), (ErrorEstimate[])null, (Delaunay)null)
	  : domainFloats.length == 3
	    ? (SampledSet)new Irregular3DSet(
		getDomainType(field), domainFloats, (CoordinateSystem)null,
		field.getDomainUnits(), (ErrorEstimate[])null, (Delaunay)null)
	    : (SampledSet)new IrregularSet(
		getDomainType(field), domainFloats, (CoordinateSystem)null,
		field.getDomainUnits(), (ErrorEstimate[])null);
    Field	consolidatedField =
      field instanceof FlatField
	? new FlatField(funcType, consolidatedDomain)
	: new FieldImpl(funcType, consolidatedDomain);

    /*
     * Set the range of the consolidated field.
     */
    for (Iterator iter = consolidatedDomainTuples.iterator(); iter.hasNext(); )
    {
      ReferencedDomainPoint	point = (ReferencedDomainPoint)iter.next();
      RealTuple			domainTuple = point.sample;
      consolidatedField.setSample(
	domainTuple, point.field.evaluate(domainTuple));
    }

    return consolidatedField;
  }

  /**
   * Creates a GriddedSet from a FlatField.  The GriddedSet will be created from
   * the domain and flat-range of the FlatField.  The first components in the
   * tuples of the GriddedSet will come from the domain of the FlatField and the
   * remaining components will come from the range of the FlatField.  Note that,
   * because a GriddedSet doesn't have the ability to contain values in small
   * primitives (e.g. byte, short), the returned set may be significantly larger
   * than the input field.
   * @param field		The FlatField from which to create a GriddedSet.
   * @param copy		Whether or not to copy the range values from
   *				the field (i.e. field.getFloats(copy)
   *				).
   * @return			The GriddedSet corresponding to the input
   *				FlatField.
   * @throws VisADException	Couldn't create necessary VisAD object.
   * @throws RemoteException	Java RMI failure.
   */
  public static GriddedSet
  createGriddedSet(FlatField field, boolean copy)
    throws VisADException, RemoteException
  {
    int			domainRank = field.getDomainDimension();
    int			flatRangeRank = field.getRangeDimension();
    RealType[]		realTypes = new RealType[domainRank + flatRangeRank];
    RealTupleType	tupleType = getDomainType(field);
    for (int i = 0; i < domainRank; i++)
      realTypes[i] = (RealType)tupleType.getComponent(i);
    tupleType = getFlatRangeType(field);
    for (int i = 0; i < flatRangeRank; i++)
      realTypes[domainRank+i] = (RealType)tupleType.getComponent(i);
    float[][]	samples = new float[realTypes.length][field.getLength()];
    /*
     * The following gets the domain values in their actual units.
     */
    System.arraycopy(
      field.getDomainSet().getSamples(), 0, samples, 0, domainRank);
    /*
     * The following gets the range values in their default units.
     */
    System.arraycopy(
      field.getFloats(copy), 0, samples, domainRank, flatRangeRank);
    int[]		lengths = new int[samples.length];
    for (int i = samples.length; --i >= 0; )
      lengths[i] = samples[i].length;
    Unit[]		units = new Unit[realTypes.length];
    System.arraycopy(field.getDomainUnits(), 0, units, 0, domainRank);
    System.arraycopy(
      field.getDefaultRangeUnits(), 0, units, domainRank, flatRangeRank);
    return
      GriddedSet.create(
	new RealTupleType(realTypes),
	samples,
	lengths,
	(CoordinateSystem)null,
	units,
	(ErrorEstimate[])null);
  }

  /**
   * Simplifies a MathType.  Removes all enclosing, single-component TupleType-s
   * until the "core" is revealed (e.g. ScalarType, multi-component TupleType).
   * @param type		The MathType to be simplified.
   * @return			The simplest form corresponding to
   *				type.
   * @throws VisADException	Couldn't create necessary VisAD object.
   */
  public static MathType simplify(MathType type)
    throws VisADException
  {
    while (type instanceof TupleType && ((TupleType)type).getDimension() == 1)
	type = ((TupleType)type).getComponent(0);
    return type;
  }

  /**
   * @deprecated Use getScalarTypes(Data, Vector) instead.
   */
  public static int getRealTypes(Data data, Vector v)
    throws VisADException, RemoteException
  {
    return getRealTypes(new Data[] {data}, v, true, false);
  }

  /**
   * @deprecated Use getScalarTypes(Data[], Vector, boolean, boolean) instead.
   */
  public static int getRealTypes(Data[] data, Vector v, boolean keepDupl,
    boolean doCoordSys) throws VisADException, RemoteException
  {
    int dupl = getScalarTypes(data, v, keepDupl, doCoordSys);
    int i = 0;
    while (i < v.size()) {
      ScalarType st = (ScalarType) v.elementAt(i);
      if (!(st instanceof RealType)) v.remove(i);
      else i++;
    }
    return dupl;
  }

  /**
   * Obtains a Vector consisting of all ScalarTypes present in a Data object's
   * MathType.
   * @param data                The Data from which to extract the ScalarTypes.
   * @param v                   The Vector in which to store the ScalarTypes.
   * @throws VisADException     Couldn't parse the Data's MathType.
   * @throws RemoteException    Couldn't obtain the remote Data's MathType.
   * @return                    The number of duplicate ScalarTypes found.
   */
  public static int getScalarTypes(Data data, Vector v)
    throws VisADException, RemoteException
  {
    return getScalarTypes(new Data[] {data}, v, true, false);
  }

  /**
   * Obtains a Vector consisting of all ScalarTypes present in an array of
   * Data objects' MathTypes.
   * @param data                The array of Data from which to extract the
   *                            ScalarTypes.
   * @param v                   The Vector in which to store the ScalarTypes.
   * @param keepDupl            Whether to add a RealType to the Vector when
   *                            it is already present there.
   * @param doCoordSys          Whether to include ScalarTypes from
   *                            CoordinateSystem references.
   * @throws VisADException     Couldn't parse a Data's MathType.
   * @throws RemoteException    Couldn't obtain a remote Data's MathType.
   * @return                    The number of duplicate ScalarTypes found.
   */
  public static int getScalarTypes(Data[] data, Vector v, boolean keepDupl,
    boolean doCoordSys) throws VisADException, RemoteException
  {
    Vector coord = (doCoordSys ? new Vector() : null);
    int[] dupl = new int[1];
    dupl[0] = 0;
    for (int i=0; i 0) {
        int vLen = types.size();
        int dLen = Display.DisplayRealArray.length;

        // construct ScalarMaps
        ScalarMap[] maps = new ScalarMap[len];
        for (int j=0; j= 0 && q < dLen) mapRange = Display.DisplayRealArray[q];

          // construct mapping
          if (mapDomain == null || mapRange == null) {
            if (showErrors) {
              System.err.print("Warning: maps pair (" + name + ", " +
                q + ") has an invalid ");
              if (mapDomain == null && mapRange == null) {
                System.err.print("domain and range");
              }
              else if (mapDomain == null) System.err.print("domain");
              else System.err.print("range");
              System.err.println(" and will be ignored");
            }
            maps[j] = null;
          }
          else {
            try {
              maps[j] = new ScalarMap(mapDomain, mapRange);
            }
            catch (VisADException exc) {
              if (showErrors) {
                System.err.println("Warning: maps pair (" + name + ", " +
                  q + ") cannot be converted to a ScalarMap");
              }
              maps[j] = null;
            }
          }
        }
        return maps;
      }
    }

    return null;
  }

  /**
   * Converts an array of strings into a VisAD Tuple.
   *
   * @param s The array of strings to be converted to a VisAD Tuple.
   *
   * @return VisAD Tuple, or null if Tuple could not be created.
   */
  public static Tuple stringsToTuple(String[] s) {
    return stringsToTuple(s, false);
  }

  /**
   * Converts an array of strings into a VisAD Tuple.
   *
   * @param s The array of strings to be converted to a VisAD Tuple.
   * @param printStackTraces true if the stack trace for
   *                         any exception should be printed.
   *
   * @return VisAD Tuple, or null if Tuple could not be created.
   */
  public static Tuple stringsToTuple(String[] s, boolean printStackTraces) {
    try {
      if (s == null) return null;
      int len = s.length;
      if (len == 0) return null;
      Text[] text = new Text[len];
      for (int i=0; itrue if the stack trace for
   *                         any exception should be printed.
   *
   * @return Array of Strings, or null if array could not be created.
   */
  public static String[] tupleToStrings(Tuple t, boolean printStackTraces) {
    if (t == null) return null;
    int len = t.getDimension();
    try {
      String[] errors = new String[len];
      for (int i=0; itrue if the object is Serializable, false otherwise.
   */
  public static boolean isSerializable(Object obj) {
    return isSerializable(obj, false);
  }

  /**
   * Verify that an object is Serializable by attempting to
   * serialize it.
   *
   * @param obj An object which needs to be serialized
   * @param printStackTraces true if the stack trace for
   *                         any exception should be printed.
   *
   * @return true if the object is Serializable, false otherwise.
   */
  public static boolean isSerializable(Object obj, boolean printStackTraces)
  {
    java.io.ByteArrayOutputStream outBytes;
    outBytes = new java.io.ByteArrayOutputStream();

    java.io.ObjectOutputStream outStream;
    try {
      outStream = new java.io.ObjectOutputStream(outBytes);
    } catch (java.io.IOException ioe) {
      if (printStackTraces) ioe.printStackTrace();
      return false;
    }

    try {
      outStream.writeObject(obj);
      outStream.flush();
    } catch (java.io.IOException ioe) {
      if (printStackTraces) ioe.printStackTrace();
      return false;
    }

    java.io.ByteArrayInputStream inBytes;
    inBytes = new java.io.ByteArrayInputStream(outBytes.toByteArray());

    try {
      outStream.close();
      outBytes.close();
    } catch (java.io.IOException ioe) {
      if (printStackTraces) ioe.printStackTrace();
      return false;
    }

    java.io.ObjectInputStream inStream;
    try {
      inStream = new java.io.ObjectInputStream(inBytes);
    } catch (java.io.IOException ioe) {
      if (printStackTraces) ioe.printStackTrace();
      return false;
    }

    Object obj2;
    try {
      obj2 = inStream.readObject();
    } catch (java.io.IOException ioe) {
      if (printStackTraces) ioe.printStackTrace();
      return false;
    } catch (ClassNotFoundException cnfe) {
      if (printStackTraces) cnfe.printStackTrace();
      return false;
    }

    try {
      inStream.close();
      inBytes.close();
    } catch (java.io.IOException ioe) {
      if (printStackTraces) ioe.printStackTrace();
      return false;
    }

    return true;
  }

  /**
   * Converts a remote Data object to a local Data object.
   *
   * @param data The Data object to be made local.
   *
   * @return Local Data object, or null if Data could not be converted.
   */
  public static DataImpl makeLocal(Data data) {
    return makeLocal(data, false);
  }

  /**
   * Converts a remote Data object to a local Data object.
   *
   * @param data The Data object to be made local.
   * @param printStackTraces true if the stack trace for
   *                         any exception should be printed.
   *
   * @return Local Data object, or null if Data could not be converted.
   */
  public static DataImpl makeLocal(Data data, boolean printStackTraces) {
    try {
      if (data != null) return data.local();
    }
    catch (VisADException exc) {
      if (printStackTraces) exc.printStackTrace();
    }
    catch (RemoteException exc) {
      if (printStackTraces) exc.printStackTrace();
    }
    return null;
  }

  /**
   * Gets the specified sample of a VisAD Set.
   *
   * @param set               The set to have a sample returned.
   * @param index             The index of the sample to be returned.
   * @return                  The sample at the specified index.  Will
   *                          be empty if the index is out-of-bounds.
   *                          Will have a single component if the set is
   *                          one-dimensional.
   * @throws VisADException   Couldn't create necessary VisAD object.
   * @throws RemoteException  Java RMI failure.
   */
  public static RealTuple getSample(Set set, int index)
          throws VisADException, RemoteException {

    RealTuple     sample;
    RealTupleType realTupleType = ((SetType) set.getType()).getDomain();
    double[][]    values        =
      Unit.convertTuple(set.indexToDouble(new int[]{ index }),
                        set.getSetUnits(),
                        realTupleType.getDefaultUnits());

    if ((index < 0) || (index >= set.getLength())) {
      sample = new RealTuple(realTupleType);
    } else {
      double[] doubles = new double[values.length];

      for (int i = doubles.length; --i >= 0; ) {
        doubles[i] = values[i][0];
      }

      sample = new RealTuple(realTupleType, doubles);
    }

    return sample;
  }

  /**
   * Gets the units of the (flat) components of the range of a FlatField.
   *
   * @param field             The FlatField.
   * @return                  The units of the (flat) components of the
   *                          range of the FlatField.  Won't be
   *                          null.
   */
  public static Unit[] getRangeUnits(FlatField field) {

      Unit[][] units  = field.getRangeUnits();
      Unit[]   result = new Unit[units.length];

      for (int i = result.length; --i >= 0; ) {
          result[i] = units[i][0];
      }

      return result;
  }

  /**
   * Make a RealType with a unique name for the given unit
   *
   * @param name name of the RealType
   * @param unit  the default unit
   *
   * @return  the RealType 
   *
   * @throws VisADException  problem creating the RealType
   */
  public static RealType getUniqueRealType(String name, Unit unit) {
      return getUniqueRealType(name, unit, null, 0);
  }

  /**
   * Make a RealType with a unique name for the given unit
   *
   * @param name name of the RealType
   * @param unit  the default unit
   * @param set  the default set
   * @param attrMask  the attribute mask
   *
   * @return  the RealType  or null if it still can't create a unique name
   */
  public static RealType getUniqueRealType(String name, Unit unit, 
                                           Set set, int attrMask)  {
    RealType type    = RealType.getRealType(name, unit, set, attrMask);
    if (type == null) {
      String  newname = cleanTypeName(name) + "[unit:" + ((unit == null)
              ? "null"
              : cleanTypeName(unit.toString())) + "]";

      type = RealType.getRealType(newname, unit, set, attrMask);
    }
    return type;
  }  

  /**
   * Make a valid VisAD RealType name from the string.  Remove
   * spaces, "." and parens.
   * @param name name to clean
   * @return cleaned up name
   */
  public static String cleanTypeName(String name) {
    name = name.replace('.', '_');
    name = name.replace(",","_");
    name = name.replace("-","_");  // so doesn't get confused with ->
    name = name.replace("*","_");  // so it doesn't confuse regexes
    name = name.replace(' ', '_');
    name = name.replace('(', '[');
    name = name.replace(')', ']');
    while(name.indexOf("__")>=0) {
      name = name.replace("__","_");
    }
    return name;
  }
}

 

Ads help maintain this website.