//dId: CDF.java,v 1.3 2002/07/15 18:33:22 liu 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.lang.*;
import java.util.*;
import java.io.File;
import gsfc.nssdc.cdf.*;
import gsfc.nssdc.cdf.util.*;

/**
 * The CDF class is the main class used to interact with a CDF file.<BR><BR>
 *
 * <B>Notes:</B><BR>
 * <UL>
 *   <LI>All files are placed in zMODE 2 upon opening or creation</LI>
 *   <LI>Variable attributes are handled slightly differently from C.  
 *   <UL>
 *     <LI>Each variable has a java.util.Vector of attributes.</LI>
 *     <LI>This vector contains only those vAttributes that have a z entry for 
 *         this variable.</LI>
 *     <LI>Therefore, the index for a given variable Attribute 
 *         may not be the same for another variable.</LI>
 *   </UL>
 * </UL>
 *
 * <CENTER><TABLE BORDER=1>
 * <TR><TD><B>CDF dataType</B></TD><TD><B>Java dataType</B></TD><TD><B>Read/Write</B></TD></TR>
 * <TR><TD>CDF_BYTE</TD><TD>java.lang.Byte</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_INT1</TD><TD>java.lang.Byte</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_UINT1</TD><TD>java.lang.Short</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_INT2</TD><TD>java.lang.Short</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_UINT2</TD><TD>java.lang.Integer</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_INT4</TD><TD>java.lang.Integer</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_UINT4</TD><TD>java.lang.Long</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_INT8</TD><TD>java.lang.Long</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_FLOAT</TD><TD>java.lang.Float</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_REAL4</TD><TD>java.lang.Float</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_DOUBLE</TD><TD>java.lang.Double</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_REAL8</TD><TD>java.lang.Double</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_EPOCH</TD><TD>java.lang.Double</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_EPOCH16</TD><TD>java.lang.Double[</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_TIME_TT2000</TD><TD>java.lang.Long</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_CHAR</TD><TD>java.lang.String</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <TR><TD>CDF_UCHAR</TD><TD>java.lang.String</TD><TD ALIGN=CENTER>Y/Y</TD></TR>
 * <CAPTION>Supported dataTypes and their mappings</CAPTION>
 * </TABLE></CENTER>
 *
 * @see gsfc.nssdc.cdf.Attribute
 * @see gsfc.nssdc.cdf.CDFException
 * @see gsfc.nssdc.cdf.Variable
 *
 * @version 1.0 
 * @version 2.0 03/18/05  Selection of current attribute is 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.
 *                        Sync'd the CDF (id) for every JNI calls.
 * @author Phil Williams, QSS Group Inc/RITSS <BR>
 *         Mike Liu, RSTX
 */ 

public class CDF extends Object implements CDFObject, CDFConstants {
    
    /*******************************************************************
     *	This is the class that all CDF commands get passed through.
     ******************************************************************/
    private CDFDelegate delegate;
    private static Object Monitor = new Object();

    private String path;         // CDF file name

    private long id;             // CDF id

    private File    theFile = null;
    private long    cdfStatus;
    private long    cType, cTypeX;
    private long    cPct;
    private long[]  cParms = new long[1];
    private long[]  cParmsX = new long[1];
    private long    cSize, uSize;
    private String  copyright = null;
    private String  version = null;
    private long    vers, libVersion;
    private long    rel, libRelease;
    private long    inc, libIncrement;
    private String  libsubIncrement, libCopyright;
    private long    encoding, encodingX;
    private long    decoding;
    private long    cacheSize;
    private long    compressCacheSize;
    private long    stageCacheSize;
    private long    negtoPosfp0;
    private long    format, formatX;
    private long    majority, majorityX;
    private long    numAttrs;
    private long    numGattrs;
    private long    numVattrs;
    private long    numRvars;
    private long    numZvars;
    private long    readOnly;
    private long    zmode;
    private long    numDims;
    private long[]  dimSizes;
    private boolean closed; // true if cdf has been closed. Need for finalizer
    private long    infoWarning;
    private static  long    backward = 0;
    private static  boolean backwardFlagSet = false;
    private static  long    validate = 0;
    private static  boolean validateFlagSet = false;

    private long    fromEnvVar;			 // Get env var value
    private static  long    backwardEnvVar = -1; // -1 if getFileBackwardEnvVar
			 			 // is not called.
    private static  long    validateEnvVar = -1; // -1 if getValidateEnvVar
                                                 // is not called.
    private long    checksum, checksumX = -1;
    private long    lastUpdated, lastUpdatedX = -1;
    private static long     checksumEnvVar = -1;
    private String  leapTableEnvVar = null;
    private long    toGetAttrVar;
    private long    leapSecondLastUpdated;

    /********************************************************************
     * The list of all the Attributes for this CDF.<BR><BR>
     *
     * Note that the order of the attributes in this list reflect the
     * attributes id in the CDF within the JNI code.  The same is true
     * for the variable list.
     ********************************************************************/
    private Vector  attributes;

    /*************************************************************************
     * The list of variables for this CDF.<BR><BR>
     *
     * Note:  See above comment.  Also, note that 2 separate lists or r and z
     * variables will have to be maintained since the ids within the CDF are
     * separate.
     *
     * @shapeType AggregationLink
     * @associates <b>Variable</b>
     *************************************************************************/
    private Vector  variables;
    
    /**
     * Constructor for CDF.
     *
     * @param path The full pathname of the CDF file.
     * @param delegate The CDFDelegate which handles all CDF commands <P>
     * @return A CDF object <P>
     * @exception CDFException If there was a problem creating the constructor
     */
    private CDF(String path, CDFDelegate delegate) throws CDFException
    {
	if (path == null || path.length() == 0) 
            throw new CDFException(BAD_CDF_NAME);

	String tmpStr = null;
	// Strip any leading and trailing whitespaces from the string
	tmpStr = path.trim(); 
        if (tmpStr == null || tmpStr.length() == 0) 
          throw new CDFException(BAD_CDF_NAME);

	while (tmpStr.startsWith(" ")) 
               tmpStr = tmpStr.substring(1);

	this.path     = tmpStr;
	this.delegate = delegate;
	this.zmode    = zMODEon2;
	attributes    = new Vector();
	variables     = new Vector();
	closed        = false;
	CDF.checksumEnvVar = CDF.getChecksumEnvVar();

    }

    private CDF(CDFDelegate delegate) throws CDFException 
    {
        this.delegate = delegate;

    }

    /**
     * Creates a CDF file in the current directory. By default, a single-file
     * CDF is created and it's the preferred format.  However, if the user 
     * wants to create a multi-file CDF, its file format needs to be changed
     * as following:
     * <PRE>
     *     CDF cdf = null;
     *     cdf = CDF.create("test");
     *     cdf.setFormat(MULTI_FILE); 
     * </PRE>
     *
     * For the single-file format CDF, the above example would have created
     * a single-file CDF called 'test.cdf'.  See Chapter 1 of the CDF User's
     * Guide for more information about the file format options. 
     * <B>Notes:</B><BR>
     * The newly created file will be of the same version as the CDF library, 
     * as a V3.*. To create a backward file, i.e., V2.7, there are two options
     * that can be used. Use the static method setFileBackward to set the backward
     * flag. The following example will create backward file for test1.cdf and 
     * test2.cdf, but a V3.* file for test3.cdf.
     * <PRE>
     *     CDF cdf1, cdf2, cdf3;
     *     CDF.setFileBackward(BACKWARDFILEon);
     *     cdf1 = CDF.create("test1");
     *     cdf2 = CDF.create("test2");
     *     CDF.setFileBackward(BACKWARDFILEoff);
     *     cdf3 = CDF.create("test3");
     * </PRE>
     * Alternatively, use an environment variable to control the backward file
     * creation. The environment variable CDF_FILEBACKWARD on Unix or Windows or
     * CDF$FILEBACKWARD on Open/VMS is used. When it is set to TRUE, a V2.7 file(s)
     * will be created automatically. In the following example, both test1.cdf and 
     * test2.cdf will be V2.7 if environment variable CDF_FILEBACKWARD 
     * (or CDF$FILEBACKWARD) is TRUE.
     * <PRE>
     *     CDF cdf1 = CDF.create("test1");
     *     CDF cdf2 = CDF.create("test2");
     * </PRE>
     *
     * @param path the full pathname of the CDF file to be created <P>
     * @return the newly created CDF file/object <P>
     * @exception CDFException if there was a problem creating a CDF file
     */

    public static CDF create(String path) throws CDFException
    {

        if (path == null || path.trim().length() == 0)
          throw new CDFException(BAD_CDF_NAME);

	CDF theCDF = new CDF(path, new CDFNativeLibrary());

  	// theCDF.theFile = new File(path);
	// Set the defaults
	theCDF.numDims  = 0;     //dummy since all vars are currently zVars
	theCDF.dimSizes = new long [] {2}; //ibid

        Vector   cmds  = new Vector();
        Vector   item1 = new Vector();
        Vector   item2 = new Vector();
        Vector   item3 = new Vector();
        Vector   item4 = new Vector();

        cmds.addElement(Long.valueOf(CREATE_));
          cmds.addElement(Long.valueOf(CDF_));
            item1.addElement("path");                    /* in */
            item1.addElement("Ljava/lang/String;");
          cmds.addElement(item1);
            item2.addElement("numDims");      /* in - not used for Z var */
            item2.addElement("J");
          cmds.addElement(item2);
            item3.addElement("dimSizes");     /* in - not used for Z var */
            item3.addElement("[J");
          cmds.addElement(item3);
            item4.addElement("id");           /* out */
            item4.addElement("J");
          cmds.addElement(item4);
	  cmds.addElement(Long.valueOf(NULL_));

        theCDF.executeCommand((CDFObject)theCDF, cmds);

	String pathT = theCDF.FindCDFName(path);
	if (pathT != null) 
	  theCDF.theFile = new File(pathT);
	theCDF.selectzMode(zMODEon2);
	theCDF.selectReadOnlyMode(READONLYoff);
        theCDF.getCDFInfo();
        theCDF.toGetAttrVar = 0;
	return theCDF;
    }

    /**
     * Creates a CDF file in the current directory. By default, a single-file
     * CDF is created and it's the preferred format. The following example will 
     * create a CDF file: 
     * <PRE>
     *     CDF cdf = null;
     *     cdf = CDF.create("test", 0);
     * </PRE>
     *
     * For the single-file format CDF, the above example would have created
     * a single-file CDF called 'test.cdf'.  The newly created file will be 
     * of the same version as the CDF library, To create a backward file, 
     * i.e., V2.7, use a differnt argument for the flag. 
     * <PRE>
     *     CDF cdf;
     *     cdf = CDF.create("test", 1);
     * </PRE>
     *
     * @deprecated Use setFileBackward(long) method to set the file backward 
     *             flag and create(String) to create file instead.
     *
     * @param path the full pathname of the CDF file to be created <P>
     * @param flag the file backward indicator flag. Passed 0 if a file of
     *             current library version is to be created. Not 0 if a backward
     *             is to be created.
     * @return the newly created CDF file/object <P>
     * @exception CDFException if there was a problem creating a CDF file
     */
//    @Deprecated
    public static CDF create(String path, int flag) throws CDFException
    {

        if (path == null || path.trim().length() == 0)
          throw new CDFException(BAD_CDF_NAME);

	CDF theCDF = new CDF(path, new CDFNativeLibrary());

	CDF.setFileBackward((long) flag);

  	// theCDF.theFile = new File(path);
	// Set the defaults
	theCDF.numDims  = 0;     //dummy since all vars are currently zVars
	theCDF.dimSizes = new long [] {2}; //ibid

        Vector   cmds  = new Vector();
        Vector   item1 = new Vector();
        Vector   item2 = new Vector();
        Vector   item3 = new Vector();
        Vector   item4 = new Vector();

        cmds.addElement(Long.valueOf(CREATE_));
          cmds.addElement(Long.valueOf(CDF_));
            item1.addElement("path");                    /* in */
            item1.addElement("Ljava/lang/String;");
          cmds.addElement(item1);
            item2.addElement("numDims");      /* in - not used for Z var */
            item2.addElement("J");
          cmds.addElement(item2);
            item3.addElement("dimSizes");     /* in - not used for Z var */
            item3.addElement("[J");
          cmds.addElement(item3);
            item4.addElement("id");           /* out */
            item4.addElement("J");
          cmds.addElement(item4);
	  cmds.addElement(Long.valueOf(NULL_));

        theCDF.executeCommand((CDFObject)theCDF, cmds);

	String pathT = theCDF.FindCDFName(path);
	if (pathT != null) 
	  theCDF.theFile = new File(pathT);
	theCDF.selectzMode(zMODEon2);
	theCDF.selectReadOnlyMode(READONLYoff);
        theCDF.getCDFInfo();
        theCDF.toGetAttrVar = 0;
	return theCDF;
    }

