// $Id: Variable.java,v 1.1.1.1 2025/09/11 12:24:45 mhliu Exp $
/*
 * Copyright 1996-2014 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gsfc.nssdc.cdf;

import java.util.*;
import java.lang.*;
import java.io.*;

import gsfc.nssdc.cdf.util.*;

/** 
 * The <B>Variable</B> class defines a CDF variable.<BR><BR>
 * <B>Notes:</B>
 * Since the CDF JavaAPI always uses <CODE>zMODE = 2</CODE>, all variables 
 * are by default, zVariables.
 *
 * @version 1.0
 * @version 2.0 03/18/05  Selection of current CDF and variable are done as
 *                        part of operations passed to JNI.
 *                        JNI call is synchronized so only one process is
 *                        allowed in a JVM, due to multi-thread safety.
 *                        The select method will never be called.
 * @author Phil Williams, QSS Group Inc/RITSS <BR>
 *         Mike Liu, RSTX
 *
 * @see gsfc.nssdc.cdf.Attribute
 * @see gsfc.nssdc.cdf.Entry
 */
public class Variable extends Object implements CDFObject, CDFConstants {
    
    private CDF myCDF;

    /**
     * The variable name
     */
    private String  name           = null;

    private long id;
    private long cdfID;
    /**
     * The compression type for this variable
     */
    private long    cType, cTypeX;

    /**
     * The compression percentage
     */
    private long    cPct;

    /**
     * The compression parameters
     */
    private long[]    cParms       = new long[1];
    private long[]    cParmsX      = new long[1];

    /**
     * The CDF data type
     */
    private long    dataType;
    private long    xdataType;   // a temp one

    /**
     * The number of dimensions
     */
    private long    numDims;

    /**
     * The number of elements
     */
    private long    numElements;
    private long    xnumElements;   // a temp one

    /**
     * The sizes of the dimensions
     */
    private long[]    dimSizes;

    /**
     * The variances for each dimension
     */
    private long[]    dimVariances, dimVariancesX;

    /**
     * The max rec for this variable
     */
    private long    maxRec;

    /**
     * The variable value data
     */
    private Object    data = null;

    /**
     * Since the data is a generic object and is set on-the-fly, this holds
     * the actual signature of the data object.  This is used in
     * getArgument within cdfNativeLibrary.c
     */
    private String dataSignature;

    /**
     * The record number
     */
    private long    recNum;

    /**
     * The record counts for hyper function
     */
    private long    recCount;

    /**
     * The record interval for hyper function
     */
    private long    recInterval;

    /**
     * The dimensional counts for hyper function
     */
    private long[]  dimCounts;

    /**
     * The dimensional indices for hyper function
     */
    private long[]  dimIndices;

    /**
     * The dimensional intervals for hyper function
     */
    private long[]  dimIntervals;

    private long    num0toRecords;   // the last record number to allocate,
				     // beginning from record 0 
    private long    numRecords;         // number of records written
    private long    numAllocRecords;    // number of records allocated
    private long    maxAllocRecord;     // maximum allocated record number 
    private long    nRecords;           // number of records initially written
    private Object  padValue       = null;
    private Object  padValueX      = null;
    private long    sparseRecords, sparseRecordsX;
    private long    recVariance, recVarianceX;
    private long    blockingFactor, blockingFactorX;
    private long    cacheSize;
    private long    reservePercent;
    private long    firstRec, lastRec;

    /**
     * Constructor for a CDF object.  It's called when a CDF object is
     * created or opened.
     *
     * @param myCDF The CDF object to be created or opened
     */
    private Variable(CDF myCDF) {

	this.myCDF = myCDF;
    }

    /**
     * Retrieve the information associated with a variable. 
     *
     * @param myCDF The current CDF to which this variable belongs. 
     * @param id The variable id from which information is retrieved <P>
     *
     * @throws CDFException If the variable of the given id does not exit.
     *
     */
    protected final static Variable retrieve(CDF myCDF, long id)
	throws CDFException
    {

synchronized(myCDF) {
	Variable v = new Variable(myCDF);
	v.id = id;

	Vector cmds = new Vector();
	Vector item0 = new Vector();
	Vector item1 = new Vector();
	Vector item2 = new Vector();
	Vector item3 = new Vector();
	Vector item4 = new Vector();
	Vector item5 = new Vector();
	Vector item6 = new Vector();
	Vector item7 = new Vector();
	Vector item8 = new Vector();
	Vector item9 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
	  cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);
	
	cmds.addElement(Long.valueOf(GET_));
	  cmds.addElement(Long.valueOf(zVAR_NAME_));
	    item0.addElement("name");
	    item0.addElement("Ljava/lang/String;");
	  cmds.addElement(item0);
	  cmds.addElement(Long.valueOf(zVAR_NUMELEMS_));
	    item1.addElement("numElements");
	    item1.addElement("J");
	  cmds.addElement(item1);
	  cmds.addElement(Long.valueOf(zVAR_DATATYPE_));
	    item2.addElement("dataType");
	    item2.addElement("J");
	  cmds.addElement(item2);
	  cmds.addElement(Long.valueOf(zVAR_NUMDIMS_));
	    item3.addElement("numDims");
	    item3.addElement("J");
	  cmds.addElement(item3);
	  cmds.addElement(Long.valueOf(zVAR_RECVARY_));
	    item4.addElement("recVariance");
	    item4.addElement("J");
	  cmds.addElement(item4);
          cmds.addElement(Long.valueOf(zVAR_BLOCKINGFACTOR_));
            item5.addElement("blockingFactor");
            item5.addElement("J");
          cmds.addElement(item5);
          cmds.addElement(Long.valueOf(zVAR_SPARSERECORDS_));
            item6.addElement("sparseRecords");
            item6.addElement("J");
          cmds.addElement(item6);
          cmds.addElement(Long.valueOf(zVAR_COMPRESSION_));
            item7.addElement("cType");
            item7.addElement("J");
          cmds.addElement(item7);
            item8.addElement("cParms");
            item8.addElement("[J");
          cmds.addElement(item8);
            item9.addElement("cPct");
            item9.addElement("J");
          cmds.addElement(item9);

	cmds.addElement(Long.valueOf(NULL_));

	v.cdfID = myCDF.getID();

	myCDF.executeCommand((CDFObject)v, cmds);

	cmds.removeAllElements();
	item0.removeAllElements();
	item1.removeAllElements();
	itemA.removeAllElements();
	itemB.removeAllElements();

	// Get the dimSizes only if it makes sense
	if (v.numDims > 0) {
	    v.dimSizes = new long[(int)v.numDims];
	    v.dimVariances = new long[(int)v.numDims];
	    v.dimCounts = new long[(int)v.numDims];
	    v.dimIndices = new long[(int)v.numDims];
	    v.dimIntervals = new long[(int)v.numDims];
            cmds.addElement(Long.valueOf(SELECT_));
              cmds.addElement(Long.valueOf(CDF_));
                itemA.addElement("cdfID");
                itemA.addElement("J");
              cmds.addElement(itemA);
              cmds.addElement(Long.valueOf(zVAR_));
                itemB.addElement("id");
                itemB.addElement("J");
              cmds.addElement(itemB);

	    cmds.addElement(Long.valueOf(GET_));
	      cmds.addElement(Long.valueOf(zVAR_DIMSIZES_));
	        item0.addElement("dimSizes");
		item0.addElement("[J");
	      cmds.addElement(item0);
	      cmds.addElement(Long.valueOf(zVAR_DIMVARYS_));
	        item1.addElement("dimVariances");
		item1.addElement("[J");
	      cmds.addElement(item1);
	    cmds.addElement(Long.valueOf(NULL_));

	    myCDF.executeCommand((CDFObject)v, cmds);

	}

        cmds.removeAllElements();
        item0.removeAllElements();
	itemA.removeAllElements();
	itemB.removeAllElements();

	v.setSignature();
        if (v.getDataType() == CDF_EPOCH16)
          v.padValue = new double[2];

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(zVAR_PADVALUE_));
            item0.addElement("padValue");
            item0.addElement("Ljava/lang/Object;");
          cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        myCDF.executeCommand((CDFObject)v, cmds);

	myCDF.addVariable(v);