    /***********************************************************************
     * Open a CDF file for read/write, the default mode for opening a CDF.  
     * If the user wants only to read the file, the file must be opened in
     * read-only mode as following:
     * <PRE>
     *     CDF cdf = CDF.open(fileName, READONLYon);
     * </PRE>
     *
     * Note: Opening a file with read/write mode will cause the checksum
     *       signature to be recomputed every time the file is closed.
     *       (NEW) Each open CDF file is subjected to a default data 
     *       validating process (some overheads) that will perform 
     *       sanity checks. To overwrite it, you can use one of two ways:
     *       1) Use the CDF static method setValidate before calling the
     *          open method:
     *          CDF.setValidate (VALIDATEFILEoff);
     *       2) Set the environment variable CDF_VALIDATE (CDF$VALIDATE
     *          on VMS) to no 
     *
     * @param path the full pathname of the CDF file to be opened <P>
     * @return the CDF object that represents the CDF file the user
     *         requested for opening <P>
     * @exception CDFException if there was a major problem opening a file
     *            Not always that a CDFException will be thrown. It is good
     *            pratice to check the status from this open method to see
     *            if some others problems, e.g., invalid checksum is being
     *            detected, may occur. Use something like the followings
     *            <PRE>
     *              if (cdf.getStatus() != CDF_OK)
     *              {
     *                if (cdf.getStatus() == CHECKSUM_ERROR)
     *                  ......
     *              }
     *            </PRE>
     *            where cdf is the returned object from the open method.
     *            It is up to each individual to determine whether to 
     *            continue to use a CDF file with an error like checksum.
     ***********************************************************************/
    public static CDF open(String path) throws CDFException
    {

	return CDF.open(path, READONLYoff);
    }

    /***********************************************************************
     * Open a CDF file.  A CDF file can be opened in read-only or
     * read/write mode.  If a file is opened in read-only mode, the user
     * can only read values out of the file.  Any operation other than 
     * reading data will throw a CDFException.  If the user wants to 
     * modify the contents of a file, the file must be opened in
     * read/write mode as following: 
     * <PRE>
     *     CDF cdf = CDF.open(fileName, READONLYoff);
     * </PRE>
     *
     * @param path the full pathname of the CDF file to be opened <P>
     * @param readOnly read-only flag that should be one the following: 
     *                 <UL> 
     *                   <LI>READONLYon - opens the file in read only mode. 
     *                   <LI>READONLYoff - opens the file in read/write mode
     *                 </UL> <P>
     * @return the CDF object that represents the CDF file the user 
     *         requested for opening <P>
     * @exception CDFException if there was a major problem opening a file
     *            Not always that a CDFException will be thrown. It is good
     *            pratice to check the status from this open method to see
     *            if some others problems, e.g., invalid checksum is being
     *            detected, may occur. Use something like the followings
     *            <PRE>
     *              if (cdf.getStatus() != CDF_OK)
     *              {
     *                if (cdf.getStatus() == CHECKSUM_ERROR)
     *                  ......
     *              }
     *            </PRE>
     *            where cdf is the returned object from the open method.
     *            It is up to each individual to determine whether to 
     *            continue to use a CDF file with an error like checksum.
     ***********************************************************************/
    public static CDF open(String path, long readOnly) throws CDFException
    {

	CDF theCDF = new CDF(path, new CDFNativeLibrary());
	// theCDF.theFile = new File(path);
	theCDF.infoWarning = 0; /* Set to off only when opening the file */

        Vector   cmds  = new Vector();
        Vector   item1 = new Vector();
        Vector   item2 = new Vector();

        // build the open vector
        cmds.addElement(Long.valueOf(OPEN_));
          cmds.addElement(Long.valueOf(CDF_));
            item1.addElement("path");
            item1.addElement("Ljava/lang/String;");
          cmds.addElement(item1);
            item2.addElement("id");
            item2.addElement("J");
          cmds.addElement(item2);
        cmds.addElement(Long.valueOf(NULL_));
	
        theCDF.executeCommand((CDFObject)theCDF, cmds);
	long statusopen = theCDF.getStatus();
/*
	if (statusopen != CDF_OK) 
	  throw new CDFException(CDF.getStatusText(statusopen));
*/
	String pathT = theCDF.FindCDFName(path);
	if (pathT != null)
	  theCDF.theFile = new File(pathT);
        // Select for read only mode
	theCDF.selectReadOnlyMode(readOnly);
	// Select for zMode - this is the only mode supported
	theCDF.selectzMode(zMODEon2);
        theCDF.getCDFInfo();
	if (statusopen < theCDF.getStatus()) theCDF.setStatus(statusopen);
        theCDF.toGetAttrVar = 1;
        return theCDF;

    }

    private void getAttributesandVariables() throws CDFException
    {
        if (this.toGetAttrVar == 0) return;
	// Get the attributes out, if any, to fill into attributes Vector
	long attrID, varID, n;
        n = this.numAttrs;       
	Attribute curAttr;
	for (attrID = 0 ; attrID < n; attrID++)
	    curAttr = Attribute.retrieve(this, attrID);
	// Get the zVariables out, if any, to fill into variables Vector

	n = this.numZvars;
	Variable v = null;
	for (varID=0; varID < n; varID++) 
	    v = Variable.retrieve(this, varID);
        this.toGetAttrVar = 0;
    }


    /**
     * Retrieve library version/release/increment/sub_increment information 
     * associated with the CDF library.
     *
     * @return The library version in string
     * @exception CDFException If there was a problem retrieving the
     *                         information associated with this CDF file
     */
    public static String getLibraryVersion() throws CDFException
    {
        CDF theCDF = new CDF(new CDFNativeLibrary());

        Vector   cmds  = new Vector();
        Vector   item1 = new Vector();
        Vector   item2 = new Vector();
        Vector   item3 = new Vector();
        Vector   item4 = new Vector();

        // build the open vector
        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(LIB_VERSION_));
            item1.addElement("libVersion");
            item1.addElement("J");
          cmds.addElement(item1);
	  cmds.addElement(Long.valueOf(LIB_RELEASE_));
            item2.addElement("libRelease");
            item2.addElement("J");
          cmds.addElement(item2);
          cmds.addElement(Long.valueOf(LIB_INCREMENT_));
            item3.addElement("libIncrement");
            item3.addElement("J");
          cmds.addElement(item3);
	  cmds.addElement(Long.valueOf(LIB_subINCREMENT_));
            item4.addElement("libsubIncrement");
            item4.addElement("Ljava/lang/String;");
          cmds.addElement(item4);
        cmds.addElement(Long.valueOf(NULL_));

        theCDF.executeCommand((CDFObject)theCDF, cmds);
        String subInc = theCDF.libsubIncrement;
        String subPar;
        if (subInc.equals("") || subInc.equals(" ") || 
            subInc.trim().length() == 0)
          subPar = "";
        else
          subPar = "_";

	return new StringBuffer().append(theCDF.libVersion).append(".")
				 .append(theCDF.libRelease)
				 .append(".").append(theCDF.libIncrement)
				 .append(subPar)
				 .append(theCDF.libsubIncrement).toString();

    }

    /**
     * Retrieve library copyright information associated with the CDF library.
     *
     * @return the string for CDF copy right note
     * @exception CDFException If there was a problem retrieving the
     *                         information associated with this CDF file
     */
    public static String getLibraryCopyright() throws CDFException 
    {
        CDF theCDF = new CDF(new CDFNativeLibrary());

        Vector   cmds  = new Vector();
        Vector   item1 = new Vector();

        // build the open vector
        cmds.addElement(Long.valueOf(GET_));
          cmds.addElement(Long.valueOf(LIB_COPYRIGHT_));
            item1.addElement("libCopyright");
            item1.addElement("Ljava/lang/String;");
          cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

        theCDF.executeCommand((CDFObject)theCDF, cmds);

        return theCDF.libCopyright;
    }

    /**
     * Retrieve all metadata information associated with this CDF file. 
     *
     * @exception CDFException If there was a problem retrieving the
     *                         information associated with this CDF file
     */
    private synchronized void getCDFInfo() 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 item7  = new Vector();
        Vector item8  = new Vector();
        Vector item9  = new Vector();
        Vector item10  = new Vector();
        Vector item11  = new Vector();
        Vector item12  = new Vector();
        Vector item13  = new Vector();
        Vector item14  = new Vector();
	Vector item15  = new Vector();
	Vector item16  = new Vector();
	Vector itemA  = new Vector();

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

        cmds.addElement(Long.valueOf(GET_));
           cmds.addElement(Long.valueOf(CDF_ENCODING_));
              item0.addElement("encoding");
              item0.addElement("J");
           cmds.addElement(item0);
           cmds.addElement(Long.valueOf(CDF_FORMAT_));
              item1.addElement("format");
              item1.addElement("J");
           cmds.addElement(item1);
           cmds.addElement(Long.valueOf(CDF_VERSION_));
              item2.addElement("vers");
              item2.addElement("J");
           cmds.addElement(item2);
           cmds.addElement(Long.valueOf(CDF_RELEASE_));
              item3.addElement("rel");
              item3.addElement("J");
           cmds.addElement(item3);
           cmds.addElement(Long.valueOf(CDF_INCREMENT_));
              item4.addElement("inc");
              item4.addElement("J");
           cmds.addElement(item4);
           cmds.addElement(Long.valueOf(CDF_MAJORITY_));
              item5.addElement("majority");
              item5.addElement("J");
           cmds.addElement(item5);
           cmds.addElement(Long.valueOf(CDF_NUMATTRS_));
              item6.addElement("numAttrs");
              item6.addElement("J");
           cmds.addElement(item6);
           cmds.addElement(Long.valueOf(CDF_NUMgATTRS_));
              item7.addElement("numGattrs");
              item7.addElement("J");
           cmds.addElement(item7);
           cmds.addElement(Long.valueOf(CDF_NUMvATTRS_));
              item8.addElement("numVattrs");
              item8.addElement("J");
           cmds.addElement(item8);
           cmds.addElement(Long.valueOf(CDF_NUMrVARS_));
              item9.addElement("numRvars");
              item9.addElement("J");
           cmds.addElement(item9);
           cmds.addElement(Long.valueOf(CDF_NUMzVARS_));
              item10.addElement("numZvars");
              item10.addElement("J");
           cmds.addElement(item10);
           cmds.addElement(Long.valueOf(CDF_CHECKSUM_));
              item15.addElement("checksum");
              item15.addElement("J");
           cmds.addElement(item15);
           cmds.addElement(Long.valueOf(CDF_LEAPSECONDLASTUPDATED_));
              item16.addElement("leapSecondLastUpdated");
              item16.addElement("J");
           cmds.addElement(item16);

        cmds.addElement(Long.valueOf(GET_));
           cmds.addElement(Long.valueOf(CDF_COPYRIGHT_));
              item11.addElement("copyright");
              item11.addElement("Ljava/lang/String;");
           cmds.addElement(item11);
           cmds.addElement(Long.valueOf(CDF_COMPRESSION_));
              item12.addElement("cType");
              item12.addElement("J");
           cmds.addElement(item12);
              item13.addElement("cParms");
              item13.addElement("[J");
           cmds.addElement(item13);
              item14.addElement("cPct");
              item14.addElement("J");
           cmds.addElement(item14);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();
        executeCommand((CDFObject)this, cmds);

        version = new StringBuffer().append(vers).append(".").append(rel)
				    .append(".").append(inc).toString();
        closed = false;
    }

    /**
     * Closes this CDF file.  It is essential that a CDF that has been 
     * created or modified by an application be closed before the program 
     * exits.  If the CDF is not closed, the file will be corrupted and
     * unreadable.  This is because the cache buffers maintained by the 
     * CDF library will not have been written to the CDF file(s). <P>
     *
     * The following example closes a CDF file:
     * <PRE>
     *     cdf.close();
     * </PRE>
     *
     * @exception CDFException if there was a problem closing the CDF file
     */
    public synchronized void close() throws CDFException
    {
        if (!closed) {
            Vector   cmds = new Vector();
            Vector   item = new Vector();

            cmds.addElement(Long.valueOf(SELECT_));
              cmds.addElement(Long.valueOf(CDF_));
                 item.addElement("id");
                 item.addElement("J");
              cmds.addElement(item);

            cmds.addElement(Long.valueOf(CLOSE_));
              cmds.addElement(Long.valueOf(CDF_));
            cmds.addElement(Long.valueOf(NULL_));
            id = getID();
            executeCommand((CDFObject)this, cmds);

            closed = true;
        }
    }

    /**
     * Gets the id of this CDF file. 
     * @return the id of this CDF file
     */
    public synchronized long getID()
    {
        return id;
    }

    /**
     * Gets the encoding method defined for this CDF.
     *
     * @return The encoding method defined for this CDF file.  One of the
     *         encoding methods described in the setEncoding method is
     *         returned.
     */
    public synchronized long getEncoding()
    {
        return encoding;
    }

    /**
     * Defines the encoding method to be used for this CDF.  A CDF's data
     * encoding affects how its attribute entry and variable data values
     * are stored.  By default, attribute entry and variable data values
     * passed into the CDF library are always stored using the host 
     * machine's native encoding.  For example, if a CDF file is created
     * without specifying what encoding method should be should on a IBM
     * PC, the IBMPC_ENCODING method is used.  This method becomes useful
     * if someone wants to create a CDF file that will be read on a 
     * machine that is different from the machine the CDF file was created.
     * A CDF with any of the supported encodings may be read from and 
     * written to any supported computer.  See section 2.2.8 of the CDF
     * User's Guide for a detailed description of the encodings listed below.
     *
     * @param encoding the encoding method to be used for this CDF that 
     *                 should be one of the following:
     *                 <UL> 
     *                    <LI>HOST_ENCODING
     *                    <LI>NETWORK_ENCODING
     *                    <LI>SUN_ENCODING
     *                    <LI>VAX_ENCODING
     *                    <LI>DECSTATION_ENCODING
     *                    <LI>SGi_ENCODING
     *                    <LI>IBMPC_ENCODING
     *                    <LI>IBMRS_ENCODING
     *                    <LI>PPC_ENCODING
     *                    <LI>HP_ENCODING
     *                    <LI>NeXT_ENCODING
     *                    <LI>ALPHAOSF1_ENCODING
     *                    <LI>ALPHAVMSd_ENCODING
     *                    <LI>ALPHAVMSg_ENCODING
     *                    <LI>ALPHAVMSi_ENCODING
     *                 </UL> <P>
     * @exception CDFException if there was a problem setting the requested
     *                         encoding method
     */
    public synchronized void setEncoding(long encoding) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(CDF_ENCODING_));
              item0.addElement("encodingX");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

	encodingX = encoding; /* temporary holding place */