	return v;
    }
}

    /**
     * Creates a variable. <P>
     *
     * The following example creates a variable called "Longitude" that is
     * scalar (non-array) and record-varying:
     * <PRE>
     *     longitude = Variable.create(cdf, "Longitude", CDF_INT2,
     *                                 1L, 0L, new long [] {1}, 
     *                                 VARY,
     *                                 new long [] {NOVARY});
     * </PRE>
     *
     * The following example creates a variable called "TestData" whose data  
     * is 2-dimensional (3 x 2), record variance is TURE, and dimension 
     * variances are TRUE. 
     * <PRE>
     *     data = Variable.create(cdf, "TestData", CDF_INT2,
     *                            1L, 2L, new long [] {3,2}, 
     *                            VARY,
     *                            new long [] {VARY, VARY});  
     * </PRE>
     * 
     * @param myCDF the CDF to which this variable belongs <P>
     * @param varName the name of the variable to create <P>
     * @param dataType the CDF data type for this variable that should be one
     *                 of the following:
     *                 <UL>
     *                    <LI>CDF_BYTE   - 1-byte, signed integer
     *                    <LI>CDF_CHAR   - 1-byte, signed character
     *                    <LI>CDF_INT1   - 1-byte, signed integer
     *                    <LI>CDF_UCHAR  - 1-byte, unsigned character
     *                    <LI>CDF_UINT1  - 1-byte, unsigned integer
     *                    <LI>CDF_INT2   - 2-byte, signed integer
     *                    <LI>CDF_UINT2  - 2-byte, unsigned integer
     *                    <LI>CDF_INT4   - 4-byte, signed integer
     *                    <LI>CDF_UINT4  - 4-byte, unsigned integer
     *                    <LI>CDF_INT8   - 8-byte, signed integer
     *                    <LI>CDF_REAL4  - 4-byte, floating point
     *                    <LI>CDF_FLOAT  - 4-byte, floating point
     *                    <LI>CDF_REAL8  - 8-byte, floating point
     *                    <LI>CDF_DOUBLE - 8-byte, floating point
     *                    <LI>CDF_EPOCH  - 8-byte, floating point
     *                    <LI>CDF_EPOCH16  - 2*8-byte, floating point
     *                    <LI>CDF_TIME_TT2000  - 8-byte, signed integer
     *                 </UL>
     * @param numElements for CDF_CHAR and CDF_UCHAR this is the 
     *                    string length, 1 otherwise <P>
     * @param numDims the dimensionality  <P>
     * @param dimSizes The dimension sizes. An array of length numDims 
     *                 indicating the size of each dimension <P>
     * @param recVary the record variance that should be either 
     *                VARY or NOVARY <P>
     * @param dimVarys The dimension variance(s).  Each dimension variance 
     *                 should be either VARY or NOVARY.<P> 
     *
     * @return newly created Variable object <P>
     * @throws CDFException if there is a problem creating a variable
     *
     */
    public static Variable create(CDF myCDF,
				  String varName,
				  long dataType,
				  long numElements,
				  long numDims,
				  long [] dimSizes,
				  long recVary,
				  long [] dimVarys) 
	throws CDFException
    {

synchronized(myCDF) {
        if (varName == null || varName.trim().length() == 0)
            throw new CDFException(BAD_VAR_NAME);

	long idx = myCDF.getVariableID(varName);
	if (idx != -1) 
	    throw new CDFException(VAR_EXISTS);

        Variable v;

	Vector cmds = new Vector();
	Vector item0 = new Vector();
	Vector item1 = new Vector();
	Vector item2 = new Vector();
	Vector item3 = new Vector();
	Vector item4 = new Vector();
	Vector item5 = new Vector();
	Vector item6 = new Vector();
	Vector item7 = new Vector();
        Vector itemA = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);

	cmds.addElement(Long.valueOf(CREATE_));
	  cmds.addElement(Long.valueOf(zVAR_));
	    item0.addElement("name");
	    item0.addElement("Ljava/lang/String;");
	  cmds.addElement(item0);
	    item1.addElement("dataType");
	    item1.addElement("J");
	  cmds.addElement(item1);
	    item2.addElement("numElements");
	    item2.addElement("J");
	  cmds.addElement(item2);
	    item3.addElement("numDims");
	    item3.addElement("J");
	  cmds.addElement(item3);
	    item4.addElement("dimSizes");
	    item4.addElement("[J");
	  cmds.addElement(item4);
	    item5.addElement("recVariance");
	    item5.addElement("J");
	  cmds.addElement(item5);
	    item6.addElement("dimVariances");
	    item6.addElement("[J");
	  cmds.addElement(item6);
	    item7.addElement("id");
	    item7.addElement("J");
	  cmds.addElement(item7);
	cmds.addElement(Long.valueOf(NULL_));

        v = new Variable(myCDF);
        v.myCDF        = myCDF;
        v.name         = varName;
        v.dataType     = dataType;
        v.numElements  = numElements;
        v.numDims      = numDims;
        v.dimSizes     = dimSizes;
        v.recVariance  = recVary;
        v.dimVariances = dimVarys;
        v.dimIndices   = new long[(int) numDims];
        v.dimCounts    = new long[(int) numDims];
        v.dimIntervals = new long[(int) numDims];
	v.cdfID = myCDF.getID();

	myCDF.executeCommand((CDFObject)v, cmds);

	v.setSignature();
	myCDF.addVariable(v);

	return v;
    }
}

    /**
     * Deletes this variable.
     *
     * @throws CDFException if there was an error deleting this variable
     */
    public synchronized void delete() throws CDFException {
	
	Vector cmds = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);
	
	cmds.addElement(Long.valueOf(DELETE_));
	  cmds.addElement(Long.valueOf(zVAR_));
	cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

	myCDF.executeCommand((CDFObject)this, cmds);

	myCDF.removeVariable(this);
    }

    /**
     * Renames the current variable.
     *
     * @param newName the new variable name <P>
     * @throws CDFException if there was a problem renaming this variable
     */
    public synchronized void rename(String newName) throws CDFException {

	Vector cmds = new Vector();
	Vector item0 = new Vector();
	Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

	cmds.addElement(Long.valueOf(PUT_));
	  cmds.addElement(Long.valueOf(zVAR_NAME_));
	    item0.addElement("name");
	    item0.addElement("Ljava/lang/String;");
	  cmds.addElement(item0);
	cmds.addElement(Long.valueOf(NULL_));

        name = newName;
	id = getID();
	cdfID = myCDF.getID();

	myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Copies this variable to a new variable.  This method only copies
     * the metadata associated with this variable.  The duplicate method
     * in this class should be used if the user wants to copy a variable 
     * with data and metadata. 
     *
     * @param varName the name of the variable to copy this variable into <P>
     *
     * @return newly copied variable
     * @throws CDFException if there was a problem copying a variable 
     */
    public synchronized Variable copy(String varName) throws CDFException {

	return (Variable) this.copy(this.myCDF, varName);
    }

    /**
     * Copies this variable into a new variable and puts it into the designated 
     * CDF file.  This method only copies the metadata associated with 
     * this variable.  The duplicate method in this class should be used 
     * if the user wants to copy a variable with data and metadata. 
     *
     * @param destCDF the destination CDF into which copy this variable 
     * @param varName the new variable name<P> 
     *
     * @return newly copied variable
     * @throws CDFException if there was a problem copying a variable 
     */
    public synchronized Variable copy(CDF destCDF, String varName) 
		throws CDFException {

        long idx = destCDF.getVariableID(varName);
        if (idx != -1) {
            throw new CDFException(VAR_EXISTS);
        }

        long [] sizes, varys;
        // Must set dummy dimSizes, etc for 0D (scalar) variables
        if (getNumDims() == 0) {
            sizes = new long[] {1};
            varys = new long[] {VARY};
        } else {
            sizes = dimSizes;
            varys = dimVariances;
        }

        Variable newVar = Variable.create(destCDF,
                                          varName,
                                          dataType,
                                          numElements,
                                          numDims,
                                          sizes,
                                          recVariance,
                                          varys);
        // Copy the metadata
        Vector attributes = this.myCDF.getAttributes();
        Attribute curAttr;
        Entry curEntry;
        for (Enumeration e=attributes.elements(); e.hasMoreElements() ;) {
            curAttr = (Attribute)e.nextElement();
            if (curAttr.getScope() == VARIABLE_SCOPE)
                try {
		    curEntry = curAttr.getEntry(getID());
		    if (this.myCDF != destCDF) { 
			// May have to create the attribute
			// if destination CDF is different from the source CDF
			Attribute destAttr;
			if (destCDF.getAttributeID(curAttr.getName()) == -1L) 
			   destAttr =	 
				Attribute.create(destCDF, curAttr.getName(), 
						 VARIABLE_SCOPE);
			else 
			   destAttr = destCDF.getAttribute(curAttr.getName());
			Entry.create(destAttr, newVar.getID(),
				     curEntry.getDataType(), curEntry.getData());
		    } else 
			Entry.create(curAttr, newVar.getID(),
				     curEntry.getDataType(), curEntry.getData());
                } catch (CDFException ce) {
                }
        }

        return newVar;

    }

    /**
     * Duplicates this variable to a new variable. <P>
     *
     * <B>Note:</B> This copies everything from the existing variable to a 
     *       new variable.  It includes the metadata associated with 
     *       this variable, all data records as well as other information 
     *       such as blocking factor/compression/sparseness/pad value.
     *
     * @param varName the name of the variable to duplicate this variable into <P>
     * @return newly duplicated variable
     * @throws CDFException if there was a problem duplicating a variable 
     */
    public synchronized Variable duplicate(String varName) throws CDFException {
	
	return (Variable) this.duplicate(this.myCDF, varName);
    }

    /**
     * Duplicates this variable and put it into the designated CDF file. <P>
     *
     * <B>Note:</B> This copies everything from the current variable to a 
     *       new variable.  It includes the metadata associated with 
     *       this variable, all data records as well as other information 
     *       such as blocking factor/compression/sparseness/pad value.
     *
     * @param destCDF the destination CDF to duplicate this variable into <P>
     * @param varName the name of the variable to duplicate this variable 
     *                into <P>
     * @return newly duplicated variable
     * @throws CDFException if there was a problem duplicating a variable
     */
    public synchronized Variable duplicate(CDF destCDF, String varName) 
		throws CDFException {

        Variable newVar = null;
        Object gotData;

        long [] indices;
        long [] interval;
        long [] sizes;

	if (numDims > 0) {
          indices = new long[(int)numDims];
          interval = new long[(int)numDims];
	  sizes = dimSizes;
          for (int i=0; i<numDims; i++) {
            indices[i] = 0L;
            interval[i] = 1L;
	  }
        } else {
	  sizes = new long [] {1};
	  indices = new long [] {0};
	  interval = new long [] {1};
	}

        long maxRecX = this.getMaxWrittenRecord();
        newVar = this.copy(destCDF, varName);

        newVar.setBlockingFactor(this.blockingFactor);
        newVar.setCompression(this.cType, this.cParms);
        newVar.setSparseRecords(this.sparseRecords);

        if (this.padValue != null) { /* Put the non-null pad value */
          newVar.setPadValue(this.padValue);
        }

        if (maxRecX > -1) {
          for (recNum = 0; recNum <= maxRecX; recNum = lastRec + 1) {
            firstRec = this.getAllocatedFrom(recNum);
            lastRec = this.getAllocatedTo(firstRec);
            lastRec = (lastRec > maxRecX? maxRecX: lastRec);
            gotData = this.getHyperData(firstRec, lastRec-firstRec+1, 1L,
                                      indices, sizes, interval);

            newVar.putHyperData(firstRec, lastRec-firstRec+1, 1L,
                                indices, sizes, interval, gotData);
          }
        }

        return newVar;

    }

    /**
     * Copies this variable's data to the destination variable. <P>
     *
     * @param destVar the destination variable to copy data into <P>
     * @throws CDFException if there was a problem copying data records
     *
     * <B>Note:</B> This copies data records from the current variable to 
     *       the destination variable. The metadata associated with the
     *       destination variable will be not changed.<P>
     *
     *       The current CDF file MUST be saved first (by calling the save()
     *       method) before 'copying/duplicating data records' operation is 
     *       performed.  Otherwise the program will either fail or produce
     *       undesired results.
     *
     */
    public synchronized void copyDataRecords(Variable destVar) 
		throws CDFException {

	this.copyDataRecords(destVar, 1L);
    }

    /**
     * Copies this variable's data records to the destination variable. <P>
     *
     *
     * @param destVar the destination variable to copy data into <P>
     * @param toWhere If toWhere = 0, it's called by copyDataRecords().
     *                If toWhere = 1, it's called by concatenateDataRecords().
     * @throws CDFException if there was a problem copying data records
     *
     * <B>Note:</B> This copies data records from the current variable to
     *       the destination variable. The metadata associated with the
     *       destination variable will be not changed.<P><BR>
     *
     *       The current CDF file MUST be saved first (by calling the save()
     *       method) before 'copying/duplicating data records' operation is
     *       performed.  Otherwise the program will either fail or produce
     *       undesired results.
     */
    private void copyDataRecords(Variable destVar, long toWhere) 
       throws CDFException {

        Object gotData;

	if (this.dataType != destVar.dataType ||
	    this.numElements != destVar.numElements ||
	    this.numDims != destVar.numDims) {
		throw new CDFException(CANNOT_COPY);
	}
	for (int i=0; i<this.numDims; i++) {
	   if (this.dimSizes[i] != destVar.dimSizes[i] ||
	       this.dimVariances[i] != destVar.dimVariances[i]) {
		throw new CDFException(CANNOT_COPY);
	   }
	}

	long [] indices;
	long [] interval;
	long [] sizes;

	if (numDims > 0) {
	  indices = new long[(int)numDims];
          interval = new long[(int)numDims];
	  sizes = dimSizes;
          for (int i=0; i<this.numDims; i++) {
            indices[i] = 0L;
            interval[i] = 1L;
	  }
        } else {
	  indices = new long[] {0};
	  interval = new long[] {1};
	  sizes = new long[] {1};
	}

        long maxRecI = this.getMaxWrittenRecord();
	long maxRecO;
	if (toWhere == 1L) maxRecO = 0; 		   // to copy
	else maxRecO = destVar.getMaxWrittenRecord() + 1;  // to concatenate

        if (maxRecI > -1) {
          for (recNum = 0; recNum <= maxRecI; recNum = lastRec + 1) {
            firstRec = this.getAllocatedFrom(recNum);
            lastRec = this.getAllocatedTo(firstRec);
            lastRec = (lastRec > maxRecI? maxRecI: lastRec);
            gotData = this.getHyperData(firstRec, lastRec-firstRec+1, 1L,
                                      indices, sizes, interval);

            destVar.putHyperData(maxRecO+firstRec, lastRec-firstRec+1, 1L,
                                 indices, sizes, interval, gotData);
          }
        }

    }

    /**
     * Concatenates this variable's data records to the destination variable.<P>
     *
     * @param destVar the destination variable to copy data records into <P>
     * @throws CDFException if there was a problem copying data records 
     *
     * <B>Note:</B> This copies only the data records from the current variable 
     *       to the destination variable. The metadata associated with the
     *       destination variable will be not changed.
     *
     */
    public synchronized void concatenateDataRecords(Variable destVar) 
		throws CDFException {

	this.copyDataRecords(destVar, 2L);
    }

    /**
     * Gets the attribute entry data for this variable. <P>
     *
     * The following examples retrieves the 'Longitude' variable entry
     * for the attribute VALIDMIN:
     * <PRE>
     *     Variable var = cdf.getVariable("Longitude");  
     *     float longitude = (float) var.getEntryData("VALIDMIN");
     * </PRE>
     *
     * @param attrName the name of the attribute to get entry data from <P>
     *
     * @return the attribute entry data for this variable <P>
     * @throws CDFException if there was a problem getting entry data
     */
    public synchronized Object getEntryData(String attrName) 
		throws CDFException {

        Attribute a = myCDF.getAttribute(attrName);
        Object entryData = a.getEntry(this).getData();
        return entryData;

    }

    /**
     * Gets a single data value.  This method is useful for extracting 
     * a specific item among many items. <P>
     *
     * Let's assume that variable TestData is defined to be 1-dimensional array
     * that has 3 elements in it.  The following example extracts the last 
     * element from the second record:
     * <PRE>
     *     Variable var = cdf.getVariable("TestData");
     *     int data = (int) var.getSingleData(1L, new long [] {2});
     * </PRE>
     *
     * Let's assume that variable TestData is defined to be 2-dimensional
     * (3x2 - 3 rows and 2 columns) array.  The following example extracts the 
     * first element of the second row from the first record:
     * <PRE>
     *     Variable var = cdf.getVariable("TestData");
     *     int data = (int) var.getSingleData(0L, new long [] {1,0});
     * </PRE>
     *
     * @param recNum the record number to retrieve data from <P>
     * @param indices the index, within a record, to extract data from<P>
     *
     * @return extracted single data value <P>
     * @throws CDFException if there was a problem extracting data
     */
    public synchronized Object getSingleData(long recNum, long[] indices) 
		throws CDFException {

	return this.getSingleDataObject(recNum,indices).getData();
    }

    /**
     * Gets a single data object from this variable. The value read
     * is put into an CDFData object.  This method is identical to the
     * getSingleData method except that the extracted data is encapsulated 
     * inside the CDFData object along with other information
     * such as record number, record count, record interval, dimension
     * indices, dimension counts, and dimension intervals.
     *
     * @param recNum the record number to retrieve data from <P>
     * @param indices the index, within a record, to extract data from<P>
     *
     * @return CDFData object containing the requested data <P> 
     * @throws CDFException if there was a problem extracting data
     */
    public synchronized CDFData getSingleDataObject(long recNum, long[] indices) 
		throws CDFException {
    
    	long [] interval;
        long [] counts;
        long [] mydices;

        if (numDims > 0) {
          interval = new long[(int)numDims];
          counts = new long[(int)numDims];
          mydices = indices;
          for (int i=0; i<numDims; i++) {
            counts[i] = 1L;
            interval[i] = 1L;
          }
        } else {
          mydices = new long[] {0};
          interval = new long[] {1};
          counts = new long[] {1};
        }

        return CDFData.get(this, recNum, 1L, 1L, mydices, counts, interval);
    }

    /**
     * Gets a single record from this variable. <P>
     *
     * Let's assume that variable TestData is defined to be 2-dimensional
     * (3x2 - 3 rows and 2 columns).  The following example extracts an 
     * entire record (containing 6 elements) from the first record from a 
     * variable of data type CDF_INT4:
     * <PRE>
     *     Variable var = cdf.getVariable("TestData");
     *     int[][] data = (int [][]) var.getRecord(0L);
     * </PRE>
     *
     * However, if a dimensional variable with all indices being invariant,
     * e.g., 2-dimensional (1x1), the retrieved object will be different.
     * (Since the variable has only one data value per record, it is preferred
     * to be defined as an 0-dim, rather.). The object is not an array, instead,
     * a single Java class item, e.g., Integer, Double, Short, etc. 
     * The following example extracts an record from the first record of
     * a variable, 2-dim (1x1), with data type CDF_INT2:
     * <PRE>
     *     Variable var = cdf.getVariable("TestVar");
     *     short data = ((Short) var.getRecord(0L)).shortValue();
     * </PRE>
     *
     * @param recNum the record number to retrieve data from <P>
     *
     * @return the requested data record 
     * @throws CDFException if there was a problem getting a record
     */
    public synchronized Object getRecord(long recNum) throws CDFException {

	return this.getRecordObject(recNum).getData();
    }

    /**
     * Get a single record of data from this variable. The values read
     * are put into an CDFData object.  This method is identical to the
     * getRecord method except that the extracted data is encapsulated 
     * inside the CDFData object along with other information
     * such as record number, record count, record interval, dimension
     * indices, dimension counts, and dimension intervals.
     *
     * @param recNum the record number to retrieve data from <P>
     *
     * @return CDFData object containing the requested data record <P>
     * @throws CDFException if there was a problem getting a record
     */
    public synchronized CDFData getRecordObject(long recNum) 
		throws CDFException {

	return this.getRecordsObject(recNum, 1L);
    }

    /**
     * Get a number of records of data from this variable. The values read
     * are put into an CDFData object.  
     *
     * @param recNum the record number to start to retrieve data from <P>
     * @param numRecs the number of records to retrieve <P>
     *
     * @return CDFData object containing the requested data record(s) <P>
     * @throws CDFException if there was a problem getting the record(s)
     */
    public synchronized CDFData getRecordsObject(long recNum, long numRecs) 
		throws CDFException {
    
	long [] indices;
        long [] interval;
        long [] sizes;

        if (numDims == 0) {
            sizes = new long [] {1};
            indices = new long [] {0};
            interval = new long [] {1};
        } else {
            sizes = dimSizes;
            indices = new long [(int)numDims];
            interval = new long [(int)numDims];
            for (int i=0; i<numDims; i++) {
                indices[i] = 0L;
                interval[i] = 1L;
            }
        }
        return CDFData.get(this, recNum, numRecs, 1L, indices, sizes, interval);
    }

    /**
     * Get all written records, from record number 0 till the last written
     * record number, from this variable. The data values read
     * are put into an CDFData object. 
     *
     * Note: If this variable has sparse records, then the missing record(s)
     *       is filled with FILLVAL (or PAD if FILLVAL does not exist) value.  
     *
     * @return CDFData object containing all data record(s) <P>
     * @throws CDFException if there was a problem getting the record(s)
     */
    public synchronized CDFData getAllRecordsObject() throws CDFException {

        long [] indices;
        long [] interval;
        long [] sizes;

        if (numDims == 0) {
            sizes = new long [] {1};
            indices = new long [] {0};
            interval = new long [] {1};
        } else {
            sizes = dimSizes;
            indices = new long [(int)numDims];
            interval = new long [(int)numDims];
            for (int i=0; i<numDims; i++) {
                indices[i] = 0L;
                interval[i] = 1L;
            }
        }
        long maxRec = this.getMaxWrittenRecord();
        if (maxRec == -1)
          return null;
        else
          return CDFData.get(this, 0L, (maxRec+1), 1L, indices, sizes,
                             interval);
    }

    /**
     * Get all written records, from record number 0 till the last written
     * record number, from this variable. The data values read
     * are put into an Object. 
     *
     * Note: If this variable has sparse records, then the missing record(s)
     *       is filled with FILLVAL (or PAD if FILLVAL does not exist) value.  
     *
     * @return Object containing all data record(s) <P>
     * @throws CDFException if there was a problem getting the record(s)
     */
    public synchronized Object getAllRecords() throws CDFException {

        return this.getAllRecordsObject().getData();
    }

    /**
     * Gets the scalar data from a non-record varying 0-dimensional variable. 
     *
     * @return the variable data from this variable <P>
     * @throws CDFException if there was a problem getting data 
     */
    public synchronized Object getScalarData() throws CDFException
    {

        return this.getScalarDataObject(0L).getData();
    }

    /**
     * Get the scalar data from a record varying 0-dimensional variable. 
     *
     * @param recNum The record number to retrieve data from <P>
     *
     * @return the variable data from this variable <P>
     * @throws CDFException if there was a problem getting data 
     */
    public synchronized Object getScalarData(long recNum) throws CDFException {
    
	return this.getScalarDataObject(recNum).getData();
    }

    /**
     * Get the scalar data from a non-record varying 0-dimensional 
     * variable.  This method is identical to the
     * getScalarData method except that the extracted data is encapsulated 
     * inside the CDFData object along with other information
     * such as record number, record count, record interval, dimension
     * indices, dimension counts, and dimension intervals. 
     *
     * @return the variable data from this variable
     * @throws CDFException if there was a problem getting data 
     */
    public synchronized CDFData getScalarDataObject() throws CDFException {

        return getScalarDataObject(0L);
    }

    /**
     * Get the scalar data from this record varying 0-dimensional variable.
     * This method is identical to the
     * getScalarData method except that the extracted data is encapsulated
     * inside the CDFData object along with other information
     * such as record number, record count, record interval, dimension
     * indices, dimension counts, and dimension intervals.
     *
     * @param recNum the record number to retrieve data from <P>
     *
     * @return the variable data from this variable
     * @throws CDFException if there was a problem getting data 
     */
    public synchronized CDFData getScalarDataObject(long recNum) 
		throws CDFException {

        long [] indices = new long [] {0};
        long [] interval = new long [] {1};
        long [] sizes = new long [] {1};

        return CDFData.get(this, recNum, 1L, 1L, indices, sizes, interval);
    }

    /**
     * Reads one or more values from the current z variable.  The values 
     * are based on the current record number, current record count, 
     * current record interval, current dimension indices, current
     * dimension counts, and current dimension intervals. <P>
     *
     * Let's assume that variable TestData is defined to be 2-dimensional
     * (3x2 - 3 rows and 2 columns).  The following example extracts the
     * entire record (containing 6 elements) from the first, second, and 
     * third records:
     * <PRE>
     *     Variable var = cdf.getVariable("TestData");
     *     int[][][] data = (int [][][]) var.getHyperData (0L, 3L, 1L,
     *                                                     new long[] {0, 0},
     *                                                     new long[] {3, 2},
     *                                                     new long[] {1, 1});
     * </PRE>
     * The following example will extract the entire record from the first record: 
     * <PRE>
     *     Variable var = cdf.getVariable("TestData");
     *     int[][] data = (int [][]) var.getHyperData (0L, 1L, 1L,
     *                                                 new long[] {0, 0},
     *                                                 new long[] {3, 2},
     *                                                 new long[] {1, 1});
     * </PRE>
     * Note: it returns a 2-dimensional object as only one record is involved.
     *
     * The following example will extract the second row from the first,
     * and third records:
     * <PRE>
     *     Variable var = cdf.getVariable("TestData");
     *     int[][] data = (int [][]) var.getHyperData (0L, 3L, 2L,
     *                                                 new long[] {1, 0},
     *                                                 new long[] {1, 2},
     *                                                 new long[] {1, 1});
     * </PRE>
     * The following example will extract the first column from the first 
     * and second records: 
     * <PRE>
     *     Variable var = cdf.getVariable("TestData");
     *     int[][] data = (int [][]) var.getHyperData (0L, 2L, 1L,
     *                                                 new long[] {0, 0},
     *                                                 new long[] {3, 1},
     *                                                 new long[] {1, 1});
     * </PRE>
     *
     * @param recNum the record number at which data search begins <P>
     * @param recCount the number of records to read <P>
     * @param recInterval the number of records to skip between reads <P>
     * @param dimIndices the dimension index within a record at which data 
     *                   search begins <P>
     * @param dimCounts the number of elements to read from dimIndices <P>
     * @param dimIntervals the number of elements to skip between reads <P>
     *
     * @return the variable data specified by recNum, recCount, recInterval,
     *         dimIndices, dimCounts, and dimIntervals <P>
     * @throws CDFException if there was a problem getting data
     */
    public synchronized Object getHyperData(long recNum, long recCount, 
					    long recInterval, long[] dimIndices,
					    long[] dimCounts, 
					    long[] dimIntervals) 
		throws CDFException {

	return CDFData.get(this, recNum, recCount, recInterval,
			   dimIndices, dimCounts, dimIntervals).getData();
    }

    /**
     * Reads one or more values from the current z variable.  The values 
     * are read based on the current record number, current record count, 
     * current record interval, current dimension indices, current
     * dimension counts, and current dimension intervals.  The values read
     * are put into an CDFData object.
     *
     * @param recNum the record number at which data search begins
     * @param recCount the number of records to read
     * @param recInterval the number of records to skip between reads
     * @param dimIndices the dimension index within a record at which data
     *                   search begins
     * @param dimCounts the number of elements to read from dimIndices
     * @param dimIntervals the number of elements to skip between reads <P>
     *
     * @return CDFData object that contains the variable data specified by 
     *         recNum, recCount, recInterval, dimIndices, dimCounts, and 
     *         dimIntervals as well as the information passed to this method
     *         plus the number of dimensions and the number of elements for
     *         this variable. <P>
     * @throws CDFException if there was a problem getting data
     */
    public synchronized CDFData getHyperDataObject(long recNum, long recCount, 
				      		   long recInterval,
				      		   long[] dimIndices, 
						   long[] dimCounts, 
				      		   long[] dimIntervals) 
		throws CDFException {

	return CDFData.get(this, recNum, recCount, recInterval,
			   dimIndices, dimCounts, dimIntervals);
    }

    /**
     * Gets the full variable information, its specification, metadata and
     * data.
     *
     * Note: Each metadata/data of epoch type data will be encoded in 
     *       date/time string.
     *
     * <PRE>
     *
     *  Variable v = cdf.getVariable("var1");
     *  Map var = v.readVariable();
     *  // Three key-value pairs will be included with keys of as
     *  // "VarSpec", "VarMetaData", "VarData"
     *
     *  // Key: "VarSpec" contains variable specification - another Map object
     *  // These include: keys of "DataType", "NumElements", "NumDims",
     *  // "DimSizes" and "PadValue".
     *  System.out.println("  specification: "+var.get("VarSpec")); 
     *
     *  // Key: "VarMetaData" contains variable attributes - another Map object
     *  // These include variable attribute name (key) and its entry (value)
     *  System.out.println("  meta: "+var.get("VarMetaData"));
     *
     *  // Key: "VarData" has variable data - an object
     *  System.out.println("  data:"); 
     *  CDFUtils.printData(var.get("VarData")); 
     *
     * </PRE>
     *
     * @return A Map object that contains the full variable information.
     */
    public synchronized Map readVariable()
    {
       return readVariable (true, true, true, true);
    }

    /**
     * Gets the variable's specification.
     *
     * @return A Map object that contains the variable's specification with
     *         the key "VarSpec". The value is another Map object.
     */
    public synchronized Map readVariableSpec()
    {
      return readVariable (true, true, false, false);
    }

    /**
     * Gets the variable's metadata.
     *
     * @return A Map object that contains the variable's metadata with
     *         the key "VarMetaData". The value is another Map object if
     *         it has metadata.
     */
    public synchronized Map readVariableMetaData()
    {
      return readVariable (true, false, true, false);
    }

    /**
     * Gets the variable's data.
     *
     * @return A Map object that contains the variable's specification with
     *         the key "VarData".
     */
    public synchronized Map readVariableData()
    {
      return readVariable (false, false, false, true);
    }

    /**
     * Gets the specified variable information: its specification, metadata
     * and data.
     *
     * <PRE>
     *
     *  Variable v = cdf.getVariable("var1");
     *  Map var = v.readVariable(true, true, true, true);
     *  // Three key-value pairs might be included with keys of as
     *  // "VarSpec" and "VarMetaData" and/or "VarData" if there are data.
     *
     *  // Key: "VarSpec" contains variable specification - another Map object
     *  // These include: keys of "DataType", "NumElements", "NumDims",
     *  // "DimSizes" and "PadValue".
     *  System.out.println("  specification: "+var.get("VarSpec")); 
     *
     *  // Key: "VarMetaData" contains variable attributes - another Map object
     *  // These include variable attribute name (key) and its entry (value)
     *  System.out.println("  meta: "+var.get("VarMetaData"));
     *
     *  // Key: "VarData" has variable data - an object
     *  System.out.println("  data:"); 
     *  CDFUtils.printData(var.get("VarData")); 
     *
     * </PRE>
     *
     * @param encoding A true/false flag indicates whether to encode epoch
     *                 data type from metadata to date/time string.
     * @param basic A true/false flag indicates whether to return the
     *              specification of the variable
     * @param metadata A true/false flag indicates whether to return the
     *                 metadata from the variable
     * @param vardata true/false flag indicates whether to return the
     *                data from the variable
     *
     * @return A Map object that contains the requested variable information.
     */
    public synchronized Map readVariable(boolean encoding, boolean basic,
                                         boolean metadata, boolean vardata)
    {
       Map vinfo = new HashMap();
       if (basic) {
         Map varSpec = new HashMap();
         varSpec.put("VarName", this.name);
//       varSpec.put("DataType", CDFUtils.getStringDataType(dataType));
         varSpec.put("DataType", getDataType());
         varSpec.put("NumElements", getNumElements());
         varSpec.put("NumDims", getNumDims());
         varSpec.put("DimSizes", getDimSizes());
         try {
           Object pad = getPadValue();
           if (encoding) {
             if (dataType == CDF_EPOCH)
               varSpec.put("PadValue", Epoch.toEncode(pad));
             else if (dataType == CDF_EPOCH16)
               varSpec.put("PadValue", Epoch16.toEncode(pad));
             else if (dataType == CDF_TIME_TT2000)
               varSpec.put("PadValue", CDFTT2000.toEncode(pad));
             else
               varSpec.put("PadValue", pad);
           } else
             varSpec.put("PadValue", pad);
         } catch (CDFException e1) { }
         vinfo.put("VarSpec", varSpec);
       }
       if (metadata) {
         try {
           Map meta = getAttributesandEntries(encoding);
           if (meta.size() > 0)
             vinfo.put("VarMetaData", meta);
         } catch (Exception ex1) {
           vinfo.put("VarMetaData", null);
         }
       }
       if (vardata) {
         try {
           Object varData = getAllRecords();
           if (varData != null) { 
             if (!encoding || (dataType != CDF_EPOCH &&
                               dataType != CDF_TIME_TT2000 &&
                               dataType != CDF_EPOCH16))
               vinfo.put("VarData", varData);
             else if (dataType == CDF_EPOCH)
               vinfo.put("VarData", Epoch.toEncode(varData));
             else if (dataType == CDF_TIME_TT2000)
               vinfo.put("VarData", CDFTT2000.toEncode(varData));
             else
               vinfo.put("VarData", Epoch16.toEncode(varData));
           } else
             vinfo.put("VarData", null);
         } catch (Exception ex2) {
           vinfo.put("VarData", null);
         }
       }
       return vinfo;
    }

    /**
     * Creates an attribute entry for this variable. <P>
     *
     * The following example creates a variable entry for the
     * variable "Longitude" associated with the attribute "VALIDMIN":
     * <PRE>
     *     Variable longitude = cdf.getVariable("Longitude");
     *     longitude.putEntry("VALIDMIN", CDF_INT2, new Short((short)180));
     * </PRE>
     *
     * @param attrName the attribute to which this attribute entry is attached 
     * @param dataType the CDF data type of the entry data - see the 
     *                 description of the create method in this class for
     *                 a list of the CDF data types supported
     * @param data the attribute entry data to be added
     *
     * @throws CDFException if a problem occurs putting an entry
     * @see gsfc.nssdc.cdf.Attribute
     * @see gsfc.nssdc.cdf.Entry
     */
    public synchronized void putEntry(String attrName, long dataType, 
				      Object data) throws CDFException
    {

	Entry.create(myCDF.getAttribute(attrName), getID(), dataType, data);

    }

    /**
     * Creates an attribute entry for this variable.
     *
     * The following example creates a variable entry for the
     * variable "Longitude" associated with the attribute "VALIDMIN":
     * <PRE>
     *     Variable longitude = cdf.getVariable("Longitude");
     *     Attribute validMin = Attribute.create(cdf, "VALIDMIN",
     *                                           VARIABLE_SCOPE);
     *     Entry.create(validMin, longitude.getID(), CDF_INT2,
     *                  new Short((short)10)); 
     *             OR 
     *     longitude.putEntry(validMin, CDF_INT2, new Short((short)180));
     * </PRE>
     *
     * @param attr the attribute to which this attribute entry is attached <P>
     * @param dataType the CDF data type of the entry data - see the 
     *                 description of the create method in this class for
     *                 a list of the CDF data types supported
     * @param data the attribute entry data to be added <P>
     *
     * @throws CDFException if a problem occurs putting an entry
     * @see gsfc.nssdc.cdf.Attribute
     * @see gsfc.nssdc.cdf.Entry
     */
    public synchronized void putEntry(Attribute attr, long dataType, 
				      Object data) throws CDFException
    {

        Entry.create(attr, getID(), dataType, data);

    }

    /**
     * Adds a single data value to this variable.  This method is used
     * to specify a particular element in a record (if a record is
     * comprised of multiple elements).  If a record contains 3 elements,
     * the following example will write the second element to record number
     * 0, leaving the first and third elements unwritten.
     * <PRE>
     *    longitude = cdf.getVariable("Longitude");
     *    longitude.putSingleData(0L, new long[] {1}, new Short((short)200));
     *           or
     *    longitude.putSingleData(0L, new long[] {1}, longitudeData[1]);
     * </PRE>      
     *
     * @param recNum the record number to which this data belongs <P>
     * @param indices the index (location) in the specified record <P>
     * @param data the data to be added <P>
     *
     * @return CDFData object containing the user specified data <P>
     * @throws CDFException if there was an error writing data
     */
    public synchronized CDFData putSingleData(long recNum, long[] indices, 
					      Object data) throws CDFException
    {

	long [] interval;
	long [] counts;
	long [] mydices;

	if (numDims > 0) {
	  interval = new long[(int)numDims];
	  counts = new long[(int)numDims];
	  mydices = indices;
	  for (int i=0; i<numDims; i++) {
	    counts[i] = 1L;
	    interval[i] = 1L;
	  }
	} else {
          counts = new long [] {1};
          mydices = new long [] {0};
          interval = new long [] {1};
	}

	return CDFData.put(this, recNum, 1L, 1L, mydices, counts, interval, 
			   data);
    }

    /**
     * Adds a scalar data to this variable (of 0 dimensional).  This
     * method should be used if a variable is defined as record-varying and
     * non-array.  The following example will write data to record number 0.
     * <PRE>
     *    longitude = cdf.getVariable("Longitude");
     *    longitude.putScalarData(0L, new Short((short)200));
     *           or
     *    longitude.putScalarData(0L, longitudeData[0]);
     * </PRE>
     *
     * @param recNum the record number to which this data belongs <P>
     * @param data the data to be added <P>
     *
     * @return CDFData object containing the user specified data <P>
     * @throws CDFException if there was an error writing data 
     */
    public synchronized CDFData putScalarData(long recNum, Object data)
        throws CDFException
    {

        return this.putSingleData(recNum, new long[] {0}, data);
    }

    /**
     * Adds a scalar data to this variable (of 0 dimensional).  This
     * method should be used if a variable is defined as non-record-varying and
     * non-array.  Note that there'll be only one record exist if a variable is
     * defined as non-record-varying.  The following example will write 
     * data to record number 0.
     * <PRE>
     *    longitude = cdf.getVariable("Longitude");
     *    longitude.putScalarData(new Short((short)200));
     *           or
     *    longitude.putScalarData(longitudeData[0]);
     * </PRE>
     * 
     * @param data the data to be added <P>
     *
     * @return CDFData object containing the user specified data <P>
     * @throws CDFException if there was an error writing data 
     */
    public synchronized CDFData putScalarData(Object data)
        throws CDFException
    {

        return this.putSingleData(0L, new long[] {0}, data);
    }

    /** 
     * Adds a single record to a record-varying variable.  This method should
     * be used if a record contains one or more elements. 
     * <PRE>
     *    The following example adds a scalar data to record number 0: 
     *        longitude = cdf.getVariable("Longitude");
     *        longitude.putRecord(0L, new Short((short)200)); 
     *
     *    The following example adds multiple elements (array) to record 
     *    number 0: 
     *        short [] longitudeData = {10, 20, 30};
     *        longitude = cdf.getVariable("Longitude");
     *        longitude.putRecord(0L, longitudeData); 
     * </PRE>
     *
     * @param recNum the record number to which this data belongs <P>
     * @param data the data to be added <P>
     *
     * @return CDFData object containing the user specified data <P>
     * @throws CDFException if there was a problem writing data 
     */
    public synchronized CDFData putRecord(long recNum, Object data)
	throws CDFException
    {

	long [] indices;
	long [] interval;
	long [] sizes;
	if (numDims > 0) {
	  indices = new long[(int)numDims];
	  interval = new long[(int)numDims];
	  sizes = dimSizes;
	  for (int i=0; i<numDims; i++) {
	    indices[i] = 0L;
	    interval[i] = 1L;
	  }
	} else {
            sizes = new long [] {1};
            indices = new long [] {0};
            interval = new long [] {1};
	}
	return CDFData.put(this, recNum, 1L, 1L, indices, sizes, interval, 
			   data);
    }

    /**
     * Adds a single record to a non-record-varying variable.  This method 
     * should be used if a record contains one element or multiple elements.
     * <PRE>
     *    The following example adds a scalar data to record number 0: 
     *        longitude = cdf.getVariable("Longitude");
     *        longitude.putRecord(new Short((short)200)); 
     *
     *    The following example adds multiple elements (array) to record
     *    number 0: 
     *        short [] longitudeData = {10, 20, 30};
     *        longitude = cdf.getVariable("Longitude");
     *        longitude.putRecord(longitudeData); 
     * </PRE>
     *
     * @param data the data to be added <P>
     *
     * @return CDFData object containing the user specified data <P>
     * @throws CDFException if there was a problem writing data
     */
    public synchronized CDFData putRecord(Object data)
        throws CDFException
    {

        return this.putRecord(0L, data);
    }

    /**
     * Writes one or more values from the current z variable.  The values
     * are written based on the current record number, current record count,
     * current record interval, current dimension indices, current
     * dimension counts, and current dimension intervals.  The values read
     * are put into an CDFData object.  Although this method returns a
     * CDFData object, it is not necessary to capture the return value to
     * a CDFData variable.  <P>
     *
     * Let's assume that variable TestData is defined to be 2-dimensional
     * (3x2 - 3 rows and 2 columns).  The following example writes the
     * entire record (containing 6 elements) to the first, second, and
     * third records:
     * <PRE>
     *     long [][][] testData = {{{10,20},{30,40},{50, 60}},
     *                             {{15,25},{45,55},{75, 85}}
     *                             {{90,95},{96,97},{2147483648L,4294967295L}}
     *                             };
     *     testData.putHyperData (0L, 3L, 1L,
     *                            new long[] {0, 0},
     *                            new long[] {3, 2},
     *                            new long[] {1, 1}, testData);
     * </PRE>
     * The following example will write the first two rows of testData to the
     * first, third, and fifth records: 
     * <PRE>
     *     testData.putHyperData (0L, 3L, 2L,
     *                            new long[] {0, 0},        
     *                            new long[] {2, 2},        
     *                            new long[] {1, 1}, testData);       
     * </PRE>
     *
     * @param recNum the record number at which data write begins <P>
     * @param recCount the number of records to write <P>
     * @param recInterval the number of records to skip between writes <P>
     * @param dimIndices the dimension index within a record at which data
     *                   write begins <P>
     * @param dimCounts the number of elements to write from dimIndices <P>
     * @param dimIntervals the number of elements to skip between writes <P>
     * @param data the data to be written <P> 
     *
     * @return CDFData object that contains the variable data specified by
     *         recNum, recCount, recInterval, dimIndices, dimCounts, and
     *         dimIntervals as well as the information passed to this method
     *         plus the number of dimensions and the number of elements for
     *         this variable. <P>
     *
     * @throws CDFException if there was a problem writing data
     */
    public synchronized CDFData putHyperData(long recNum, long recCount, 
					     long recInterval, 
			     		     long[] dimIndices, 
					     long[] dimCounts, 
			     		     long[] dimIntervals, Object data)
	throws CDFException
    {

	return CDFData.put(this, recNum, recCount, recInterval,
			   dimIndices, dimCounts, dimIntervals, data);
    }

    /**
     * Writes a number of records from the current z variable.  The values
     * are written from the starting record number.
     * Although this method returns a
     * CDFData object, it is not necessary to capture the return value to
     * a CDFData variable.  <P>
     *
     * Let's assume that variable TestData is defined to be 2-dimensional
     * (3x2 - 3 rows and 2 columns).  The following example writes three
     * records to the variable as the first, second, and third record:
     * <PRE>
     *     long [][][] testData = {{{10,20},{30,40},{50, 60}},
     *                             {{15,25},{45,55},{75, 85}}
     *                             {{90,95},{96,97},{2147483648L,4294967295L}}
     *                             };
     *     testData.putRecords (0L, 3L, testData);
     * </PRE>
     *
     * @param startRec the starting record number at which data write begins <P>
     * @param recCount the number of records to write <P>
     * @param data the data to be written <P> 
     *
     * @return CDFData object that contains the variable data specified by
     *         recNum, recCount, recInterval, dimIndices, dimCounts, and
     *         dimIntervals as well as the information passed to this method
     *         plus the number of dimensions and the number of elements for
     *         this variable. <P>
     *
     * @throws CDFException if there was a problem writing data
     */
    public synchronized CDFData putRecords(long startRec, long recCount, 
			     		   Object data)
	throws CDFException
    {

        long ndims = getNumDims();
        long[] dimIndicesX;
        long[] dimCountsX;
        long[] dimIntervalsX;
        if (ndims > 0) {
          dimIndicesX = new long[(int)ndims];
          dimCountsX = getDimSizes();
          dimIntervalsX = new long[(int)ndims];
          for (int ij = 0; ij < (int)ndims; ++ij) {
            dimIndicesX[ij] = 0L;
            dimIntervalsX[ij] = 1L;
          }
        } else {
          dimIndicesX = new long[] {0L};
          dimCountsX = new long[] {1L};
          dimIntervalsX = new long[] {1L};
        }
	return CDFData.put(this, startRec, recCount, 1L,
			   dimIndicesX, dimCountsX, dimIntervalsX, data);
    }

    /**
     * Selects this variable.  There is no need to build the entire
     * select cmd vector since this is handled in the native method
     * cdfNativeLib in cdfNativeLibrary.c
     *
     * @throws CDFException If there was a problem selecting this variable
     */
    private final void select() throws CDFException {

	Vector cmds = new Vector();
	// Make sure that the id is up to date
	cmds.addElement(Long.valueOf(NULL_)); // Select this variable

        id = getID();

	myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Selects this variable, a record and its indices.
     *
     * @param recNum The record number to be selected 
     * @param indices The indices to be selected <P>
     * @throws CDFException If there was a problem selecting the
     *                         specified record or indices. 
     */
    protected synchronized final void select(long recNum, long[] indices) 
		throws CDFException {

	int i;
        Vector cmds = new Vector();
	Vector item0 = new Vector();
	Vector item1 = new Vector();
	Vector item2 = new Vector();
        Vector itemA = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
	  cmds.addElement(Long.valueOf(zVAR_));
	    item0.addElement("id");
	    item0.addElement("J");
	  cmds.addElement(item0);
	  cmds.addElement(Long.valueOf(zVAR_RECNUMBER_));
	    item1.addElement("recNum");
	    item1.addElement("J");
	  cmds.addElement(item1);
          cmds.addElement(Long.valueOf(zVAR_DIMINDICES_));
            item2.addElement("dimIndices");
            item2.addElement("[J");
          cmds.addElement(item2);
	cmds.addElement(Long.valueOf(NULL_));

        this.recNum = recNum;
        for (i=0; i< numDims; i++) dimIndices[i] = indices[i];
        // Make sure that the id is up to date
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * This will select this variable, a range of records and their indices.
     * It is for a hyper function.
     *
     * @param recNum The record number to be selected
     * @param recCount The number of records to be selected from recNum
     * @param recInterval The record interval 
     * @param dimIndices The dimension indices to be selected
     * @param dimCounts The dimension counts to be selected
     * @param dimIntervals The dimension intervals to be selected <P>
     *
     * @throws CDFException If there was a problem selecting the
     *                         specified record or indices.
     */
    protected synchronized final void select(long recNum, long recCount, 
					     long recInterval,
			        	     long[] dimIndices, 
					     long[] dimCounts, 
                                	     long[] dimIntervals) 
	 throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector item1 = new Vector();
        Vector item2 = new Vector();
        Vector item3 = new Vector();
        Vector item4 = new Vector();
        Vector item5 = new Vector();
	Vector item6 = new Vector();
        Vector itemA = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            item0.addElement("id");
            item0.addElement("J");
          cmds.addElement(item0);
          cmds.addElement(Long.valueOf(zVAR_RECNUMBER_));
            item1.addElement("recNum");
            item1.addElement("J");
          cmds.addElement(item1);
          cmds.addElement(Long.valueOf(zVAR_RECCOUNT_));
            item2.addElement("recCount");
            item2.addElement("J");
          cmds.addElement(item2);
          cmds.addElement(Long.valueOf(zVAR_RECINTERVAL_));
            item3.addElement("recInterval");
            item3.addElement("J");
          cmds.addElement(item3);
          cmds.addElement(Long.valueOf(zVAR_DIMINDICES_));
            item4.addElement("dimIndices");
            item4.addElement("[J");
          cmds.addElement(item4);
          cmds.addElement(Long.valueOf(zVAR_DIMCOUNTS_));
            item5.addElement("dimCounts");
            item5.addElement("[J");
          cmds.addElement(item5);
          cmds.addElement(Long.valueOf(zVAR_DIMINTERVALS_));
            item6.addElement("dimIntervals");
            item6.addElement("[J");
          cmds.addElement(item6);
        cmds.addElement(Long.valueOf(NULL_));

        this.recNum= recNum;
        this.recCount = recCount;
        this.recInterval = recInterval;
        this.dimIndices  = dimIndices;
        this.dimCounts   = dimCounts;
        this.dimIntervals = dimIntervals;

        // Make sure that the id is up to date
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the CDF object to which this variable belongs.
     *
     * @return the CDF object to which this variable belongs
     */
    public synchronized CDF getMyCDF(){

	return myCDF;
    }

    /**
     * Gets the compression type of this variable.
     *
     * @return the compression type of this variable 
     */
    public synchronized long getCompressionType() {

	return cType;

    }

    /**
     * Gets the compression percentage rate of this variable.
     *
     * @return the compression percentage rate of this variable
     */
    public synchronized long getCompressionPct() {

	return cPct;

    }

    /**
     * Sets the compression parameters of this variable.  This is only
     * applicable for the GZIP compression method.
     *
     * @return the compression parameters of this variable
     */
    public synchronized long [] getCompressionParms() {

        return cParms;

    }

    /** 
     * Sets the compression type and parameters for this variable.
     *
     * @param cType the compression type
     * @param cParms the compression parameters that go with cType<P>
     *
     * @throws CDFException if a problem occurs setting compression
     *                         type and parameters
     */
    public synchronized void setCompression(long cType, long[] cParms) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector item1 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_COMPRESSION_));
              item0.addElement("cTypeX");
              item0.addElement("J");
           cmds.addElement(item0);
              item1.addElement("cParmsX");
              item1.addElement("[J");
           cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

        this.cTypeX = cType;
        this.cParmsX = cParms;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	this.cType = cType;
	this.cParms = cParms;
    }

    /**
     * Gets the string representation of the compression type and parameters 
     * set for this variable.
     *
     * @return the string representation of the compression type and 
     *         parameters for this variable <P>
     * @throws CDFException if a problem occurs getting the compression
     *                         type and parameters
     */
    public synchronized String getCompression() throws CDFException {

        StringBuffer temp = new StringBuffer();

        if (cType == NO_COMPRESSION)
            temp.append("No compression");
        else
            temp.append(CDFUtils.getStringCompressionType(cType)).append(".").
		 append(cParms[0]);
        return temp.toString();
    }

    /**
     * Gets the number of dimensions for this variable.
     *
     * @return the number of dimensions for this variable
     */
    public synchronized long getNumDims() {

        return numDims;

    }

     /**
     * Gets the dimensions size of this variable.
     *
     * @return the dimension size of this variable
     */
    public synchronized long[] getDimSizes() {

	return dimSizes;

    }

    /**
     * Gets the number of elements for this variable.  For CDF_CHAR 
     * and CDF_UCHAR this is the number of characters in the string.
     * For all other types this defaults to 1.
     *
     * @return the number of elements for this variable
     */
    public synchronized long getNumElements() {

	return numElements;

    }

    /**
     * Gets the name of this variable.
     *
     * @return the name of this variable
     */
    public synchronized String getName() {

	return name;
    }

    /**
     * Gets the ID of this variable.
     *
     * @return the ID of this variable 
     */
    public synchronized long getID() {
	  return myCDF.getVariableID(name);
    }
    
    /**
     * Gets the name of this variable.
     *
     * @return the name of this variable
     */
    public synchronized String toString() {

	return name;
    }

    /**
     * Sets the record variance for this variable.
     *
     * @param recVariance the record variance that should be either 
     *                    VARY or NOVARY. <P>
     * @throws CDFException if a problem occurs setting the record
     *            variance
     */
    public synchronized void setRecVariance(long recVariance) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_RECVARY_));
              item0.addElement("recVarianceX");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.recVarianceX = recVariance;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	this.recVariance = recVariance;
    }

    /**
     * Gets the value of record variance.
     *
     * @return True if this variable is record varying, False otherwise
     */
    public synchronized boolean getRecVariance() {

	if (recVariance == VARY) 
	    return true;
	else 
	    return false;

    }

    /**
     * Sets the dimension variances for this variable.
     *
     * @param dimVariances the dimension variances for this variable <P>
     * @throws CDFException if a problem occurs setting the 
     *            dimension variances
     */
    public synchronized void setDimVariances(long[] dimVariances) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_DIMVARYS_));
              item0.addElement("dimVariancesX");
              item0.addElement("[J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.dimVariancesX = dimVariances;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	this.dimVariances = dimVariances;
    }

    /**
     * Gets the dimension variances for this variable.
     *
     * @return the dimension variances for this variable
     */
    public synchronized long [] getDimVariances() {

	return dimVariances;

    }

    /**
     * Gets the CDF data type of this variable.
     *
     * @return the CDF data type of this variable
     *
     */
    public synchronized long getDataType() {

	return dataType;

    }
    
    /**
     * Sets the signature based on the data type of the variable
     */
    private void setSignature() {

	    switch ((int)dataType) {
	    case (int)CDF_BYTE:
	    case (int)CDF_INT1:
		dataSignature = "Ljava/lang/Byte;";
		break;
	    case (int)CDF_INT2:
	    case (int)CDF_UINT1:
		dataSignature = "Ljava/lang/Short;";
		break;
	    case (int)CDF_INT4:
	    case (int)CDF_UINT2:
		dataSignature = "Ljava/lang/Integer;";
		break;
	    case (int)CDF_UINT4:
	    case (int)CDF_INT8:
	    case (int)CDF_TIME_TT2000:
		dataSignature = "Ljava/lang/Long;";
		break;
	    case (int)CDF_REAL4:
	    case (int)CDF_FLOAT:
		dataSignature = "Ljava/lang/Float;";
		break;
	    case (int)CDF_REAL8:
	    case (int)CDF_DOUBLE:
	    case (int)CDF_EPOCH:
		dataSignature = "Ljava/lang/Double;";
		break;
            case (int)CDF_EPOCH16:
                dataSignature = "[D";
                break;
	    case (int)CDF_CHAR:
	    case (int)CDF_UCHAR:
		dataSignature = "Ljava/lang/String;";
		break;
	    default:
		break;
	    }
    }

    /**
     * Deletes a range of records from this variable. While non-sparse
     * variable records after the last deleted record will be renumbered,
     * the sparse variable records will not.
     *
     * @param firstRec the first record to be deleted
     * @param lastRec the last record to be deleted <P>
     *
     * @throws CDFException if a problem occurs deleting records
     */
    public synchronized void deleteRecords(long firstRec, long lastRec) 
		throws CDFException {
        this.toDeleteRecords(firstRec, lastRec, false);
    }

    /**
     * Deletes a range of records from this variable. All records after the
     * last deleted record are renumbered for both the sparse or non-sparse
     * variable after the deletion. 
     *
     * @param firstRec the first record to be deleted
     * @param lastRec the last record to be deleted <P>
     *
     * @throws CDFException if a problem occurs deleting records
     */
    public synchronized void deleteRecordsRenumber(long firstRec,
                                                   long lastRec) 
		throws CDFException {
        this.toDeleteRecords(firstRec, lastRec, true);
    }

    private void toDeleteRecords(long firstRec, long lastRec, boolean reNumber) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector item1 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(DELETE_));
           cmds.addElement(Long.valueOf(
                           reNumber?zVAR_RECORDS_RENUMBER_:zVAR_RECORDS_));
              item0.addElement("firstRec");
              item0.addElement("J");
           cmds.addElement(item0);
              item1.addElement("lastRec");
              item1.addElement("J");
           cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

        this.firstRec = firstRec;
        this.lastRec = lastRec;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Allocates a range of records for this variable.
     *
     * @param firstRec the first record to be allocated
     * @param lastRec the last record to be allocated <P>
     *
     * @throws CDFException if a problem occurs allocating records
     */
    public synchronized void allocateBlock(long firstRec, long lastRec) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector item1 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_ALLOCATEBLOCK_));
              item0.addElement("firstRec");
              item0.addElement("J");
           cmds.addElement(item0);
              item1.addElement("lastRec");
              item1.addElement("J");
           cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

        this.firstRec = firstRec;
        this.lastRec = lastRec;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Allocates a number of records, starting from record number 0.
     *
     * @param num0toRecords the number of records to be allocated <P>
     * @throws CDFException if a problem occurs allocating records 
     */
    public synchronized void allocateRecords(long num0toRecords) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_ALLOCATERECS_));
              item0.addElement("num0toRecords");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.num0toRecords = num0toRecords;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the number of records physically written (not allocated) for 
     * this variable.
     *
     * @return the number of records written physically <P>
     * @throws CDFException if a problem occurs getting the number
     *                         of records written physically 
     */
    public synchronized long getNumWrittenRecords() throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(GET_));
           cmds.addElement(Long.valueOf(zVAR_NUMRECS_));
              item0.addElement("numRecords");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	return numRecords;
    }

    /**
     * Gets the last written record number, beginning with 0.
     *
     * @return the last written record number <P>
     * @throws CDFException if a problem occurs getting the last
     *                         written record number 
     */
    public synchronized long getMaxWrittenRecord() throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);
	
        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(zVAR_MAXREC_));
            item0.addElement("maxRec");
            item0.addElement("J");
          cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

        return maxRec;
    }

    /**
     * Gets the number of records allocated for this variable.
     *
     * @return the number of records allocated <P>
     * @throws CDFException if a problem occurs getting the 
     *                         number of records allocated
     */
    public synchronized long getNumAllocatedRecords() throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(zVAR_NUMallocRECS_));
            item0.addElement("numAllocRecords");
            item0.addElement("J");
          cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

        return numAllocRecords;
    }

    /**
     * Gets the maximum allocated record number for this variable.
     *
     * @return the maximum allocated record number <P>
     * @throws CDFException if a problem occurs getting the 
     *                         maximum allocated record number 
     */
    public synchronized long getMaxAllocatedRecord() throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(zVAR_MAXallocREC_));
            item0.addElement("maxAllocRecord");
            item0.addElement("J");
          cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

        return maxAllocRecord;
    }

    /**
     * Sets the pad value for this variable.  This pad value is used, 
     * when storing data, for undefined values.
     *
     * @param padValue the pad value to be used for undefined values <P>
     * @throws CDFException if a problem occurs setting the pad value
     */
    public synchronized void setPadValue(Object padValue) throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

	if (this.dataType == CDF_CHAR || this.dataType == CDF_UCHAR) {
/*
	  int len = ((String)padValue).length();
	  if  (len < this.numElements) {
	    StringBuffer tmp = new StringBuffer((String)padValue);
            int ix;
            for (ix = 0; ix < (this.numElements - len); ++ix) tmp.append(' ');
	    this.padValue = new String(tmp.toString());
	  } else
*/
	    this.padValue = padValue;
	} else
	  this.padValue = padValue;

	try {
          cmds.addElement(Long.valueOf(SELECT_));
            cmds.addElement(Long.valueOf(CDF_));
              itemA.addElement("cdfID");
              itemA.addElement("J");
            cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

          cmds.addElement(Long.valueOf(PUT_));
            cmds.addElement(Long.valueOf(zVAR_PADVALUE_));
              item0.addElement("padValue");
              item0.addElement("Ljava/lang/Object;");
            cmds.addElement(item0);
          cmds.addElement(Long.valueOf(NULL_));

          this.padValueX = padValue;
          id = getID();
	  cdfID = myCDF.getID();

          myCDF.executeCommand((CDFObject)this, cmds);

	} catch (CDFException e) {
	  throw new CDFException(CANNOT_CHANGE);
	}
    }

    /**
     * Checks if the pad value has been defined for this variable. 
     *
     * @return Whether the user-defined pad value exists. It is
     *         either true or false.  
     *         <UL>
     *             <LI>true - pad value has been specified.
     *             <LI>false - pad value is not specified.<P> 
     *         </UL>
     * @throws CDFException if a problem occurs checking the existence of the
     *                         pad value
     *
     * Note: The getPadValue() method will return a pad value, whether it is
     *       the user defined or the default.
     */
    public synchronized boolean checkPadValueExistence() throws CDFException {

        Vector cmds = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

	try {
          cmds.addElement(Long.valueOf(SELECT_));
            cmds.addElement(Long.valueOf(CDF_));
              itemA.addElement("cdfID");
              itemA.addElement("J");
            cmds.addElement(itemA);
            cmds.addElement(Long.valueOf(zVAR_));
              itemB.addElement("id");
              itemB.addElement("J");
            cmds.addElement(itemB);

          cmds.addElement(Long.valueOf(CONFIRM_));
            cmds.addElement(Long.valueOf(zVAR_PADVALUE_));
          cmds.addElement(Long.valueOf(NULL_));

          id = getID();
	  cdfID = myCDF.getID();

          myCDF.executeCommand((CDFObject)this, cmds);

	  long existing = myCDF.getStatus();
	  if (existing == CDF_OK) return true;
	  else return false;

        } catch (CDFException e) {
          throw new CDFException(BAD_CDFSTATUS);
        }
    }

    /**
     * Gets the pad value for this variable.
     *
     * @return the pad value set for this variable <P>
     * @throws CDFException if a problem occurs reading the pad value
     */
    public synchronized Object getPadValue() throws CDFException {

        if (this.padValue != null) return this.padValue;
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
        Vector itemB = new Vector();

        if (getDataType() == CDF_EPOCH16)
          padValue = new double[2];

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

          cmds.addElement(Long.valueOf(GET_));
            cmds.addElement(Long.valueOf(zVAR_PADVALUE_));
              item0.addElement("padValue");
              item0.addElement("Ljava/lang/Object;");
            cmds.addElement(item0);
          cmds.addElement(Long.valueOf(NULL_));

          id = getID();
          cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);
        this.padValueX = padValue;

        return padValue;

    }

    /**
     * Sets the sparse record type for this variable.
     *
     * @param sparseRecords sparse record type that should be one of the
     *                      following types:
     *                      <UL>
     *                         <LI>NO_SPARSERECORDS - The variable doesn't 
     *                                                have sparse records.
     *                         <LI>PAD_SPARSERECORDS - The variable has 
     *                                pad-missing records. 
     *                         <LI>PREV_SPARSERECORDS - The variable has 
     *                                previous-missing records.  
     *                      </UL>
     * @throws CDFException if a problem occurs setting the sparse
     *                         record type
     */
    public synchronized void setSparseRecords(long sparseRecords) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_SPARSERECORDS_));
              item0.addElement("sparseRecordsX");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.sparseRecordsX = sparseRecords;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	this.sparseRecords = sparseRecords;
    }

    /**
     * Gets the sparse record type for this variable.
     *
     * @return one of the following sparse record type is returned:
     *         <UL>
     *            <LI>NO_SPARSERECORDS - means that no sparse records are defined
     *            <LI>PAD_SPARSERECORDS - means that the variable's pad value 
     *                        is used when reading values from a missing 
     *                        record  
     *            <LI>PREV_SPARSERECORDS - means that values from the previous 
     *                        existing records are used when reading values 
     *                        from a missing record
     *          </UL>
     */
    public synchronized long getSparseRecords() {

        return sparseRecords;

    }

    /**
     * Sets the blocking factor for this variable.  The blocking factor has 
     * no effect for Non-Record varying (NRV) variables or muti-file CDFs.
     *
     * @param blockingFactor the blocking factor -  a value of zero (0) 
     *                           indicates that the default blocking 
     *                           factor should be used <P>
     *
     * @throws CDFException if a problem occurs setting the blocking factor
     */
    public synchronized void setBlockingFactor(long blockingFactor) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_BLOCKINGFACTOR_));
              item0.addElement("blockingFactorX");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.blockingFactorX = blockingFactor;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	this.blockingFactor = blockingFactor;
    }

    /**
     * Gets the blocking factor for this variable.
     *
     * @return the blocking factor set this variable <P>
     * @throws CDFException if a problem occurs getting the blocking 
     *                         factor set for this variable
     */
    public synchronized long getBlockingFactor() throws CDFException {

        return blockingFactor;

    }

    /**
     * Sets the number of records to be written initially for this variable. 
     *
     * @param nRecords the number of records to be written initially <P>
     * @throws CDFException if a problem occurs writing initial records 
     */
    public synchronized void setInitialRecords(long nRecords) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(zVAR_INITIALRECS_));
              item0.addElement("nRecords");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.nRecords = nRecords;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Sets the number of 512-byte cache buffers to be used.  This operation is
     * not applicable for a single-file CDF. 
     *
     * @param cacheSize the number of 512-byte cache buffers <P>
     * @throws CDFException if a problem occurs allocating cache buffers
     */
    public synchronized void selectCacheSize(long cacheSize) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

          cmds.addElement(Long.valueOf(zVAR_CACHESIZE_));
            item0.addElement("cacheSize");
            item0.addElement("J");
          cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.cacheSize = cacheSize;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the number of 512-byte cache buffers defined for this variable.
     *
     * @return the number of 512-byte cache buffers set for this variable <P>
     * @throws CDFException if a problem occurs getting the number
     *                         of cache buffers set for this variable
     */
    public synchronized long confirmCacheSize() throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(zVAR_CACHESIZE_));
              item0.addElement("cacheSize");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);
        return this.cacheSize;

    }

    /**
     * Sets the reserve percentage to be used for this variable.  This 
     * operation is only applicable to compressed z Variables.  The 
     * Concepts chapter in the CDF User's Guide describes the reserve 
     * percentage scheme used by the CDF library.
     *
     * @param reservePercent the reserve percentage to be used<P>
     * @throws CDFException if a problem occurs setting a reserve 
     *                         percentage
     */
    public synchronized void selectReservePercent(long reservePercent) 
		throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

          cmds.addElement(Long.valueOf(zVAR_RESERVEPERCENT_));
            item0.addElement("reservePercent");
            item0.addElement("J");
          cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        this.reservePercent = reservePercent;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the reserve percentage set for this variable.  This operation is
     * only applicable to compressed z Variables.
     *
     * @return the reserve percentage set for this variable <P>
     * @throws CDFException if a problem occurs getting the reserve 
     *                         percentage
     */
    public synchronized long confirmReservePercent() throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(zVAR_RESERVEPERCENT_));
              item0.addElement("reservePercent");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	return this.reservePercent;
    }

    /**
     * Checks the existence of an explicitly specified pad value for the
     * current z variable.  If an explicit pad value has not been 
     * specified, the informational status code NO_PADVALUE_SPECIFIED is 
     * returned. Otherwise, CDF_OK is returned.
     *
     * @return Existence of pad value.  If no pad value is specified for 
     *         this variable, NO_PADVALUE_SPECIFIED is returned. If
     *         a pad value has been specified, then CDF_OK is returned. <P>
     * @throws CDFException if a problem occurs checking the 
     *                         existence of pad value. 
     * Note: for NO_PADVALUE_SPECIFIED, getPadValue method will return the
     *       default pad value.
     */
    public synchronized long confirmPadValue() throws CDFException {

        Vector cmds = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(zVAR_PADVALUE_));
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

        return myCDF.getStatus();
    }

    /**
     * Inquires the next allocated record at or after a given record for this 
     * variable.
     *
     * @param recNum The record number at which to begin searching for the 
     *               next allocated record.  If this record exists, it will
     *               be considered the next allocated record. <P>
     *
     * @return the number of the next allocated record <P>
     * @throws CDFException if a problem occurs getting the number 
     *                         of the next allocated record
     */
    public synchronized long getAllocatedFrom(long recNum) throws CDFException {

        Vector cmds = new Vector();
	Vector item0 = new Vector();
	Vector item1 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(zVAR_ALLOCATEDFROM_));
            item0.addElement("recNum");     /* in */
            item0.addElement("J");
          cmds.addElement(item0);
            item1.addElement("firstRec");   /* out */
            item1.addElement("J");
          cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

        this.recNum = recNum;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	return this.firstRec;
    }

    /**
     * Inquires the last allocated record (before the next unallocated record) 
     * at or after a given record for this variable.
     *
     * @param firstRec the record number at which to begin searching for the 
     *                 last allocated record <P>  
     * @return the number of the last allocated record <P>
     * @throws CDFException if a problem occurs getting the number 
     *                         of the last allocated record
     */
    public synchronized long getAllocatedTo(long firstRec) throws CDFException {

        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector item1 = new Vector();
        Vector itemA = new Vector();
	Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(zVAR_ALLOCATEDTO_));
            item0.addElement("firstRec");     /* in */
            item0.addElement("J");
          cmds.addElement(item0);
            item1.addElement("lastRec");      /* out */
            item1.addElement("J");
          cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

        this.firstRec = firstRec;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

        return this.lastRec;
    }

    /**
     * Update the data specification (data type and number of elements)
     * of the variable.
     * @param  dataType the data type of the entry data
     * @param  numElements the number of elements fo the entry data
     * @throws CDFException An exception is thrown if the operation fails
     */
    public synchronized void updateDataSpec(long dataType, long numElements)
        throws CDFException {

        Vector cmds  = new Vector();
        Vector item0 = new Vector();
        Vector item1 = new Vector();
        Vector itemA = new Vector();
        Vector itemB = new Vector();

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
            itemA.addElement("cdfID");
            itemA.addElement("J");
          cmds.addElement(itemA);
          cmds.addElement(Long.valueOf(zVAR_));
            itemB.addElement("id");
            itemB.addElement("J");
          cmds.addElement(itemB);

        cmds.addElement(Long.valueOf(PUT_));
          cmds.addElement( Long.valueOf(zVAR_DATASPEC_));
            item0.addElement("xdataType");
            item0.addElement("J");
          cmds.addElement(item0);
            item1.addElement("xnumElements");
            item1.addElement("J");
          cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

        this.xdataType = dataType;
        this.xnumElements = numElements;
        id = getID();
	cdfID = myCDF.getID();

        myCDF.executeCommand((CDFObject)this, cmds);

	this.dataType = dataType;
	this.numElements = numElements;
	setSignature();
    }


    /**
     * Returns the variable attributes that are associated with this 
     * variable. 
     * <PRE>
     *     The following example describes how to retrieve all the variable
     *     attributes that are associated with a particular variable.
     *
     *        Variable v = cdf.getVariable("myVariable");
     *        Vector   attrs = v.getAttributes();
     *        if (attrs.size() &gt; 0) {
     *            for (Enumeration e=attrs.elements(); e.hasMoreElements();) {
     *                 Attribute a = (Attribute) e.nextElement();
     *                 // manipulate the attribute
     *            }
     *        }
     * </PRE>
     * @return Returns the variable attributes that are associated with 
     *         this variable.
     */
    public synchronized Vector getAttributes () {

        Variable v = null;

        try {
            v = this.myCDF.getVariable(this.getName());
            Vector attrs = new Vector();
            Vector va = this.myCDF.getVariableAttributes();

            for (Enumeration e=va.elements(); e.hasMoreElements();) {
              Attribute a = (Attribute) e.nextElement();
              try {
                  Entry entry = a.getEntry(v);
                  if (entry != null) {
                      attrs.addElement(a);
                  }
              } catch (CDFException ex) {   // No attribute entry exists
              }
            }
            return attrs;
        } catch (CDFException ex) { 
          return new Vector();
        }
    }

    /**
     * Returns the variable attributes and their entries that are associated 
     * with this variable. 
     * <PRE>
     *     The following example describes how to retrieve all the variable
     *     attributes and their entries that are associated with a particular
     *     variable.
     *
     *       Variable v = cdf.getVariable("myVariable");
     *       Map vaes = v.getAttributesandEntries();
     *       if (vaes != null) {
     *         for (Object key : vaes.keySet()) {
     *           System.oit.println("Attribute:"+key+" entry:"+vaes.get(key));
     *         }
     *       }
     * </PRE>
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values. CDF Epoch type data will be encoded in date/time
     *       string.
     *
     * @return Returns a Map object that contains variable attribute names as
     *         keys and entries as values that are associated with 
     *         this variable. All keys and values are in object type. If
     *         there is no attribute, then null is returned;
     */
    public synchronized Map getAttributesandEntries () {

      return getAttributesandEntries (true);
    }

    /**
     * Returns the variable attributes and their entries that are associated 
     * with this variable. 
     * <PRE>
     *     The following example describes how to retrieve all the variable
     *     attributes and their entries that are associated with a particular
     *     variable.
     *
     *       Variable v = cdf.getVariable("myVariable");
     *       Map vaes = v.getAttributesandEntries(true);
     *       if (vaes != null) {
     *         for (Object key : vaes.keySet()) {
     *           System.oit.println("Attribute:"+key+" entry:"+vaes.get(key));
     *         }
     *       }
     * </PRE>
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values.
     *  
     * @param  encoding A true/false flag indicates whether to encode epoch
     *                  type data to date/time string.
     *
     * @return Returns a Map object that contains variable attribute names as
     *         keys and entries as values that are associated with 
     *         this variable. All keys and values are in object type. If
     *         there is no attribute, then null is returned;
     */
    public synchronized Map getAttributesandEntries (boolean encoding) {

        Map aes = new HashMap();
        Vector attrs = getAttributes();
        long id = getID();
        if (attrs.size() == 0) return null;
        for (Enumeration e=attrs.elements(); e.hasMoreElements();) {
          Attribute a = (Attribute) e.nextElement();
          String attrName = a.getName();
          try {
            Entry en = a.getEntry(id);
            Object data = en.getData();
            if (encoding) {
              long dataType = en.getDataType();
              if (dataType == CDF_EPOCH) {
                aes.put(attrName, Epoch.toEncode(data));
              } else if (dataType == CDF_EPOCH16)
                aes.put(attrName, Epoch16.toEncode(data));
              else if (dataType == CDF_TIME_TT2000) {
                aes.put(attrName, CDFTT2000.toEncode(data));
              } else
                aes.put(attrName, data);
            } else
              aes.put(attrName, data);
          } catch (CDFException xx) { System.out.println("error entry="+xx);}
        }
        return aes;
    }

    /**
     * Dump the data, either the variable value or metadata, with or without 
     * the format. The format comes from the FORMAT variable attribute.
     * @param  data An object, likely an attribute entry, for output
     *
     */
    public synchronized void dumpDataWithFormat (Object data) {
        String format, xformat;
        try {
          xformat     = (String) getEntryData("FORMAT");
        } catch (CDFException ex) {
          xformat = null;
        }
        format = CDFUtils.CFtoJformat(xformat);
        CDFUtils.printDataWithFormat (data, format);

    }

    /**
     * Dump the data, either the variable value or metadata, with or without 
     * the format. The format comes from the FORMAT variable attribute.
     * @param  data An object, likely an attribute entry, for output
     * @param outWriter the print writer to which formatted representations 
     *                  of the object/data is printed as a text-output stream
     *
     *
     */
    public synchronized void dumpDataWithFormat (Object data,
                                                 PrintWriter outWriter) {
        String format, xformat;
        try {
          xformat     = (String) getEntryData("FORMAT");
        } catch (CDFException ex) {
          xformat = null;
        }
        format = CDFUtils.CFtoJformat(xformat);
        CDFUtils.printDataWithFormat (data, format, outWriter, 0);

    }

    /**
     * Dump the data, either the variable value or metadata, with 
     * the format. The format comes from the FORMAT variable attribute.
     * @param  data A CDFData object, likely variable data, for output
     *
     */
    public synchronized void dumpDataWithFormat (CDFData data) {
        String format, xformat;
        try {
          xformat     = (String) getEntryData("FORMAT");
        } catch (CDFException ex) {
          xformat = null;
        }
        format = CDFUtils.CFtoJformat(xformat);
        data.dumpDataWithFormat (format);

    }

}