//	select();
	id = getID();

        executeCommand((CDFObject)this, cmds);

	this.encoding = encoding; /* set it only after the file is changed */
    }

    /**
     * Defines the CDF decoding method to be used for this CDF.  A CDF's
     * decoding affects how its attribute entry and variable data values are
     * passed out to a calling application.  The decoding for a CDF may be
     * selected any number of times while the CDF is open.  Selecting a
     * decoding does not affect how the values are store in the CDF file(s) -
     * only how the values are decoded by the CDF library. 
     *
     * @param decoding the decoding method to be used for this CDF that
     *                 should be one of the following:
     *                 <UL>
     *                    <LI>HOST_DECODING - this is the default decoding
     *                    <LI>NETWORK_DECODING
     *                    <LI>SUN_DECODING
     *                    <LI>VAX_DECODING
     *                    <LI>DECSTATION_DECODING
     *                    <LI>SGi_DECODING
     *                    <LI>IBMPC_DECODING
     *                    <LI>IBMRS_DECODING
     *                    <LI>PPC_DECODING
     *                    <LI>HP_DECODING
     *                    <LI>NeXT_DECODING
     *                    <LI>ALPHAOSF1_DECODING
     *                    <LI>ALPHAVMSd_DECODING
     *                    <LI>ALPHAVMSg_DECODING
     *                    <LI>ALPHAVMSi_DECODING
     *                 </UL> <P>
     * @exception CDFException if there was a problem selecting the 
     *                         requested decoding method
     */
    public synchronized void selectDecoding(long decoding) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

        id = getID();
        cmds.addElement(Long.valueOf(SELECT_));
           cmds.addElement(Long.valueOf(CDF_));
              itemA.addElement("id");
              itemA.addElement("J");
           cmds.addElement(itemA);

           cmds.addElement(Long.valueOf(CDF_DECODING_));
              item0.addElement("decoding");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	this.decoding = decoding;
	id = getID();

        executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the CDF decoding method defined for this CDF.
     *
     * @return The decoding method set for this CDF file.  One of the decoding
     *         methods defined in the selectDecoding method is returned. <P>
     * @exception CDFException if there was a problem getting the 
     *                         decoding method set for this CDF file
     */
    public synchronized long confirmDecoding() throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(CDF_DECODING_));
              item0.addElement("decoding");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();
        executeCommand((CDFObject)this, cmds);

	return this.decoding;
    }

    /**
     * Defines the number of 512-byte cache buffers to be used for the dotCDF 
     * file (for the current CDF).  The concepts Chapter in the CDF User's
     * Guide describes the caching scheme used by the CDF library. 
     *
     * @param cacheSize the number of 512-byte cache buffers <P>
     * @exception CDFException if there was a problem setting the CDF 
     *                         cache size 
     */
    public synchronized void selectCDFCacheSize(long cacheSize) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

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

//	select();
	this.cacheSize = cacheSize;
	id = getID();

        executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the CDF cache size (the number of 512-byte cache buffers) set 
     * for this CDF.
     *
     * @return the number of 512-byte cache buffers set for this CDF <P>
     * @exception CDFException if there was a problem getting the CDF 
     *                         cache size
     */
    public synchronized long confirmCDFCacheSize() throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

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

//	select();
	id = getID();

        executeCommand((CDFObject)this, cmds);

	return this.cacheSize;
    }

    /**
     * Defines whether to translate -0.0 to 0.0 for reading or writing.  
     * Negative floating-point zero (-0.0) is legal on computers that use 
     * IEEE 754 floating-point representation (e.g. most UNIX-based
     * computers and the PC) but is illegal on VAXes and DEC alphas running 
     * OpenVMS operating system.  If this mode disabled, a warning
     * (NEGATIVE_FP_ZERO) is returned when -0.0 is read from a CDF (and the
     * decoding is that of a VAX or DEC Alpha running OpenVMS) or written
     * to a CDF (and the encoding is that of a VAX or DEC Alpha running i
     * OpenVMS).
     *
     * @param negtoPosfp0 flag to translate -0.0 to 0.0 (NEGtoPOSfp0on = on,
     *                    NEGtoPOSfp0off = off) <P>
     *
     * @exception CDFException if there was a problem setting the -0.0 to 
     *                         0.0 translation flag 
     */
    public synchronized void selectNegtoPosfp0(long negtoPosfp0) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

           cmds.addElement(Long.valueOf(CDF_NEGtoPOSfp0_MODE_));
              item0.addElement("negtoPosfp0");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	this.negtoPosfp0 = negtoPosfp0;
	id = getID();

        executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the -0.0 to 0.0 translation flag set for this CDF.
     *
     * @return flag to translate -0.0 to 0.0 (NEGtoPOSfp0on = on, 
     *         NEGtoPOSfp0off = off) <P>
     * @exception CDFException if there was a problem getting the value
     *                         of the -0.0 to 0.0 translation flag
     */
    public synchronized long confirmNegtoPosfp0() throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(CDF_NEGtoPOSfp0_MODE_));
              item0.addElement("negtoPosfp0");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();

        executeCommand((CDFObject)this, cmds);

	return this.negtoPosfp0;
    }

    /**
     * Gets the CDF format defined for this CDF.
     *
     * @return the format of this CDF (SINGLE_FILE = single-file CDF, 
     *         MULTI_FILE = multi-file CDF)
     */
    public synchronized long getFormat() {
        return this.format;
    }

    /**
     * Specifies the format of this CDF.  A CDF's format can't be changed
     * once any variables are created.  See section 1.4 of the CDF User's
     * Guide for more detailed information about the file format options.
     *
     * @param format the CDF file format to be used that should be one
     *               of the following: 
     *               <UL>
     *                  <LI>SINGLE_FILE - This is the default.  The CDF 
     *                                    consists of only one file. 
     *                  <LI>MULTI_FILE - The CDF consists of one header file
     *                                   for control and attribute data and one 
     *                                   additional file for each variable 
     *                                   in the CDF.
     *               </UL><P>
     * @exception CDFException if there was a problem setting a file format
     */
    public synchronized void setFormat(long format) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(CDF_FORMAT_));
              item0.addElement("formatX");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

	this.formatX = format;	
	id = getID();
//	select();
        executeCommand((CDFObject)this, cmds);

	/* Set format only after the file is successfully changed. Otherwise */
        /* an exception is thrown and the following step will not be executed.*/
        this.format = format;
    }

    /**
     * Gets the CDF library version that was used to create this CDF 
     * (e.g. 2.6.7, etc.).
     *
     * @return the CDF libray version number that was used to create this CDF
     */
    public synchronized String getVersion() {
        return this.version;
    }

    /**
     * Gets the variable majority defined for this CDF.
     *
     * @return the variable majority defined for this CDF 
     *         (ROW_MAJOR = row major, COLUMN_MAJOR = column major)
     */
    public synchronized long getMajority() {
        return this.majority;
    }

    /**
     * Sets the variable majority for this CDF.  The variable majority of a CDF 
     * describes how variable values within each variable array (record)
     * are stored.  Each variable in a CDF has the same majority.
     *
     * @param majority The majority to be used in storing data (ROW_MAJOR = row major, 
     *        COLUMN_MAJOR = column major) <P>
     * @exception CDFException if a problem occurred in setting a majority
     */
    public synchronized void setMajority(long majority) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA  = new Vector();

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

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(CDF_MAJORITY_));
              item0.addElement("majorityX");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

	this.majorityX = majority;
	id = getID();
//	select();
        executeCommand((CDFObject)this, cmds);

	this.majority = majority;
    }

    /**
     * Gets the total number of global and variable attributes in this CDF.
     *
     * @return the total number of global and variable attributes in this CDF
     */
    public synchronized long getNumAttrs()
    { 
      try {
	getAttributesandVariables();
        return attributes.size();
      } catch (Exception ex) {
        return 0L;
      }

    }

    /**
     * Gets the number of global attributes in this CDF.
     *
     * @return the number of global attributes in this CDF file
     */
    public synchronized long getNumGattrs()
    {
        long count = 0;
        Attribute a;
        try {
	  getAttributesandVariables();
          for (Enumeration e=attributes.elements(); e.hasMoreElements();) {
            a = (Attribute)e.nextElement();
            if (a.getScope() == GLOBAL_SCOPE)
              count++;
          }
          return count;
	} catch (Exception ex) {
          return 0L;
        }
    }

    /**
     * Gets the number of variable attributes in this CDF.  Since r variables
     * are not supported by the CDF Java APIs, the number of z variables is
     * always returned.  
     *
     * @return the number of variable attributes in this CDF file
     */
    public synchronized long getNumVattrs()
    {
        long count = 0;
        Attribute a;
	try {
	  getAttributesandVariables();
          for (Enumeration e=attributes.elements(); e.hasMoreElements();) {
            a = (Attribute)e.nextElement();
            if (a.getScope() == VARIABLE_SCOPE)
              count++;
          }
          return count;
        } catch (Exception ex) {
          return 0L;
        }

    }

    /**
     * Gets the number of r variables.  Zero is returned since r variables
     * are not supported.  Z variables can do everything r variables
     * can do plus more.
     *
     * @return the number of r variables in this CDF file
     */
    public synchronized long getNumRvars() 
    {

        return this.numRvars;
    }

    /**
     * Gets the number of z variables in this CDF file.
     *
     * @return the number of z variables in this CDF file
     */
    public synchronized long getNumZvars()
    {
      try {
	getAttributesandVariables();
	return (long)variables.size();
      } catch (Exception ex) {
        return 0L;
      }

    }

    /**
     * Gets the CDF copyright statement for this CDF.
     *
     * @return the CDF copyright statement
     */
    public synchronized String getCopyright() {
        return this.copyright;
    }

    /**
     * Sets the desired read-only mode.  See the description of the read-only
     * flag defined in the open method in this class for details.
     *
     * Caveat: Arbitrary changing the read-only mode to READONLYon while 
     *         doing writing/updating will cause a problem to the file if
     *         the checksum bit is turned on (as the checksum signature may
     *         not get updated and a warning for data integrity will be issued 
     *         when the file is open later).    
     *
     * @param readOnly read-only flag (READONLYon = on, READONLYoff = off) <P>
     * @exception CDFException if a problem occurred in setting a flag
     */
    public synchronized void selectReadOnlyMode(long readOnly) throws CDFException
    {
        Vector   cmds  = new Vector();
        Vector   item1 = new Vector();
        Vector   itemA = new Vector();

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

          cmds.addElement(Long.valueOf(CDF_READONLY_MODE_));
            item1.addElement("readOnly");
            item1.addElement("J");
          cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

	this.readOnly = readOnly;
	id = getID();
//	select();
        executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the value of the read-only mode flag set for this CDF file.
     *
     * @return read-only flag (READONLYon = on, READONLYoff = off) <P>
     * @exception CDFException if a problem occurred in getting the value of
     *                         the read-only flag set for this CDF file
     */
    public synchronized long confirmReadOnlyMode() throws CDFException
    {
        Vector   cmds  = new Vector();
        Vector   item1 = new Vector();
        Vector   itemA = new Vector();

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

        cmds.addElement(Long.valueOf(CONFIRM_));
          cmds.addElement(Long.valueOf(CDF_READONLY_MODE_));
            item1.addElement("readOnly");
            item1.addElement("J");
          cmds.addElement(item1);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();
        executeCommand((CDFObject)this, cmds);

	return this.readOnly;
    }

    /**
     * Gets the compression type set for this CDF.
     *
     * @return the compression type set for this CDF - one of the 
     *         following is returned:
     *         <UL>
     *           <LI>NO_COMPRESSION - no compresssion
     *           <LI>RLE_COMPRESSION - Run-length compression
     *           <LI>HUFF_COMPRESSION - Huffman compression
     *           <LI>AHUFF_COMPRESSION - Adaptive Huffman compression
     *           <LI>GZIP_COMPRESSION - Gnu's "zip" compression
     *         </UL>
     */
    public synchronized long getCompressionType() {
        return this.cType;
    }

    /**
     * Gets the compression percentage set for this CDF.
     *
     * @return the compression percentage set for this CDF.
     */
    public synchronized long getCompressionPct() {
        return this.cPct;
    }

    /**
     * Gets the compression parameters set for this CDF.  See the description 
     * of the setCompression method in this class for more information.
     *
     * @return the compression parameter set for this CDF
     */
    public synchronized long[] getCompressionParms() {
        return this.cParms;
    }

    /**
     * Sets the compression type and parameters for this CDF.
     *
     * @param cType the compression type to be applied to this CDF that should 
     *              be one of the following: 
     *        <UL>
     *           <LI>NO_COMPRESSION - no compresssion
     *           <LI>RLE_COMPRESSION - Run-length compression. Currently, 
     *                  only the run-length encoding of zeros is supported.
     *                  The compression parameter must be set to RLE_OF_ZEROs.
     *           <LI>HUFF_COMPRESSION - Huffman compression. Currently,
     *                  only optimal encoding trees are supported.  The
     *                  compression parameter must be set to 
     *                  OPTIMAL_ENCODING_TREES.
     *           <LI>AHUFF_COMPRESSION - Adaptive Huffman compression.
     *                  Currently, only optimal encoding trees are supported.  
     *                  The compression parameter must be set to 
     *                  OPTIMAL_ENCODING_TREES.
     *           <LI>GZIP_COMPRESSION - Gnu's "zip" compression.  The
     *                  compression parameter may range from 1 to 9.  
     *                  1 provides the least compression and requires less
     *                  execution time.  9 provides the most compression but
     *                  requires the most execution time.
     *        </UL><P>
     *
     * @param cParms Compression parameter.  There is only one parameter for 
     *               all the compression methods described above.  <P>
     *
     * @exception CDFException if a problem occurred in setting the 
     *                         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();

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

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(CDF_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();

//	select();
        executeCommand((CDFObject)this, cmds);

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

    /**
     * Gets the string representation of the compression type and parameters 
     * defined for this CDF.
     *
     * @return the string representation of the compression type and parameters
     *         (e.g. GZIP.9, RLE.0, etc.) defined for this CDF <P>
     * @exception CDFException if a problem occurred in getting the 
     *                         compression type and parameters set for this CDF
     */
    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();
    }

    /**
     * Selects the zMode to be used for this CDF.  zMODEon2 is the only mode
     * supported since it is far superior and efficient than the zMODEon1 and
     * zMODEoff modes.
     *  
     * @param zmode The Zmode in which this CDF is supposed to operate under <P>
     * @exception CDFException If a problem occurred in setting the 
     *            desired Z mode
     */
    private void selectzMode(long zmode) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();

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

           cmds.addElement(Long.valueOf(CDF_zMODE_));
              item0.addElement("zmode");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

	this.zmode = zmode;
	id = getID();
//      select();
        executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the zMode set for this CDF.
     * 
     * @return 'zMODEon2' is always returned since it is the only mode
     *          supported by the CDF Java APIs. 
     *
     * @exception CDFException if a problem occurred in getting the zmode set
     *                         for this CDF file
     */
    public synchronized long confirmzMode() throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();

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

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(CDF_zMODE_));
              item0.addElement("zmode");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();
	executeCommand((CDFObject)this, cmds);

	return this.zmode;
    }

    /**
     * Sets the number of 512-byte cache buffers to be used for the compression
     * scratch file (for the current CDF).  The Concepts Chapter in the CDF
     * User's Guide describes the caching scheme used by the CDF library.
     * 
     * @param compressCacheSize the number of 512-byte cache buffers to be 
     *                          used <P>
     * @exception CDFException if a problem occurs in setting the cache size
     */
    public synchronized void selectCompressCacheSize(long compressCacheSize) 
       throws CDFException
    {

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

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

           cmds.addElement(Long.valueOf(COMPRESS_CACHESIZE_));
              item0.addElement("compressCacheSize");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

	this.compressCacheSize = compressCacheSize;
	id = getID();
//	select();

        executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the number of 512-byte cache buffers being used for the
     * compression scratch file (for the current CDF). 
     * 
     * @return the number of 512-byte cache buffers being used 
     * @exception CDFException if a problem occurs in getting the 
     *                         cache size defined 
     */
    public synchronized long confirmCompressCacheSize() throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();

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

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(COMPRESS_CACHESIZE_));
              item0.addElement("compressCacheSize");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();
        executeCommand((CDFObject)this, cmds);

        return this.compressCacheSize;
    }

    /**
     * Sets the number of 512-byte cache buffers to be used for the staging 
     * scratch file (for the current CDF).  The Concepts Chapter in the CDF 
     * User's Guide describes the caching scheme used by the CDF library.
     *
     * @param stageCacheSize the Number of cache buffers to be used 
     * @exception CDFException if a problem occurs in setting the 
     *                         cache size 
     */
    public synchronized void selectStageCacheSize(long stageCacheSize) 
		throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();

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

           cmds.addElement(Long.valueOf(STAGE_CACHESIZE_));
              item0.addElement("stageCacheSize");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

	this.stageCacheSize = stageCacheSize;
	id = getID();
//	select();

        executeCommand((CDFObject)this, cmds);

    }

    /**
     * Gets the number of 512-byte cache buffers defined for the 
     * staging scratch file.
     *
     * @return the number of 512-byte cache buffers defined for the
     *         staging scratch file
     * @exception CDFException if a problem occurs in getting the number
     *            of cache buffers defined for the staging scratch file
     */
    public synchronized long confirmStageCacheSize() throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();

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

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(STAGE_CACHESIZE_));
              item0.addElement("stageCacheSize");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();
        executeCommand((CDFObject)this, cmds);

        return this.stageCacheSize;

    }

   /**
    * Gets the name of this CDF.
    * @return the name of this CDF
    */
    public synchronized String getName() {
        return this.path;
    }

   /**
    * Renames the current CDF.  It's here because CDF.java implements the
    * CDFObject interface that defines three methods: rename, delete, 
    * getname.  This method doesn't do anything now, but it will be
    * refined to rename a single-CDF and multi-CDF files in the future.
    *
    * @param path the new CDF name to be renamed to
    */
    public synchronized void rename(String path) {
	this.path = path;

        theFile.renameTo(new File(path));
        // build the rename command
    }

   /**
    * Deletes this CDF file.
    * @exception CDFException if a problem occurs in deleting this CDF file
    */
    public synchronized void delete() throws CDFException
    {
        Vector cmd = new Vector();
        Vector itemA  = new Vector();

        cmd.addElement(Long.valueOf(SELECT_));
           cmd.addElement(Long.valueOf(CDF_));
              itemA.addElement("id");
              itemA.addElement("J");
           cmd.addElement(itemA);

        cmd.addElement(Long.valueOf(DELETE_));
	  cmd.addElement(Long.valueOf(CDF_));
	cmd.addElement(Long.valueOf(NULL_));

//	select();
	id = getID();

        executeCommand((CDFObject)this, cmd);

    }

   /**
    * Saves this CDF file without closing.  There are times the users will 
    * have to save the contents of a CDF file before some operations can be
    * performed.  For example, a CDF file must be saved first before records
    * can be deleted properly for variables that are defined to have 
    * sparse and/or compressed records.
    *
    * @exception CDFException if there was a problem saving the
    *                         contents of this CDF file
    */
    public synchronized void save() throws CDFException
    {
        Vector cmd = new Vector();
        Vector itemA  = new Vector();
/*
        cmd.addElement(Long.valueOf(SELECT_));
           cmd.addElement(Long.valueOf(CDF_));
              itemA.addElement("id");
              itemA.addElement("J");
           cmd.addElement(itemA);
*/
        cmd.addElement(Long.valueOf(SAVE_));
/*
	cmd.addElement(Long.valueOf(CDF_));
        cmd.addElement(Long.valueOf(NULL_));
*/
	id = getID();
        executeCommand((CDFObject)this, cmd);

    }

   /**
    * Sets the file backward flag so that when a new CDF file is created, 
    * it will be created in either in the older V2.7 version or the current
    * library version, i.e., V3.*. It only works for V3.* library.
    * Setting this flag will overwrite environment varibale CDF_FILEBACKWARD
    * (or CDF$FILEBACKWARD on OpenVMS) if it is set. All CDF files created
    * after this static method call will be affected.
    *
    * @param flag The flag indicates whether to create a new CDF(s) in the backward
    *             version. BACKWARDFILEon means a backward file(s) is to be created
    *             and BACKWARDFILEoff means a V3.* file(s) is to be created. <P>
    * @exception CDFException if there was a problem
    * 
    */
    public static void setFileBackward(long flag) throws CDFException
    {

        String libVersion = CDF.getLibraryVersion();
        if (libVersion.charAt(0) == '3') {
	  CDF theCDF = new CDF(new CDFNativeLibrary()); 
          Vector cmd = new Vector();
          cmd.addElement(Long.valueOf(BACKWARD_));
    	  cmd.addElement(Long.valueOf(flag));
          theCDF.executeCommand((CDFObject)theCDF, cmd);
	  CDF.backwardFlagSet = true;
	  if (flag == BACKWARDFILEon || flag != 0) 
	    CDF.backward = BACKWARDFILEon;
	  else
	    CDF.backward = BACKWARDFILEoff;

	}
    }

   /**
    * Gets the file backward flag.
    *
    * @return The flag indicating whether the CDF file was created in the older 
    *         V2.7 version. It is only applicable for V3.* library. Returns 
    *         true if backward files are to be created, false otherwise. 
    *                         
    */
    public static boolean getFileBackward() {

	if (CDF.backwardFlagSet) {
          if (CDF.backward == BACKWARDFILEon) return true;
	  else return false;
	} else {
          try {
            int val = getFileBackwardEnvVar();
            if (val == 1) return true;
            return false;
          } catch (Exception ex) {
            return false;
          }
        }
    }

   /**
    * Gets the value of the CDF_FILEBACKWARD environment variable. 
    *
    * @return 1 if the environment variable is set to true, 0 if not
    *         set or set to anything else.
    * @exception CDFException if there was a problem
    */
    public static int getFileBackwardEnvVar() throws CDFException
    {

	if (CDF.backwardEnvVar == -1) {
	  CDF theCDF = new CDF(new CDFNativeLibrary());
          Vector cmd = new Vector();
          Vector item = new Vector();

          cmd.addElement(Long.valueOf(GETCDFFILEBACKWARD_));
            item.addElement("fromEnvVar");           /* out */
            item.addElement("J");
          cmd.addElement(item);

          theCDF.executeCommand((CDFObject)theCDF, cmd);
	  CDF.backwardEnvVar = theCDF.fromEnvVar;
	}

        return (int) CDF.backwardEnvVar; 
    }

   /**
    * Gets the value of the CDF_VALIDATE (or CDF$VALIDATE on VMS) 
    * environment variable. 
    *
    * @return 1 if the environment variable is set to true, 0 if not
    *         set or set to anything else.
    * @exception CDFException if there was a problem
    */
    private static int getValidateEnvVar() throws CDFException
    {

	if (CDF.backwardEnvVar == -1) {
	  CDF theCDF = new CDF(new CDFNativeLibrary());
          Vector cmd = new Vector();
          Vector item = new Vector();

          cmd.addElement(Long.valueOf(GETCDFVALIDATE_));
            item.addElement("fromEnvVar");           /* out */
            item.addElement("J");
          cmd.addElement(item);

          theCDF.executeCommand((CDFObject)theCDF, cmd);
	  CDF.validateEnvVar = theCDF.fromEnvVar;
	}

        return (int) CDF.validateEnvVar; 
    }

   /**  
    * Gets the the CDF_LEAPSECONDSTABLE (or CDF$LEAPSECONDSTABLE on VMS) 
    * environment variable. 
    *
    * @return the string the environment variable is set to, null if not
    *         set
    * @exception CDFException if there was a problem
    */
    public static String getLeapSecondsTableEnvVar() throws CDFException
    {

        CDF theCDF = new CDF(new CDFNativeLibrary());
        Vector cmd = new Vector();
        Vector item = new Vector();
        cmd.addElement(Long.valueOf(GETLEAPSECONDSENVVAR_));
          item.addElement("leapTableEnvVar");           /* out */
          item.addElement("Ljava/lang/String;");
        cmd.addElement(item);

        theCDF.executeCommand((CDFObject)theCDF, cmd);

        return theCDF.leapTableEnvVar; 
    }     
          
   /**
    * Gets the value of the CDF_CHECKSUM environment variable.
    *
    * @return 1 if the environment variable is set to MD5, 0 if not
    *         set or set to anything else.
    * @exception CDFException if there was a problem
    */
    public static long getChecksumEnvVar() throws CDFException
    {

        if (CDF.checksumEnvVar == -1) {
          CDF theCDF = new CDF(new CDFNativeLibrary());
          Vector cmd = new Vector();
          Vector item = new Vector();

          cmd.addElement(Long.valueOf(GETCDFCHECKSUM_));
            item.addElement("fromEnvVar");           /* out */
            item.addElement("J");
          cmd.addElement(item);

          theCDF.executeCommand((CDFObject)theCDF, cmd);
          CDF.checksumEnvVar = theCDF.fromEnvVar;
        }

        return CDF.checksumEnvVar;
    }

   /**
    * Sets the file validation mode so that when a CDF file is open, 
    * it will be validated accordingly.
    * Setting this flag will overwrite environment varibale CDF_VALIDATE
    * (or CDF$VALIDATE on OpenVMS) if it is set. If none is set, the default
    * will have the files validated when open. All CDF files open
    * after this static method call will be applied.
    *
    * @param mode The mode indicates whether to validate CDF(s) while open.
    *             <b>VALIDATEFILEon</b> means all files are subjected to ve validated.
    *             <b>VALIDATEFILEoff</b> means no data validation will be performed. <P>
    * @exception CDFException if there was a problem
    * 
    */
    public static void setValidate(long mode) throws CDFException
    {

	  CDF theCDF = new CDF(new CDFNativeLibrary()); 
          Vector cmd = new Vector();
          cmd.addElement(Long.valueOf(VALIDATE_));
    	  cmd.addElement(Long.valueOf(mode));
          theCDF.executeCommand((CDFObject)theCDF, cmd);
          try {
          } catch (Exception ex) {
            System.out.println(" exception getValidateEnvVar...");
          }

	  CDF.validateFlagSet = true;
	  if (mode == VALIDATEFILEon || mode != 0) 
	    CDF.validate = VALIDATEFILEon;
	  else
	    CDF.validate = VALIDATEFILEoff;
    }

   /**
    * Gets the file validation mode.
    *
    * @return The mode indicating whether the CDF file is to be validated
    *         when it is open. Returns true if it will be validated, 
    *         false otherwise. 
    *                         
    */
    public static boolean getValidate() {

	if (CDF.validateFlagSet) {
          if (CDF.validate == VALIDATEFILEon) return true;
	  else return false;
	} else {
          try {
            int val = getValidateEnvVar();
            if (val == 1) return true;
            return false;
          } catch (Exception ex) {
            return true;
          }
        }
    }

    /**
     * Gets the status of the most recent CDF JNI/library function call.
     * This value can be examined and appropriate action can be taken. <P>
     *
     * The following example sends a signal to the JNI code to write a
     * single data to the current CDF. JNI in turn performs the requested 
     * operation.  It then checks to see whether the requested
     * operation was successfully performed or not. 
     * <PRE>
     *     variable.putSingleData(recNum, dimIndicies, data);
     *     long status = cdf.getStatus();
     *     if (status != CDF_OK) {
     *         String statusText = CDF.getStatusText(status);
     *         System.out.println ("status = "+statusText);
     *     }
     * </PRE>
     * @return the status of the most recent CDF JNI/library function call
     */
    public synchronized long getStatus() {
        return cdfStatus;
    }

    private synchronized void setStatus(long inStatus) {
        cdfStatus = inStatus;
    }

    /**
     * Gets the status text of the most recent CDF JNI/library function 
     * call. <P>
     *
     * The following example shows how to obtain the text representation of
     * the status code returned from the getStatus method: 
     * <PRE>
     *     long status = cdf.getStatus();
     *     if (status != CDF_OK) {
     *         String statusText = CDF.getStatusText(status);
     *         System.out.println ("status = "+statusText);
     *     }
     * </PRE>
     *
     * @param statusCode status code to be translated<P>
     * @return she string representation of the passed status code
     */
    public static String getStatusText(long statusCode) {
        StringBuffer statusText = new StringBuffer();

        if (statusCode > 0) 
            statusText.append("INFO: ");
        else if (statusCode < 0 && statusCode > -2000)
            statusText.append("WARNING: ");

        return statusText.append(CDFException.getStatusMsg(statusCode)).toString();
    }

    /**
     * Sets the informational (status code &lt; 0) or warning messages (status 
     * code between -1 and -2000) coming from the CDF JNI/library function 
     * off.  This is the default when a file is opened or created. 
     */
    public synchronized void setInfoWarningOff() {
        infoWarning = 0;
    }

    /**
     * Sets the informational (status code &lt; 0) or warning messages (status 
     * code between -1 and -2000) coming from the CDF JNI/library function 
     * on.  
     */
    public synchronized void setInfoWarningOn() {
        infoWarning = 1;
    }

    /**
     * Selects this CDF.  There is no need to build the entire
     * select cmd vector since this is handled in the native method
     * cdfNativeLib in cdfNativeLibrary.c
     */
    private synchronized final void select() throws CDFException
    {
        Vector cmds = new Vector();

        cmds.addElement(Long.valueOf(NULL_)); // Select this CDF
        id = getID();

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

    }

    /**
     * Gets the name of this CDF.
     * @return the name of this CDF
     */
    public String toString() {
        return path;
    }

    /**
     * Do the necessary cleanup when garbage collector reaps it.
     *
     * @exception java.lang.Throwable if there was a problem doing cleanup
     */
    public void finalize() throws java.lang.Throwable {
        //file.finalize();
        super.finalize();
    }

    /**
     * This is a placeholder for future expansions/extensions.
     * @return CDFDelegate object
     */
    public synchronized CDFDelegate getDelegate(){
        return delegate;
    }
    /**
     * This is a placeholder for future expansions/extensions.
     *
     * @param delegate The CDFDelegate executing the command
     */
    public synchronized void setDelegate(CDFDelegate delegate) {
        this.delegate = delegate;
    }

    /** 
     * executeCommand is where messages get passed to the CDFDelegate.
     * CDFDelegate in turn sends the commands it received to JNI for 
     * processing.
     *
     * @param obj The CDFObject executing the command
     * @param command The command vector
     * @exception CDFException If there was a problem executing the given
     */

    protected synchronized void executeCommand(CDFObject obj, Vector command)
        throws CDFException
    {
//  Ensure that only one operation is allowed in a JNI. 
        synchronized(CDF.Monitor) {
           delegate.cdflib(this, obj, command);
        }
    }

    ///////////////////////////////////////////////
    //                                           //
    //        Attribute handling methods         //
    //                                           //
    ///////////////////////////////////////////////

    /**
     * Gets the id of the given attribute.
     *
     * @param attrName the name of the attribute to check <P>
     * @return the id of the named attribute if it exists, -1 otherwise
     */
    public synchronized long getAttributeID(String attrName)
    {

	int i = 0;
	try {
	  getAttributesandVariables();
	  if (attributes.size() == 0) return -1L;
          if (attrName == null || attrName.trim().length() == 0) return -1L;
	  while (!attributes.elementAt(i).toString().trim().equals(attrName.trim())) {
	    i++;
	    if (i >= (attributes.size())) break;
	  }
	  if (i == attributes.size())
	    return -1L;
	  else
	    return (long) i;
	} catch (Exception ex) {
	  return -1L;
	}
    }
	
    /**
     * Adds an attribute to this CDF.  The Attribute class uses this method 
     * to setup the connection between the CDF object and Attribute object.
     *
     * @param newAttribute the name of the attribute to be added 
     */
    protected final synchronized void addAttribute(Attribute newAttribute) throws CDFException
    {

	attributes.addElement(newAttribute);
    }

    /**
     * Removes an attribute.  The Attribute class uses this to break the 
     * connection between the CDF object and Attribute object.
     *
     * @param oldAttribute the name of the attribute to be removed
     */
    protected final synchronized void removeAttribute(Attribute oldAttribute)
    {
      try {
	getAttributesandVariables();
	attributes.removeElement(oldAttribute);
      } catch (Exception ex) {
      }
    }

    /**
     * Gets the attribute for the given attribute number.<BR><BR> 
     *
     * <B>Note:</B> The attrNum may not necessarily correspond to 
     * the attribute number stored in the CDF file.
     *
     * @param attrNum the attribute number to get
     * @return the Attribute object that corresponds to the requested 
     *         attribute number <P>
     * @exception CDFException if the supplied attribute number does not exist
     */
    public synchronized Attribute getAttribute(long attrNum) throws CDFException
    {
	getAttributesandVariables();
	if (attrNum > attributes.size()) {
	  throw new CDFException(NO_SUCH_ATTR);
	}
	return (Attribute)attributes.elementAt((int)attrNum);
    }

    /**
     * Gets the attribute for the given attribute name. <P>
     *
     * The following example retrieves the attribute named "ValidMin":
     * <PRE>
     *     Attribute validMin = cdf.getAttribute("ValidMin");
     * </PRE>
     *
     * @param attrName the name of the attribute to get <P>
     *
     * @return the Attribute object that corresponds to the requested attribute
     *         name
     * @exception CDFException if the supplied attribute name does not exist
     */
    public synchronized Attribute getAttribute(String attrName) throws CDFException
    {
	getAttributesandVariables();
	long idx = getAttributeID(attrName);
	if (idx == -1) {
	  throw new CDFException(NO_SUCH_ATTR);
	}
	return (Attribute) attributes.elementAt((int)idx);

    }
 
    /**
     * Gets all the global and variable attributes defined for this CDF.
     * 
     * The following example retrieves all the global and variable attributes:
     * <PRE>
     *     Vector attr = cdf.getAttributes();
     * </PRE>
     *
     * @return a vector that contains the global and variable attributes 
     *         defined in this CDF
     */
    public synchronized Vector getAttributes()
    {
      try {
	getAttributesandVariables();
	return attributes;
      } catch (Exception ex) {
        return new Vector();
      }

    }

    /**
     * Gets the global attributes defined for this CDF.
     *
     * @return A vector that contains the global attributes defined in this
     *         CDF
     */
    public synchronized Vector getGlobalAttributes()
    {
      try {
	getAttributesandVariables();
	Vector ga = new Vector();
	Attribute a;
	for (Enumeration e=attributes.elements(); e.hasMoreElements();) {
	    a = (Attribute)e.nextElement();
	    if (a.getScope() == GLOBAL_SCOPE)
		ga.addElement(a);
	}
	return ga;
      } catch (Exception ex) {
        return new Vector(); 
      }

    }

    /**
     * Gets the basic information about this CDF.
     *
     * The returned map has the following form:
     *   "CDFinfo": {
     *     "Format": "SINGLE",
     *     "Version": "3.8.0",
     *     "FileName": "test",
     *     "NumVars": 21,
     *     "Majority": "ROW"
     *     ...
     *     ...
     *   }
     *
     * @return A Map object that contains the basic information about the CDF.
     */
    public synchronized Map readCDFInfo()
    {
      return readCDF (true, true, false, false, false, false);   
    }


    /**
     * Gets the global attributes and their entries defined for this CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values. The epoch data type into encoded date/time string.
     *
     * @return A Map object that contains the global attributes, as the keys,
     *         and entries, as the values. All are of object type. Each entry
     *         is also a map, which consists of entry number as the key and
     *         entry data as the value.
     */
    public synchronized Map readCDFGlobalAttributes()
    {
      return readCDFGlobalAttributes(true);   
    }


    /**
     * Gets the global attributes and their entries defined for this CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values.
     *
     * The returned map has the following form:
     * 
     *   "GLOBAL_ATTR_NAME1": {
     *     "0": ...,
     *     "1": ...
     *   },
     *   "GLOBAL_ATTR_NAME2": {
     *     "0": ...,
     *     "1": [
     *       4294967295,
     *       2147483648
     *     ]
     *   }
     *   "GLOBAL_ATTR_NAME3": {
     *     "0": ...,
     *     "1": ...,
     *     ...
     *     ...
     *   {  
     *   ...
     *   ...
     *
     * @param encoding A true/false flag to indicate whether to convert epoch
     *                 data type into encoded date/time string.
     *
     * @return A Map object that contains the global attributes, as the keys,
     *         and entries, as the values. All are of object type. Each entry
     *         is also a map, which consists of entry number as the key and
     *         entry data as the value.
     */
    public synchronized Map readCDFGlobalAttributes(boolean encoding)
    {
      return readCDFGlobalAttributes(null, encoding);
    }

    /**
     * Gets a specified global attribute's entry(ies) defined for
     * this CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values. The epoch data type into encoded date/time string.
     *
     * @param attrName Aglobal attribute name
     * @return A Map object that contains the global attributes, as the keys,
     *         and entries, as the values. All are of object type. Each entry
     *         is also a map, which consists of entry number as the key and
     *         entry data as the value.
     */
    public synchronized Map readCDFGlobalAttributes(String attrName)
    {
      return readCDFGlobalAttributes(new String[] {attrName}, true);   
    }

    /**
     * Gets a specified list of global attributes and their entries defined for
     * this CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values. The epoch data type into encoded date/time string.
     *
     * @param attrNames An array of global attribute names 
     * @return A Map object that contains the global attributes, as the keys,
     *         and entries, as the values. All are of object type. Each entry
     *         is also a map, which consists of entry number as the key and
     *         entry data as the value.
     */
    public synchronized Map readCDFGlobalAttributes(String[] attrNames)
    {
      return readCDFGlobalAttributes(attrNames, true);   
    }

    /**
     * Gets a specified global attribute's entry(ies) defined for
     * this CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values. The epoch data type into encoded date/time string.
     *
     * @param attrNum A global attribute number
     * @return A Map object that contains the global attributes, as the keys,
     *         and entries, as the values. All are of object type. Each entry
     *         is also a map, which consists of entry number as the key and
     *         entry data as the value.
     */
    public synchronized Map readCDFGlobalAttributes(long attrNum)
    {
      return readCDFGlobalAttributes(new long[] {attrNum}, true);   
    }

    /**
     * Gets a specified list of global attributes and their entries defined for
     * this CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values. The epoch data type into encoded date/time string.
     *
     * @param attrNums An array of global attribute numbers 
     * @return A Map object that contains the global attributes, as the keys,
     *         and entries, as the values. All are of object type. Each entry
     *         is also a map, which consists of entry number as the key and
     *         entry data as the value.
     */
    public synchronized Map readCDFGlobalAttributes(long[] attrNums)
    {
      return readCDFGlobalAttributes(attrNums, true);   
    }

    /**
     * Gets a list of specified global attributes and their entries
     * defined for this CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values.
     * @param attrs An array of attribute names of numbers
     * @param encoding A true/false flag to indicate whether to convert epoch
     *                 data type into encoded date/time string.
     *
     * @return A Map object that contains the global attributes, as the keys,
     *         and entries, as the values. All are of object type. Each entry
     *         is also a map, which consists of entry number as the key and
     *         entry data as the value.
     */
    public synchronized Map readCDFGlobalAttributes(Object attrs, 
                                                    boolean encoding)
    {
      Map gae = new HashMap();
      try {
        int choice = 0, selected = 0;
        if (attrs != null) {
          if (attrs instanceof String[]) {
            choice = 1;
            selected = ((String[])attrs).length;
          } else if (attrs instanceof long[]) {
            choice = 2;
            selected = ((long[])attrs).length;
          }
        } 
        Vector ga = getGlobalAttributes();
	Attribute a;
        boolean found;
	for (Enumeration e=ga.elements(); e.hasMoreElements();) {
	    a = (Attribute)e.nextElement();
            found = true;
            if (choice != 0) {
              found = false;
              for (int ii = 0; ii < selected; ++ii) {
                if (choice == 1) {
                  if (((String[])attrs)[ii].equals(a.getName())) {
                    found = true;
                    break;
                  }
                } else {
                  if (((long[])attrs)[ii] == a.getID()) {
                    found = true;
                    break;
                  }
                }
              }
            }
            if (!found) continue;
            Vector ges = a.getEntries();
            if (ges.size() == 0) {
              gae.put(a.getName(), null);
            } else {
              Map gae1 = new HashMap();
              Entry en;
              for (Enumeration b=ges.elements(); b.hasMoreElements();) {
                en = (Entry)b.nextElement();
                if (en == null) continue;
                Object data = en.getData();
                if (encoding) {
                  long dataType = en.getDataType();
                  if (dataType == CDF_EPOCH) {
                    gae1.put(en.getName(), Epoch.toEncode(data));
                  } else if (dataType == CDF_EPOCH16)
                    gae1.put(en.getName(), Epoch16.toEncode(data));
                  else if (dataType == CDF_TIME_TT2000) {
                    gae1.put(en.getName(), CDFTT2000.toEncode(data));
                  } else
                    gae1.put(en.getName(), data);
                } else
                  gae1.put(en.getName(), data);
              }
              gae.put(a.getName(), gae1);
            }
        }
      } catch (Exception ex) { }
      return gae;
    }

    /**
     * Gets a map of global attributes and variable attributes with no
     * entry data.
     *
     * @return A Map object that contains up to itwo elements, one for global
     *         attributes and one for variable attributes. The value is the
     *         name(s) of the attributes() that has no entry data.
     */
    public synchronized Map readCDFNoEntryAttributes()
    {
      Map noEntry = new HashMap();
      try {
        Vector ga = getGlobalAttributes();
        Vector gattrs = new Vector();
        Vector vattrs = new Vector();
	Attribute a;
	for (Enumeration e=ga.elements(); e.hasMoreElements();) {
	    a = (Attribute)e.nextElement();
            Vector ges = a.getEntries();
            if (ges.size() == 0)
              gattrs.addElement(a.getName());
        }
        if (gattrs.size() > 0)
          noEntry.put ("GlobalAttributes", gattrs); 
        ga = getVariableAttributes();
	for (Enumeration e=ga.elements(); e.hasMoreElements();) {
	    a = (Attribute)e.nextElement();
            Vector ges = a.getEntries();
            if (ges.size() == 0)
              vattrs.addElement(a.getName());
        }
        if (vattrs.size() > 0)
          noEntry.put ("variableAttributes", vattrs); 
      } catch (Exception ex) { }
      if (noEntry.size() > 0)
        return noEntry;
      else
        return null;
    }

    /**
     * Reads all variables' information in the CDF.
     *
     * The returned map has the following form:
     *   "Variables": {
     *      "Var_Name1": {
     *        "VarSpec": {
     *          "NumElements": 1,
     *          ...
     *          ...
     *        }
     *        "VarMetaData" : {
     *          "VALIDMIN": 0
     *          ...
     *        }
     *        "VarData" : {
     *         ...
     *        }
     *      }
     *      "Var_Name2": {
     *        "VarSpec": {
     *          "NumElements": 1,
     *          ...
     *          ...
     *        }
     *        "VarMetaData" : {
     *          "VALIDMIN": 0
     *          ...
     *        }
     *        "VarData" : {
     *         ...
     *        }
     *      }
     *      ...
     *      ...
     *   } 
     * @return A Map object that contains the basic variable information,
     *         its metadata and data from all variables
     * @exception CDFException If there was a problem retrieving the variable
     *                         information from this CDF file
     *
     */
    public synchronized Map readCDFVariables() throws CDFException
    {
      return readCDF(true, false, false, true, true, true);   
    }

    /**
     * Reads all variables' specifications in the CDF.
     *
     * The returned map has the following form:
     *   "Variables": {
     *      "Var_Name1": {
     *        "VarSpec": {
     *          "NumElements": 1,
     *          "PadValue": "0000-01-01T00:00:00.000",
     *          "DataType": "CDF_EPOCH",
     *          "NumDims": 0
     *          ...
     *          ...
     *        }
     *      }
     *      "Var_Name2": {
     *         "VarSpec": {
     *          "NumElements": 1,
     *          "PadValue": "0000-01-01T00:00:00.000",
     *          "DataType": "CDF_EPOCH",
     *          "NumDims": 0
     *          ...
     *          ...
     *         }
     *      }
     *      ...
     *      ...
     *   } 
     *
     * @return A Map object that contains the basic information for all variables
     * @exception CDFException If there was a problem retrieving the variable
     *                         information from this CDF file
     *
     */
    public synchronized Map readCDFVariablesSpec() throws CDFException
    {
      return readCDF (true, false, false, true, false, false);
    }

    /**
     * Reads all variables' metadata in the CDF.
     *
     * The returned map has the following form:
     *   "Variables": {
     *      "Var_Name1": {
     *        "VarMetaData": {
     *          "VALIDMIN": "2010-01-01T00:00:00.000",
     *          "VALIMAX": ...
     *          ...
     *        }
     *      }
     *      "Var_Name2": {
     *         "VarMetaData": {
     *          "VALIMIN": 1,
     *          "VALIMAX": 10,
     *          ...
     *         }
     *      }
     *      ...
     *   } 
     *
     * @return A Map object that contains the metadata for all variables
     * @exception CDFException If there was a problem retrieving the variable
     *                         information from this CDF file
     *
     */
    public synchronized Map readCDFVariablesMetaData() throws CDFException
    {
      return readCDF (true, false, false, false, true, false);
    }

    /**
     * Reads all variables' data in the CDF.
     *
     * The returned map has the following form:
     *   "Variables": {
     *      "Var_Name1": {
     *         "VarData": {
     *           ...
     *           ...
     *         }
     *      }
     *      "Var_Name2": {
     *         "VarData": {
     *           ...
     *           ...
     *         }
     *      }
     *      ...
     *   } 
     *
     * @return A Map object that contains the data from all variables
     * @exception CDFException If there was a problem retrieving the variable
     *                         information from this CDF file
     *
     */
    public synchronized Map readCDFVariablesData() throws CDFException
    {
      return readCDF (true, false, false, false, false, true);
    }

    /**
     * Gets the full CDF information.
     *
     * 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 A Map object that contains the CDF basic information, its global
     *         attributes and variables' specification, metadata and data.
     */
    public synchronized Map readCDF()
    {
      return readCDF (true, true, true, true, true, true);
    }

    /**
     * Gets the full CDF information.
     *
     * 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.
     *
     * @param encoding A true/false flag indicates whether to encode epoch
     *                 data type from metadata to date/time string.
     * @return A Map object that contains the CDF basic information, its global
     *         attributes and variables' specification, metadata and data.
     */
    public synchronized Map readCDF(boolean encoding)
    {
      return readCDF (encoding, true, true, true, true, true);
    }

    /**
     * Gets the specified information from a CDF.
     *
     * 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
     *                 data type from metadata to date/time string.
     * @param basic A true/false flag indicates whether to read the basic
     *              information about the CDF
     * @param globals A true/false flag indicates whether to read the global
     *                attributes in the CDF
     * @param varinfo A true/false flag indicates whether to read each variable's
     *                information.
     * @return A Map object that contains the CDF basic information, its global
     *         attributes and/or all variables' specification, metadata and data.
     *
     */
    public synchronized Map readCDF(boolean encoding, boolean basic,
                                    boolean globals, boolean varinfo) 
    {
      return readCDF (encoding, basic, globals, varinfo, varinfo, varinfo);
    }

    /**
     * Gets the specified information from a CDF.
     *
     * 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
     *                 data type from metadata to date/time string.
     * @param basic A true/false flag indicates whether to read the basic
     *              information about the CDF
     * @param globals A true/false flag indicates whether to read the global
     *                attributes in the CDF
     * @param varinfo A true/false flag indicates whether to read each variable's
     *                basic information.
     * @param varmeta A true/false flag indicates whether to read each variable's
     *                metadata.
     * @param vardata A true/false flag indicates whether to read each variable's
     *                data.
     * @return A Map object that contains the CDF basic information, its global
     *         attributes and all variables' metadata and data.
     *
     */
    public synchronized Map readCDF(boolean encoding, boolean basic,
                                    boolean globals, boolean varinfo,
                                    boolean varmeta, boolean vardata)
    {
       return readCDF (encoding, basic, globals, varinfo, varmeta, vardata,
                       true);
    }

    /**
     * Gets the specified information from a CDF.
     *
     * Note: Each attribute's entry, an object, can be a single data or an
     *       array of values.
     *
     * <PRE>
     * Map acdf = cdf.readCDF(true, true, true, true, true, true);
     *
     * for (Object key : acdf.keySet()) {
     *
     *   // May contain 3 key/value pairs: keys include "CDFinfo",
     *   // "GlobalAttributes" and "Variables".
     *
     *   // Get key: "Variables"'s value -- a Map
     *
     *   if (((String)key).equals("Variables")) {
     *     Map vars = (Map) acdf.get(key);
     *     if (vars == null) continue;
     *     for (Object varName : vars.keySet()) {
     *       // each key/value pair is variable name and its info
     *       System.out.println("** Variable: "+varName);
     *       Map var = (Map) vars.get(varName);
     *       // Each variable's info includes upto 3 key/value mappings:
     *       // "VarDef", "VarMetaData" and "VarData".
     *
     *       for (Object key1 : var.keySet()) {
     *         if (key1.equals("VarSpec")) {
     *           // Key: "VarSpec" has Variable specification
     *           Map specs = var.get(key1);
     *           for (Object key2 : specs.keySet()) {
     *             ....
     *             ....
     *           }
     *         } else if (key1.equals("VarMetaData")) {
     *           // Key: "VarMeataData" has variable metadata
     *           Map meta = var.get(key1);
     *           for (Object key2 : meta.keySet()) {
     *             ....
     *             ....
     *           }
     *         } else if ((key1.equals("VarData")) {
     *           // Key: "VarData" has variable data
     *           Object data = var.get(key1);
     *           ....
     *           ....
     *         } else {
     *           error....
     *         }
     *       }
     *     }
     *   } else { // other keys: "CDFinfo", "GloblaAttributes" and their values
     *     System.out.println(key + " - \n   " + acdf.get(key));
     *   }
     * }
     * </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 read the basic
     *              information about the CDF
     * @param globals A true/false flag indicates whether to read the global
     *                attributes in the CDF
     * @param varinfo A true/false flag indicates whether to read each variable's
     *                basic information.
     * @param varmeta A true/false flag indicates whether to read each variable's
     *                metadata.
     * @param vardata A true/false flag indicates whether to read each variable's
     *                data.
     * @param noentry A true/false flag indicates whether to collect attributes 
     *                that have no entries
     * @return A Map object that contains the CDF basic information, its global
     *         attributes and all variables' metadata and data.
     *
     */
    public synchronized Map readCDF(boolean encoding, boolean basic,
                                    boolean globals, boolean varinfo,
                                    boolean varmeta, boolean vardata,
                                    boolean noentry)
    {
      Map cdfTotal = new HashMap();
      try {
        if (basic) {
          // CDF basic
          Map basicMap = new HashMap();
          basicMap.put("FileName", path);
          basicMap.put("Version", getVersion());
//          basicMap.put("Majority", CDFUtils.getStringMajority((getMajority())));
          basicMap.put("Majority", getMajority());
//          basicMap.put("Format", CDFUtils.getStringFormat((getFormat())));
          basicMap.put("Format", getFormat());
//          basicMap.put("Encoding", CDFUtils.getStringEncoding((getEncoding())));
          basicMap.put("Encoding", getEncoding());
          basicMap.put("NumGlobalAttrs", getNumGattrs());
          basicMap.put("NumNumVarAttrs", getNumVattrs());
          basicMap.put("NumVars", getNumVars());
          basicMap.put("LastLeapSecond", getLeapSecondLastUpdated());

          cdfTotal.put("CDFinfo", basicMap);
        }
        if (globals) {
          // Global attributes
          Map globalAttributes = readCDFGlobalAttributes(encoding);
          if (globalAttributes.size() > 0) 
            cdfTotal.put("GlobalAttritbues", globalAttributes);
        }
        if (varinfo || varmeta || vardata) {
          // Variables
          Map variablesInfo = new HashMap();
          int i, size;
          size = (int) getNumVars();
          if (size > 0) {
            for (i = 0; i < size; ++i) {
              try {
                Variable v = (Variable) getVariable((long)i);
                String varName = v.getName();  
                Map vinfo = v.readVariable(encoding, varinfo, varmeta, vardata);
                variablesInfo.put(varName, vinfo);
              } catch (CDFException ss) {}
            }     
          }
          cdfTotal.put("Variables", variablesInfo);
        }
        if (noentry) {
          // Global and variable attributes without data
          Map noEntry = readCDFNoEntryAttributes();
          if (noEntry != null) 
            cdfTotal.put("NoEntryAttributes", noEntry);
        }
      } catch (Exception ex) { }
      return cdfTotal;
    }

    /**
     * Gets the variable attributes defined for this CDF.
     *
     * @return A vector that contains the variable attributes defined in this
     *         CDF
     */
    public synchronized Vector getVariableAttributes()
    {
      try {

	Vector va = new Vector();
	Attribute a;
	for (Enumeration e=attributes.elements(); e.hasMoreElements();) {
	  a = (Attribute)e.nextElement();
	  if (a.getScope() == VARIABLE_SCOPE)
	    va.addElement(a);
	}
	return va;
      } catch (Exception ex) {
        return new Vector();
      }

    }

    /**
     * Gets the variable attributes defined for this CDF that are not
     * associated with any variables.
     *
     * @return A vector that contains the empty variable attributes defined 
     *         in this CDF.
     */
    public synchronized Vector getOrphanAttributes()
    {
      try {
	getAttributesandVariables();
        boolean  emptyAttr = true;
        Vector   emptyAttrs = new Vector();

        if (this.getNumVars() <= 0) return emptyAttrs;
        Vector     va = this.getVariableAttributes();
        Vector     vars = this.getVariables();

        //  Examine one attribute at a time.  If an attribute does not
        //  belong to any of the variables, then it is an empty/orphan
        //  attribute.

        for (Enumeration e=va.elements(); e.hasMoreElements();) {
           Attribute a = (Attribute) e.nextElement();
           emptyAttr = true;
           for (Enumeration e1=vars.elements(); e1.hasMoreElements();) {
                Variable v = (Variable) e1.nextElement();
                try {
                     Entry entry = a.getEntry(v);
                     if (entry != null) {
                         emptyAttr = false;
                         break;       // Examine the next attribute
                     }
                } catch (CDFException ex) {
                    if (ex.getCurrentStatus() != NO_SUCH_ENTRY) {
                        System.out.println ("** Error occurred in "+
                                            "getOrphanAttributes");
                        System.out.println (ex);
                        System.exit (0);
                     }
                 }
            }
            if (emptyAttr)  emptyAttrs.addElement (a);
        }
        return emptyAttrs;
      } catch (Exception ex) {
	return new Vector();
      }
    }

	    
    ///////////////////////////////////////////////
    //                                           //
    //         Variable handling methods         //
    //                                           //
    ///////////////////////////////////////////////

    /**
     * Gets the ID of the given variable.
     *
     * @param varName the name of the variable to check <P>
     * @return -1 if the variable does not exist.  The variable id if the
     *         variable does exist.
     *
     */
    public synchronized long getVariableID(String varName)
    {

	try {
	  getAttributesandVariables();
	  long i = 0;
	  if (variables.size() == 0) return -1L;
          if (varName == null || varName.trim().length() == 0) return -1L;
	  while (!variables.elementAt((int)i).toString().trim().equals(varName.trim())) {
	    i++;
	    if (i >= (variables.size())) break;
	  }
	  if (i == variables.size())
	    return -1L;
	  else
	    return i;
	} catch (CDFException ex) {
	  return -1L;
	}
    }
	
    /**
     * Adds a variable to this CDF.  The Variable class uses this to 
     * setup the connection between the CDF object and Variable object.
     *
     * @param newVariable The variable to be added to this CDF 
     */
    protected synchronized final void addVariable(Variable newVariable) {

	Attribute curAttr;
	  // Remove any entries for the oldVariable from any variable attributes
	for (Enumeration e=attributes.elements(); e.hasMoreElements() ;) {
	    curAttr = (Attribute)e.nextElement();
	    if (curAttr.getScope() == VARIABLE_SCOPE)
		curAttr.addNullEntry();
	}
	variables.addElement(newVariable);
    }

    /**
     * Remove a variable from this CDF.  The Variable class uses this to 
     * break the connection between the CDF object and Variable object.
     *
     * @param oldVariable The variable to be removed from this CDF.
     */
    protected synchronized final void removeVariable(Variable oldVariable)
    {

	try {
	  getAttributesandVariables();
	  Attribute curAttr;
	  int idx = variables.indexOf(oldVariable);

	  // Remove any entries for the oldVariable from any variable attributes
	  for (Enumeration e=attributes.elements(); e.hasMoreElements() ;) {
	    curAttr = (Attribute)e.nextElement();
	    if (curAttr.getScope() == VARIABLE_SCOPE)
		curAttr.removeEntry(idx);
	  }
	  // Remove the oldVariable from the list.
	  variables.removeElement(oldVariable);
	} catch (CDFException ex) {}
    }

    /**
     * Gets the variable object for the given variable number. 
     *
     * @param varNum variable number from which the variable is retrieved <P>
     * @return the variable object that corresponds to the variable id <P>
     * @exception CDFException if the supplied variable number does not exist
     */
    public synchronized Variable getVariable(long varNum) throws CDFException
    {

	  getAttributesandVariables();
	  if (varNum > variables.size()) { 
	    throw new CDFException(NO_SUCH_VAR);
	  }
	  return (Variable)variables.elementAt((int)varNum);
    }

    /**
     * Gets the variable object for the given variable name. <P>
     *
     * The following example retrieves a variable called "Longitude":
     * <PRE>
     *     Variable longitude = cdf.getVariable("Longitude");
     * </PRE>
     *
     * @param varName the variable name to get <P>
     * @return the variable object that corresponds to the variable name <P>
     * @exception CDFException if the supplied variable name does not exist
     */
    public synchronized Variable getVariable(String varName) throws CDFException
    {

	  getAttributesandVariables();
	  long idx = getVariableID(varName);
	  if (idx == -1) {
	    throw new CDFException(NO_SUCH_VAR);
	  }
	  return (Variable)variables.elementAt((int)idx);
    }

    /**
     * Gets the z variables defined for this CDF. <P>
     *
     * <B>Note:</B> Since all CDFs opened or created with the CDFJava 
     * APIs are placed into zMODE 2, there are no rVarialbles.  All 
     * variables are treated as zVariables.
     *
     * @return a Vector containing all the z variables defined in this CDF
     */
    public synchronized Vector getVariables()
    {

	try {
	  getAttributesandVariables();
	  return variables;
	} catch (CDFException ex) {
	  return new Vector();
	}
    }

    /**
     * Gets the number of Z variables defined for this CDF. <P>
     *
     * @return the numer of variables
     * <B>Note:</B> Since all CDFs opened or create with the CDFJava 
     * APIs are placed into zMODE 2, there are no rVarialbles.  All 
     * variables are treated as zVariables.
     */
    public synchronized long getNumVars()
    {

	try {
	  getAttributesandVariables();
	  return (long)variables.size();
	} catch (CDFException ex) {
	  return 0L;
	}
    }

    /**
     * Retrieves a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for reading one or more variables' data in a
     * single call, instead of reading individual variable's data one
     * at a time. <P>
     *
     * @param recNum the record number to retrieve data from <P>
     * @param strVars the variable (array of variable names) to retrieve
     *                data from<P>
     *
     * @return the requested record in a Java vector that contains the
     *         variables' data. <BR>
     *         The first object in the vector corresponds to the first
     *         variable's record, the second object in the vector corresponds
     *         to the second variable's record, and so on. <P>
     *
     * @exception CDFException if there was a problem getting a record<P>
     * 
     * <B>Note:</B> A virtual variable record is returned if the
     * given record does not exist. Any error during data retrieval
     * will cause the process to stop (an exception thrown) and thus nothing
     * (a null object) will be returned.
     */
    public synchronized Vector getRecord(long recNum, String[] strVars) 
		  throws CDFException
    {
        return getRecord(recNum, strVars, null);
    }

    /**
     * Retrieves a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for reading one or more variables' data in a
     * single call, instead of reading individual variable's data one
     * at a time. <P>
     *
     * @param recNum the record number to retrieve data from <P>
     * @param strVars the variable (array of variable names) to retrieve
     *                data from<P>
     * @param status the individual status (array of statuses) for reading
     *               each variable record <p>
     *
     * @return the requested record in a Java vector that contains the
     *         variables' data. <BR>
     *         The first object in the vector corresponds to the first
     *         variable's record, the second object in the vector corresponds
     *         to the second variable's record, and so on. <P>
     *
     * @exception CDFException if there was a problem getting a record<P>
     * 
     * <B>Note:</B> A virtual variable record is returned if the                               
     * given record does not exist. Any error during data retrieval
     * will cause the process to stop (an exception thrown) and thus nothing
     * (a null object) will be returned. <P>
     * 
     * The following example reads the 2nd record from Longitude and
     * Temperature and prints their contents.
     * <PRE>
     *       String[] strVars = {"Longitude", "Temperature"};
     *       Vector record;
     *       long[] status = new long[2];
     *       record = cdf.getRecord(1L, strVars, status);
     *
     *       // Check the contents of the 'status' array - optional
     *
     *       // var: Longitude - data type: CDF_UINT2, dimensionality: 1:[3] 
     *       System.out.print ("    2nd record of Longitude -- ");
     *       for (int i=0; i &lt; 3; i++)
     *            System.out.print (((int[])record.elementAt(0))[i]+" ");
     *       System.out.println ("");
     *
     *       // var: Temperature -- data type: CDF_REAL4, dimensionality: 1:[3] 
     *       System.out.print ("    2nd record of Temperature -- ");
     *       for (int i=0; i &lt; 3; i++)
     *            System.out.print (((float[])record.elementAt(1))[i]+" ");
     *       System.out.println ("");
     * </PRE>
     */
    public synchronized Vector getRecord(long recNum, String[] strVars, 
					 long[] status) throws CDFException
    {

        if (recNum < 0 || strVars == null || strVars.length == 0)
          return null;
        int varsNum = strVars.length;
        long[] varIDs = new long[varsNum];
        for (int i = 0; i < varsNum; i++) {
          varIDs[i] = this.getVariableID(strVars[i]);
          if (varIDs[i] == -1) {
            System.err.println("Error: Variable: "+strVars[i]+
			       " not exists!!!");
            throw new CDFException(NO_SUCH_VAR);
          }
        }
        return getRecord(recNum, varIDs, status);

    }
    /**
     * Retrieves a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for reading one or more variables' data in a
     * single call, instead of reading individual variable's data one
     * at a time. <P>
     * 
     * @param recNum the record number to retrieve data from <P>
     * @param varIDs the variable IDs (array of variable IDs) to retrieve
     *               data from<P>
     *
     * @return the requested record in a Java vector that contains the
     *         variables' data. <BR>
     *         The first object in the vector corresponds to the first
     *         variable's record, the second object in the vector corresponds
     *         to the second variable's record, and so on. <P>
     *
     * @exception CDFException if there was a problem getting a record<P>
     *
     * <B>Note:</B> A virtual variable record is returned if the 
     * given record does not exist. Any error during data retrieval
     * will cause the process to stop (an exception thrown) and thus nothing 
     * (a null object) will be returned. 
     */
    public synchronized Vector getRecord(long recNum, long[] varIDs)
                  throws CDFException
    {

        return getRecord(recNum, varIDs, null);

    }

    /**
     * Retrieves a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for reading one or more variables' data in a
     * single call, instead of reading individual variable's data one
     * at a time. <P>
     *
     * @param recNum the record number to retrieve data from <P>
     * @param varIDs the variable IDs (array of variable IDs) to retrieve
     *               data from<P>
     * @param status the individual status (array of statuses) for reading
     *               each variable record <p>
     *
     * @return the requested record in a Java vector that contains the 
     *         variables' data. <BR>
     *         The first object in the vector corresponds to the first 
     *         variable's record, the second object in the vector corresponds 
     *         to the second variable's record, and so on. <P>
     *
     * @exception CDFException if there was a problem getting a record<P>
     *
     * <B>Note:</B> A virtual variable record is returned if the 
     * given record does not exist. Any error during data retrieval
     * will cause the process to stop (an exception thrown) and thus nothing 
     * (a null object) will be returned. <P>
     * 
     * The following example reads the 2nd record from Longitude (varIds[0])
     * and Temperature (varIDs[1]) and prints their contents.
     * <PRE>
     *       long[] varIDs = {2, 10};    // Obtained from Variable.getID()
     *       Vector record;
     *       long[] status = new long[2];
     *       record = cdf.getRecord(1L, varIDs, status);
     *
     *       // Check the contents of the 'status' array - optional
     *
     *       // var: Longitude - data type: CDF_UINT2, dimensionality: 1:[3]
     *       System.out.print ("    2nd record of Longitude -- ");
     *       for (int i=0; i &lt; 3; i++)
     *            System.out.print (((int[])record.elementAt(0))[i]+" ");
     *       System.out.println ("");
     *
     *       // var: Temperature - data type: CDF_REAL4, dimensionality: 1:[3]
     *       System.out.print ("    2nd record of Temperature -- ");
     *       for (int i=0; i &lt; 3; i++)
     *            System.out.print (((float[])record.elementAt(1))[i]+" ");
     *       System.out.println ("");
     * </PRE>
     */
    public synchronized Vector getRecord(long recNum, long[] varIDs, 
					 long[] status) throws CDFException
    {

        if (recNum < 0 || varIDs == null || varIDs.length == 0)
          return null;
        int varsNum = varIDs.length;
        Vector myData = new Vector();
        Variable var;
        for (int i = 0; i < varsNum; i++) {
          try {
            var = this.getVariable(varIDs[i]);
          } catch (CDFException e) {
            System.err.println("Error: Variable: "+varIDs[i]+
			       " not exists!!!");
            throw new CDFException(NO_SUCH_VAR);
          }
          myData.add(var.getRecord(recNum));
          if (status != null) status[i] = this.getStatus();
        }
        return myData;

    }

    /**
     * Writes a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for writing one or more variables' data in a
     * single call, instead of writing individual variable's data one
     * at a time. <P>
     *
     * @param recNum the record number to write data to <P>
     * @param strVars the variable (array of variable names) to write
     *                data to<P>
     * @param myData  a Java vector that contains the variables' data. <BR>
     *                The first object in the vector corresponds to the
     *                first variable's record, the second object in the
     *                vector corresponds to the second variable's record,
     *                and so on. <P>
     *
     * @exception CDFException if there was a problem writing the record for
     *                         any of the variables<P>
     * <B>Note:</B> Any error during the data writing will cause the process
     * to stop (an exception thrown) and thus the operation will not be 
     * completed. Nothing will be done if the element counts of parameters 
     * don't match. 
     */
    public synchronized void putRecord(long recNum, String[] strVars, 
				       Vector myData) throws CDFException
    {

        this.putRecord(recNum, strVars, myData, null);

    }

    /**
     * Writes a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for writing one or more variables' data in a
     * single call, instead of writing individual variable's data one
     * at a time. <P>
     *
     * @param recNum the record number to write data to <P>
     * @param strVars the variable (array of variable names) to write
     *                data to<P>
     * @param myData  a Java vector that contains the variables' data. <BR>
     *                The first object in the vector corresponds to the
     *                first variable's record, the second object in the
     *                vector corresponds to the second variable's record,
     *                and so on. <P>
     * @param status the individual status (array of statuses) for writing
     *               each variable record <p>
     *
     * @exception CDFException if there was a problem writing the record for
     *                         any of the variables <P>
     * <B>Note:</B> Any error during the data writing will cause the process
     * to stop (an exception thrown) and thus the operation will not be 
     * completed. Nothing will be done if the element counts of parameters 
     * don't match. <P> 
     * 
     * The following example writes the contents of a record (which consists
     * of two CDF variables - Longitude and Temperature) to record number 2. 
     * <PRE>
     *    String[] strVars = {"Longitude",     // variable names in CDF
     *                        "Temperature"};
     *
     *   // Longitude -- data type: CDF_UINT2 dimensionality: 1:[3] 
     *   int[] longitude_data = {333, 444, 555};
     *
     *   // Temperature -- data type: CDF_FLOAT dimensionality: 0:[] 
     *   Float temperature_data = Float.valueOf((float)999.99);
     *
     *   Vector record = new Vector();
     *   record.add(longitude_data);
     *   record.add(temperature_data);
     *
     *   cdf.putRecord(1L, strVars, record);  // Write a record to record #2
     * </PRE>
     */
    public synchronized void putRecord(long recNum, String[] strVars, 
				       Vector myData, long[] status) 
		throws CDFException
    {

        if (recNum < 0 || strVars == null || strVars.length == 0 ||
            myData == null || myData.isEmpty()) return;
        int varsNum = strVars.length;
        long[] varIDs = new long[varsNum];
        for (int i = 0; i < varsNum; i++) {
          varIDs[i] = this.getVariableID(strVars[i]);
          if (varIDs[i] == -1) {
            System.err.println("Error: Variable: "+strVars[i]+
			       " not exists!!!");
            throw new CDFException(NO_SUCH_VAR);
          }
        }
        this.putRecord(recNum, varIDs, myData, status);
    }

    /**
     * Writes a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for writing one or more variables' data in a
     * single call, instead of writing individual variable's data one
     * at a time. <P>
     *
     * @param recNum the record number to write data to <P>
     * @param varIDs the variable IDs (array of variable IDs) to write
     *               data to<P>
     * @param myData  a Java vector that contains the variables' data. <BR>
     *                The first object in the vector corresponds to the
     *                first variable's record, the second object in the 
     *                vector corresponds to the second variable's record, 
     *                and so on. <P>
     *
     * @exception CDFException if there was a problem writing the record for
     *                         any of the variables <P>
     * <B>Note:</B> Any error during the data writing will cause the process
     * to stop (an exception thrown) and thus the operation will not be
     * completed. Nothing will be done if the element counts of parameters 
     * don't match. 
     */
    public synchronized void putRecord(long recNum, long[] varIDs, 
				       Vector myData) throws CDFException
    {

        this.putRecord(recNum, varIDs, myData, null);

    }

    /**
     * Writes a logical record that consists of single variable record(s)
     * from an arbitrary number of CDF variables.  This is a
     * convenient method for writing one or more variables' data in a
     * single call, instead of writing individual variable's data one
     * at a time. <P>
     *
     * @param recNum the record number to write data to <P>
     * @param varIDs the variable IDs (array of variable IDs) to write
     *               data to<P>
     * @param myData  a Java vector that contains the variables' data. <BR>
     *                The first object in the vector corresponds to the
     *                first variable's record, the second object in the
     *                vector corresponds to the second variable's record,
     *                and so on. <P>
     * @param status the individual status (array of statuses) for writing
     *               each variable record <p>
     *
     * @exception CDFException if there was a problem writing the record for
     *                         any of the variables <P>
     * <B>Note:</B> Any error during the data writing will cause the process
     * to stop (an exception thrown) and thus the operation will not be
     * completed. Nothing will be done if the element counts of parameters
     * don't match. <P>
     *
     * The following example writes the contents of a record (which consists
     * of two CDF variables - Longitude and Temperature) by using variable IDs
     * (instead of variable names) to record number 2.
     * <PRE>
     *   long[] varIDs = {3, 9};   // Can be obtained from variable.getID()
     *
     *   // Longitude -- data type: CDF_UINT2 dimensionality: 1:[3]
     *   int[] longitude_data = {333, 444, 555};
     *
     *   // Temperature -- data type: CDF_FLOAT dimensionality: 0:[]
     *   Float temperature_data = Float.valueOf((float)999.99);
     *
     *   Vector record = new Vector();
     *   record.add(longitude_data);
     *   record.add(temperature_data);
     *
     *   cdf.putRecord(1L, varIDs, record);  // Write a record to record #2
     * </PRE>
     */
    public synchronized void putRecord(long recNum, long[] varIDs, 
				       Vector myData, long[] status)
                throws CDFException
    {
        if (recNum < 0 || varIDs == null || varIDs.length == 0 ||
            myData == null || myData.isEmpty()) return;
        if (varIDs.length != myData.size()) {
          System.err.println("Error: the variables' count: "+varIDs.length+
                             " does not match the record objects' count: "+
                             myData.size());
          return;
        }
        if (status != null && status.length < varIDs.length) {
          System.err.println("Error: the variables' count: "+varIDs.length+
                             " does not match the status' count: "+
                             status.length);
          return;
        }
        int varsNum = varIDs.length;
        Variable var;
        for (int i = 0; i < varsNum; i++) {
          try {
            var = this.getVariable(varIDs[i]);
          } catch (CDFException e) {
            System.err.println("Error: Variable: "+varIDs[i]+
			       " not exists!!!");
            throw new CDFException(NO_SUCH_VAR);
          }
          var.putRecord(recNum, myData.elementAt(i));
	  if (status != null) status[i] = this.getStatus();
        }
    }

    /**
     * Specifies the checksum option applied to the CDF.
     *
     * @param checksum the checksum option to be used for this CDF. Currently,
     *                 other than NO_CHECKSUM option, only MD5_CHECKSUM (using 
     *                 MD5 checksum algorithm) is supported. 
     * @exception CDFException if there was a problem with the passed option,
     *                         setting the checksum or other vital infomation 
     *                         from this CDF file.
     */
    public synchronized void setChecksum(long checksum) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item1 = new Vector();
	Vector item2 = new Vector();
	
	if (checksum != NO_CHECKSUM && checksum != MD5_CHECKSUM) 
	  throw new CDFException(BAD_CHECKSUM);;

	this.checksumX = checksum;

        cmds.addElement(Long.valueOf(SELECT_));
          cmds.addElement(Long.valueOf(CDF_));
	    item1.addElement("id");
	    item1.addElement("J");
	  cmds.addElement(item1);

        cmds.addElement(Long.valueOf(PUT_));
          cmds.addElement(Long.valueOf(CDF_CHECKSUM_));
            item2.addElement("checksumX");
            item2.addElement("J");
          cmds.addElement(item2);
        
        cmds.addElement(Long.valueOf(NULL_));
       	id = getID(); 
        executeCommand((CDFObject)this, cmds);
        this.checksum = checksum;

    }

    /** 
     * Gets the checksum method, if any, applied to the CDF. 
     *                       
     * @return the checksum method used for this CDF. Currently,
     *         it returns NONE_CHECKSUM (0) if no checksum is used;
     *                    MD5_CHECKSUM (1) if MD5 method is used;
     */ 
    public synchronized long getChecksum() {
	return this.checksum;
        
    }

    /**
     * Set the leap second last updated for this CDF.  Normally, a new CDF
     * is created, this field is set automatically. Only to call this method
     * if the CDF is based on an existing one.
     *  
     * @param lastUpdated The last date that the leap second was updated. It is
     *                    in YYYYMMDD form.
     * @exception CDFException If a problem occurred in setting the 
     *            desired field.
     */
    public synchronized void setLeapSecondLastUpdated(long lastUpdated) throws CDFException
    {
        Vector cmds = new Vector();
        Vector item0 = new Vector();
        Vector itemA = new Vector();

        this.lastUpdatedX = lastUpdated;
        cmds.addElement(Long.valueOf(SELECT_));
           cmds.addElement(Long.valueOf(CDF_));
              itemA.addElement("id");
              itemA.addElement("J");
           cmds.addElement(itemA);

        cmds.addElement(Long.valueOf(PUT_));
           cmds.addElement(Long.valueOf(CDF_LEAPSECONDLASTUPDATED_));
              item0.addElement("lastUpdatedX");
              item0.addElement("J");
           cmds.addElement(item0);
        cmds.addElement(Long.valueOf(NULL_));

        id = getID();
//      select();
        executeCommand((CDFObject)this, cmds);
        this.lastUpdated = lastUpdated;

    }

    /** 
     * Gets the date that the CDF has the last leap second updated.
     *                       
     * @return the date in YYYYMMDD that the last leap second was updated
     *         when the CDF is based (relavant to TT2000 variables).
     */ 
    public synchronized long getLeapSecondLastUpdated() {
	return this.leapSecondLastUpdated;
        
    }

    /**
     * Verifies the data integrity of the CDF file from its checksum.
     *
     * @return The status of data integrity check through its checksum.
     *         it should return CDF_OK if the integrity check is fine. Or, it may
     *         return a value of CHECKSUM_ERROR indicating the data integrity was
     *         compromised. Or, it may return other CDF error if it has problem 
     *         reading the CDF data filed(s). No need to use this method as when
     *         the file is open, its data integrity is automatically checked with
     *         the used checksum method.
     * @exception CDFException if there was a problem getting the
     *                         checksum or other vital infomation from this CDF file
     */
    public synchronized long verifyChecksum() throws CDFException
    {
        Vector cmds = new Vector();
        Vector itemA  = new Vector();

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

        cmds.addElement(Long.valueOf(CONFIRM_));
           cmds.addElement(Long.valueOf(CDF_CHECKSUM_));
        cmds.addElement(Long.valueOf(NULL_));
	id = getID();
        executeCommand((CDFObject)this, cmds);

        return this.getStatus();
    }

    private String FindCDFName (String path) {
	String pathT;

	if (new File(path).isFile()) return path;

	pathT = new StringBuffer().append(path).append(".cdf").toString();
	if (new File(pathT).isFile()) return pathT;

        pathT = new StringBuffer().append(path).append(".CDF").toString();
        if (new File(pathT).isFile()) return pathT;

        pathT = new StringBuffer().append(path).append(".cdf;1").toString();
        if (new File(pathT).isFile()) return pathT;
  
        pathT = new StringBuffer().append(path).append(".CDF;1").toString();
        if (new File(pathT).isFile()) return pathT;
	
	return null;

    }

}
