/******************************************************************************
* Copyright 1996-2013 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
******************************************************************************/

import java.io.*;
import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import gsfc.nssdc.cdf.*;
import gsfc.nssdc.cdf.util.*;

public class GetMyCDFData implements CDFConstants {

    /**
     * The Variable to which the data belongs.
     */
    private Variable _myVar;

    /**
     * The data returned from the CDFlib call.  This will always be 
     * a 1D array of the correct primitive or String data
     */
    private Object _data;

    /**
     * The data after _dataArray has been unwrapped to the proper
     * array dimensions.
     */
    private Object _dataArray;


    /**
     * Variable id. 
     */
    private long id;

    /**
     * How many data values a data get/put action involves.  Note that for
     * CDF_CHAR and CDF_UCHAR, this is the total number of characters.
     */
    private long numValues;

    /**
     * Mirror _myVar.getNumElements(). numElements = 1 or the string length
     * for CDF_CHAR and CDF_UCHAR data.  
     */
    private long numElements;

     /**
     * Used in the JNI. This is the "real" signature of _data.
     */
    private String dataSignature;

    private long dataType;

    /**
     * The dimensionality of the actual passed data or retrieved data.
     */
    private int nDims = 0;

    /**
     * The dimension sizes of this variable. 
     */
    private int [] dimSizes;


    /**
     * At which record does this hyper get/put function starts.
     */
    private long recStart;
    
    
    /**
     * The number of records a hyper get/put function involves.
     */
    private long recCount;
    
    
    /**
     * What is the spacing between records for a hyper get/put function.
     */
    private long recInterval;
    
    
    /**
     * What are the starting dimension indices within a record for a 
     * hyper get/put function.
     */
    private long [] dimIndices;
    
    /**
     * Gets the starting dimension index within a record for a hyper 
     * get/put function.  Dimension index indicates where the data search 
     * started from within a record.  
     * Let's say a record is comprised of a 2x5 two-dimensional array 
     * (2 rows and 5 columns).  If the index returned from this method has  
     * a value of {1,0}, then the data search was performed starting at the 
     * first element of the second row.  Similarly, the value of {0,0} 
     * represents that the data search search was performed starting at the
     * first element of the first record. 
     *
     * @return the dimension index for this variable 
     */
    public long [] getDimIndices() {
         return dimIndices;
    }
    
    /**
     * How many values in each dimension within a record for a 
     * hyper get/put function.
     */
    private long [] dimCounts;
    
    /**
     * The dimension intervals. 
     */
    private long [] dimIntervals;
    
    private static final String CDATA_BEGIN = "<![CDATA[";
    private static final String CDATA_END   = "]]>";
    private static final String[] special1 = {"<"};
    private static final String[] special2 = {"&lt;"};
    private static final String[] special3 = {"&", "<", ">", "\"", "'"};
    private static final String[] special4 = {"&amp;", "&lt;", "&gt;",
                                              "&quot;", "&apos;"};

    public static boolean checkStringData (Object data) {

        int  i, arrayLength;
        boolean found = false;
        String signature = CDFUtils.getSignature(data);
        if (signature.charAt(0) == '[') {
            arrayLength = Array.getLength(data);
            for (i=0; i < arrayLength; i++) {
              Object one = Array.get(data, i);
              if (CDFUtils.getSignature(one).charAt(0) == '[') {
                 found = checkStringData (one);
                 if (found) return true;
              } else {
                found = (((String)one).indexOf("<") > -1);
                if (found) return found;
              }
            }
            return found;
        } else
          found = (((String)data).indexOf("<") > -1);
        return found;
    }

    public static Object replaceStringDataToXML (Object data) {

        int  i, arrayLength, j;
        boolean found = false;
        String signature = CDFUtils.getSignature(data);
        if (signature.charAt(0) == '[') {
            arrayLength = Array.getLength(data);
            String[] newData = new String[arrayLength];
            for (i=0; i < arrayLength; i++) {
              newData[i] = ((String[])data)[i];
//            for (j=0; j < Array.getLength(special1); j++)
//              newData[i] = newData[i].replaceAll(special1[j], special2[j]);
              for (j=0; j < Array.getLength(special3); j++) {
                if (newData[i].indexOf(special4[i]) != -1) continue;
                newData[i] = newData[i].replaceAll(special3[j], special4[j]);
              }
            }
            return newData;
        } else {
          String newData;
          newData = (String) data;
//        for (j=0; j < Array.getLength(special1); j++) 
//              newData = newData.replaceAll(special1[j], special2[j]);
          for (j=0; j < Array.getLength(special3); j++) {
            if (newData.indexOf(special4[j]) != -1) continue;
            newData = newData.replaceAll(special3[j], special4[j]);
          }
          return newData;
        }
    }

    public static Object replaceStringNameToXML (Object data) {

        int  i, arrayLength, j;
        boolean found = false;
        String signature = CDFUtils.getSignature(data);
        if (signature.charAt(0) == '[') {
            arrayLength = Array.getLength(data);
            String[] newData = new String[arrayLength];
            for (i=0; i < arrayLength; i++) {
              newData[i] = ((String[])data)[i];
              for (j=0; j < Array.getLength(special3); j++) {
                if (newData[i].indexOf(special4[i]) != -1) continue;
                newData[i] = newData[i].replaceAll(special3[j], special4[j]);
              }
            }
            return newData;
        } else {
          String newData;
          newData = (String) data;
          for (j=0; j < Array.getLength(special3); j++) {
            if (newData.indexOf(special4[j]) != -1) continue;
            newData = newData.replaceAll(special3[j], special4[j]);
          }
          return newData;
        }
    }

    public static Object replaceFromXMLStringData (Object data) {

        int  i, arrayLength, j;
        boolean found = false;
        String signature = CDFUtils.getSignature(data);
        if (signature.charAt(0) == '[') {
            arrayLength = Array.getLength(data);
            String[] newData = new String[arrayLength];
            for (i=0; i < arrayLength; i++) {
              newData[i] = ((String[])data)[i];
//            for (j=0; j < Array.getLength(special1); j++)
//              newData[i] = newData[i].replaceAll(special2[j], special1[j]);
              for (j=0; j < Array.getLength(special3); j++)
                newData[i] = newData[i].replaceAll(special4[j], special3[j]);
            }
            return newData;
        } else {
          String newData = (String) data;
//        for (j=0; j < Array.getLength(special1); j++) 
//              newData = newData.replaceAll(special2[j], special1[j]);
          for (j=0; j < Array.getLength(special3); j++) 
                newData = newData.replaceAll(special4[j], special3[j]);
          return newData;
        }
    }

    public static Object replaceFromXMLStringName (Object data) {

        int  i, arrayLength, j;
        boolean found = false;
        String signature = CDFUtils.getSignature(data);
        if (signature.charAt(0) == '[') {
            arrayLength = Array.getLength(data);
            String[] newData = new String[arrayLength];
            for (i=0; i < arrayLength; i++) {
              newData[i] = ((String[])data)[i];
              for (j=0; j < Array.getLength(special3); j++)
                newData[i] = newData[i].replaceAll(special4[j], special3[j]);
            }
            return newData;
        } else {
          String newData = (String) data;
          for (j=0; j < Array.getLength(special3); j++) 
                newData = newData.replaceAll(special4[j], special3[j]);
          return newData;
        }
    }

   /**
    * This method returns the variable's dataType in string that is used in
    * the XLM element.
    */
    public static String getDataTypeElement (long dataType) {
	if (dataType == CDF_EPOCH || dataType == CDF_EPOCH16 || 
            dataType == CDF_TIME_TT2000) return "dateTime";
        else if (dataType == CDF_CHAR || dataType == CDF_UCHAR)
            return "string";
        else if (dataType == CDF_REAL4 || dataType == CDF_FLOAT)
            return "float";
        else if (dataType == CDF_REAL8 || dataType == CDF_DOUBLE)
            return "double";
        else if (dataType == CDF_INT1) return "byte";
        else if (dataType == CDF_UINT1) return "unsignedByte";
        else if (dataType == CDF_INT2) return "short";
        else if (dataType == CDF_UINT2) return "unsignedShort";
        else if (dataType == CDF_INT4) return "int";
        else if (dataType == CDF_UINT4) return "unsignedInt";
        else if (dataType == CDF_INT8) return "long";
        else return "unknown";

    }
 
   /**
    * This method returns the corresponding data type from a string value in
    * the XLM element. As "datetime" can be one of CDF_EPOCH, CDF_EPOCH16
    * or CDF_TIME_TT2000, it returns a dummy value of 100. Its real type
    * will be determined later when the entry value is read.
    */
    public static long xsdTypeToCDFType(String dataType) {
        if (dataType == null) return -1;
        String lDataType = dataType.toLowerCase();
	if (lDataType.equals("datetime")) return 100;
        else if (lDataType.equals("string")) return CDF_CHAR;
        else if (lDataType.equals("float")) return CDF_FLOAT;
        else if (lDataType.equals("double")) return CDF_DOUBLE;
        else if (lDataType.equals("byte")) return CDF_INT1;
        else if (lDataType.equals("unsignedbyte")) return CDF_UINT1;
        else if (lDataType.equals("short")) return CDF_INT2;
        else if (lDataType.equals("unsignedshort")) return CDF_UINT2;
        else if (lDataType.equals("int")) return CDF_INT4;
        else if (lDataType.equals("unsignedint")) return CDF_UINT4;
        else if (lDataType.equals("long")) return CDF_INT8;
        else return -1;

    }
 
   /**
    * Constructor for GetMyCDFData.
    *
    * @param v the variable from which this GetMyCDFData object is created <P>
    */
    private GetMyCDFData (Object dataArray, 
                          long   datatype, 
                          long   numDims, 
                          long[] dimensionSizes,
                          long   nElements) {
	_dataArray = dataArray;
	dataType   = datatype; 
	// nDims   = (int) numDims;
        numElements = nElements; 
        dimSizes = new int[(int) numDims];

        nDims = 0;
        for (int i=0; i < numDims; i++)
             if (dimensionSizes[i] > 1) 
                 dimSizes[nDims++] = (int) dimensionSizes[i];
    }


    public int getDims () { return nDims; }


    public static GetMyCDFData create(Object dataArray,
                                      long   datatype,
                                      long   numDims,
                                      long[] dimensionSizes,
                                      long   nElements) 
    {
        GetMyCDFData theData = new GetMyCDFData (dataArray, datatype, numDims,
                                                 dimensionSizes, nElements);
        return theData;
    }
    

    // used to determine the boundaries
    private long product(int [] array, int start, int stop) {
	long product = 1;
	for (int i=start; i<stop; i++)
	    if (array[i] > 1) product *= array[i];

	// return product*numElements;
	return product;
    }


    public static void outputIndentation(PrintWriter outWriter,
                                         int indent,
                                         String indentation) {
        for (int i = 0; i < indent; i++) {
             outWriter.print(indentation);
        }
    }


    /**
     * Dumps variable data, one row at a time per record.  This is a generic
     * utility for dumping data to a screen.  Data can be scalar or 
     * 1-dimensional or multi-dimensional array of any data type.<P>
     *
     * The following example retrieves the first record, comprised of
     * 3x5 (3 rows and 5 columns) array, into a generic object and dumps 
     * its contents to screen one row at a time.  In this case three rows
     *  will be displayed on a screen, each row containing 5 elements. 
     * <PRE>
     *     GetMyCDFData data;
     *     CDFData datax;
     *     long[] dimIndices   = {0,0};
     *     long[] dimIntervals = {3,5};
     *     long[] dimSizes     = {1,1}; <P>
     *     datax = var.getHyperDataObject(0L,         // record start
     *                                    1,          // record counts 
     *                                    1,          // record interval
     *                                    dimIndices,
     *                                    dimSizes,
     *                                    dimIntervals);
     *     data = GetMyCDFData.create(datax, var.getDataType(),
     *                                var.getNumDims(),var.getDimSizes(),
     *                                var.getNumElements());
     *     data.dumpData(....);
     * </PRE>
     *
     */
    public void dumpData(PrintWriter outWriter, 
                         String   recStartIndicator,
                         String   recEndIndicator,
                         String   elementDelimiter,
                         boolean  elementFlag,
                         int      indent,
                         String   indentation,
                         boolean  iso8601,
                         boolean  withz) {
       dumpData(outWriter, recStartIndicator, recEndIndicator,
                elementDelimiter, elementFlag, indent, indentation, iso8601,
                withz, true);
    }

    /**
     * Dumps variable data, one row at a time per record.  This is a generic
     * utility for dumping data to a screen.  Data can be scalar or 
     * 1-dimensional or multi-dimensional array of any data type.<P>
     *
     * The following example retrieves the first record, comprised of
     * 3x5 (3 rows and 5 columns) array, into a generic object and dumps 
     * its contents to screen one row at a time.  In this case three rows
     *  will be displayed on a screen, each row containing 5 elements. 
     * <PRE>
     *     GetMyCDFData data;
     *     CDFData datax;
     *     long[] dimIndices   = {0,0};
     *     long[] dimIntervals = {3,5};
     *     long[] dimSizes     = {1,1}; <P>
     *     datax = var.getHyperDataObject(0L,         // record start
     *                                    1,          // record counts 
     *                                    1,          // record interval
     *                                    dimIndices,
     *                                    dimSizes,
     *                                    dimIntervals);
     *     data = GetMyCDFData.create(datax, var.getDataType(),
     *                                var.getNumDims(),var.getDimSizes(),
     *                                var.getNumElements());
     *     data.dumpData(....);
     * </PRE>
     *
     */
    public void dumpData(PrintWriter outWriter, 
                         String   recStartIndicator,
                         String   recEndIndicator,
                         String   elementDelimiter,
                         boolean  elementFlag,
                         int      indent,
                         String   indentation,
                         boolean  iso8601,
                         boolean  withz,
                         boolean  useCDATA) {

        /////////////////////////////////////////////////////////////
        //                                                         //
        //                    Dump 1D Arrays                       //
        //                                                         //
        /////////////////////////////////////////////////////////////

        indent++;
        boolean useCDATA2;
        useCDATA2 = false;
        if ((dataType == CDF_CHAR || dataType == CDF_UCHAR) && useCDATA)
            useCDATA2 = checkStringData(_dataArray);
        outputIndentation (outWriter, indent, indentation);
        if (nDims <= 1) {
            outWriter.print (recStartIndicator);
            if (nDims == 0) {
                if (dataType == CDF_EPOCH) {
                    if (!_dataArray.getClass().isArray()) {
                      Double lEpoch = (Double) _dataArray;
                      outWriter.print ((!iso8601)?
                                        Epoch.encode(lEpoch.doubleValue()):
                                        (Epoch.encode4(lEpoch.doubleValue())+
                                         (withz?"Z":"")));
                    } else {
                      double lEpoch = ((double[]) _dataArray)[0];
                      outWriter.print ((!iso8601)?
                                        Epoch.encode(lEpoch):
                                        (Epoch.encode4(lEpoch)+(withz?"Z":"")));
                    }
                } else if (dataType == CDF_EPOCH16) {
                    double[] lEpoch = (double[]) _dataArray;
                    outWriter.print ((!iso8601)?
                                      Epoch16.encode(lEpoch):
                                      (Epoch16.encode4(lEpoch)+(withz?"Z":"")));
                } else if (dataType == CDF_TIME_TT2000) {
                    if (!_dataArray.getClass().isArray()) {
                      Long lEpoch = (Long) _dataArray;
                      outWriter.print (CDFTT2000.encode(lEpoch.longValue())+
                                       (withz?"Z":""));
                    } else {
                      long lEpoch = ((long[]) _dataArray)[0];
                      outWriter.print (CDFTT2000.encode(lEpoch)+(withz?"Z":""));
                    }
                } 
                else { 
                    if (useCDATA2) {
                       outWriter.print (CDATA_BEGIN);
                       if (!_dataArray.getClass().isArray())
                         outWriter.print(_dataArray.toString());
                       else {
                         Object ttt = Array.get(_dataArray,0);
                         outWriter.print(ttt.toString());
                       }
                       outWriter.print (CDATA_END);
                    } else {
                       if (!_dataArray.getClass().isArray()) {
                         if (dataType != CDF_CHAR && dataType != CDF_UCHAR)
                           outWriter.print(_dataArray);
                         else
                           outWriter.print(GetMyCDFData.replaceStringDataToXML(
                                                             _dataArray));
                       } else {
                         Object ttt = Array.get(_dataArray,0);
                         if (dataType != CDF_CHAR && dataType != CDF_UCHAR)
                           outWriter.println(ttt);
                         else
                           outWriter.println(GetMyCDFData.replaceStringDataToXML(ttt));
                       }
                    }
                }
            }
            else {
                if (dataType == CDF_CHAR || dataType == CDF_UCHAR) {
                    outWriter.println ("");
                }
                switch ((int) dataType) {
                case (int)CDF_CHAR:
                case (int)CDF_UCHAR:
                    indent++;
                    int lastElement = dimSizes[nDims-1];

                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (indent != -99)
                            outputIndentation (outWriter, indent, indentation);

                        // If a string delimiter is not defined from the 
                        // command line (through the -strDelimiter: option), 
                        // recStartIndicator is set to "<record>".  Otherwise,
                        // recStartIndicator is set to 
                        // <record elementDelimiter="@~">

                        if (elementFlag) {
                            outWriter.print("<element index=\""+j+"\">");
                        }
                        else
                            outWriter.print(elementDelimiter);
                        if (useCDATA2) {
                           outWriter.print(CDATA_BEGIN); 
                           outWriter.print(((String [])_dataArray)[j]);
                           outWriter.print(CDATA_END);
                        } else {
                           outWriter.print(GetMyCDFData.replaceStringDataToXML(
                                                     ((String [])_dataArray)[j]));
                        }
                        if (elementFlag) {
                            outWriter.print("</element>");
                        }
                        else
                            outWriter.print(elementDelimiter);
                        
                        if (j != lastElement) outWriter.println("");
                    }
                    indent--;
                    if (indent != -99)
                        outputIndentation (outWriter, indent, indentation);
                    break;
                case (int)CDF_BYTE:
                case (int)CDF_INT1:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        outWriter.print(((byte [])_dataArray)[j]);
                    }
                    break;
                case (int)CDF_INT2:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        outWriter.print(((short [])_dataArray)[j]);
                    }
                    break;
                case (int)CDF_UINT1:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        if (((short [])_dataArray)[j] >=0) 
			  outWriter.print(((short [])_dataArray)[j]);
			else {
			  short tmp = (short)(((short [])_dataArray)[j]+256); 
			  outWriter.print(tmp);
			}
                    }
                    break;
                case (int)CDF_INT4:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        outWriter.print(((int [])_dataArray)[j]);
                    }
                    break;
                case (int)CDF_UINT2:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        if (((int [])_dataArray)[j] >=0)
                          outWriter.print(((int [])_dataArray)[j]);
                        else {
			  int tmp = (int)(((int [])_dataArray)[j]+65536);
                          outWriter.print(tmp);
			}
                    }
                    break;

                case (int)CDF_UINT4:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        if (((long [])_dataArray)[j] >=0)
                          outWriter.print(((long [])_dataArray)[j]);
                        else {
			  long tmp = (long)(((long [])_dataArray)[j]+
					    4294967296L);
                          outWriter.print(tmp);
			}
                    }
                    break;
                case (int)CDF_INT8:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        outWriter.print(((long [])_dataArray)[j]);
                    }
                    break;
                case (int)CDF_REAL4:
                case (int)CDF_FLOAT:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        outWriter.print(((float [])_dataArray)[j]);
                    }
                    break;
                case (int)CDF_REAL8:
                case (int)CDF_DOUBLE:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        outWriter.print(((double [])_dataArray)[j]);
                    }
                    break;
                case (int)CDF_EPOCH:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
			outWriter.print((!iso8601)?
                                        Epoch.encode(((double [])_dataArray)[j]):
                                        (Epoch.encode4(((double [])_dataArray)[j])+
                                         (withz?"Z":"")));
                    }
                    break;
                case (int)CDF_EPOCH16:
		    double[] twoDouble = new double[2];
                    for (int j=0, k=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
			twoDouble[0] = ((double [])_dataArray)[k++];
			twoDouble[1] = ((double [])_dataArray)[k++];
                        outWriter.print((!iso8601)?
                                        Epoch16.encode(twoDouble):
                                        (Epoch16.encode4(twoDouble)+
                                         (withz?"Z":"")));
                    }
                    break;
                case (int)CDF_TIME_TT2000:
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (j>0) outWriter.print(elementDelimiter);
                        outWriter.print(
                              CDFTT2000.encode(((long [])_dataArray)[j])+
                              (withz?"Z":""));
                    }
                    break;
                default:
                    break;
                } /* switch (dataType) */

               if (dataType == CDF_CHAR || dataType == CDF_UCHAR) {
               }
            }
            outWriter.println (recEndIndicator);

        /////////////////////////////////////////////////////////////
        //                                                         //
        //              Dump Multidimensional Arrays               //
        //                                                         //
        /////////////////////////////////////////////////////////////

        } else {
            /*
             * Setup the subArrays array
             * cIndex is the holds the index for the current subarray
             * boundary is the # of values in the subarray
             */
            Object aRow = null;
            Object [] subArrays = new Object[(int)nDims-1];
            int [] cIndex   = new int[(int)nDims-1];
            long [] boundary = new long[(int)nDims-1];

            int jj=0;

            subArrays[0] = _dataArray;
            cIndex[0] = 0;
	    boundary[0] = product(dimSizes,0,(int)nDims);

            for (int i=1; i<(int)nDims-1;i++) {
                subArrays[i] = Array.get(subArrays[i-1], 0);
                boundary[i] = product(dimSizes,i,(int)nDims);
                cIndex[i] = 0;
            }

            int n = 0; // The current element in the _data
            Object cObject = _dataArray;  // A temp object to hold a subarray
            boolean boundaryCrossed;

            outWriter.print (recStartIndicator);
            if (dataType == CDF_CHAR || dataType == CDF_UCHAR) {
                if (elementFlag)   
                    outWriter.println ("");
                else
                    if (useCDATA2) outWriter.println (CDATA_BEGIN);
            }

            while (n < boundary[0]) {
                // Get the correct 2D subarray to print
                if (n!=0) {
                    jj++;      // Increment the counter for 3-D
                    if (dataType != CDF_CHAR && dataType != CDF_UCHAR) 
                        outWriter.print (elementDelimiter);

                    for (int i = 0; i < (int)nDims-1; i++) {
                        boundaryCrossed = ((n % boundary[i]) == 0);
                        if (boundaryCrossed) {
                            // Get the next sub array
                            cIndex[i]+=1;
                            cObject = Array.get(cObject, cIndex[i]);
                            subArrays[i] = cObject;

                            // Get the first element of each
                            // subsequent subarray
                            for (int j=i+1;j<(int)nDims-1;j++) {
                                cIndex[j] = 0;
                                subArrays[j] =
                                    Array.get(subArrays[j-1],cIndex[j]);
                            }
                            break;

                        } else {
                            cObject = subArrays[i];
                        }
                    }
                }

                // Fill the correct elements of _data

                for (int i=0;i<dimSizes[(int)nDims-2];i++) {
            
                    // if (i > 0) outWriter.print (" ");
                    if (i > 0) { 
                        if (dataType == CDF_CHAR || dataType == CDF_UCHAR) 
                           indent--;
                        else 
                           outWriter.print (elementDelimiter);
                    }

                    switch ((int) dataType) {
                    case (int)CDF_CHAR:
                    case (int)CDF_UCHAR:
                        aRow =
                            (String [])Array.get(subArrays[(int)nDims - 2], i);
                        indent++;
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (indent != -99)
                                outputIndentation (outWriter, indent, 
                                                   indentation);

                            if (elementFlag) {
                                if (nDims == 2)
                                    outWriter.print("<element index=\""+i+
                                                    ","+j+"\">");
                                else
                                    outWriter.print("<element index=\""+jj+
                                                    ","+i+","+j+"\">");
                            }
                            else
                                outWriter.print(elementDelimiter);
			    if (useCDATA2) {
                               outWriter.print(CDATA_BEGIN);
                               outWriter.print(((String [])aRow)[j]); 
			       if (useCDATA2) outWriter.print(CDATA_END);
                            } else {
                               outWriter.print(GetMyCDFData.
                                   replaceStringDataToXML(((String [])aRow)[j]));
                            }
                            if (elementFlag) {
                                outWriter.println("</element>");
                            }
                            else
                                outWriter.println(elementDelimiter);
                        }
                        break;
                    case (int)CDF_BYTE:
                    case (int)CDF_INT1:
                        aRow = (byte [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            outWriter.print(((byte [])aRow)[j]);
                        }
                        break;
                    case (int)CDF_INT2:
                        aRow = (short [])Array.get(subArrays[(int)nDims - 2], i)
;
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            outWriter.print(((short [])aRow)[j]);
                        }
                        break;
                    case (int)CDF_UINT1:
                        aRow = (short [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            if (((short [])aRow)[j] >=0) 
				outWriter.print(((short [])aRow)[j]);
			    else {
				short tmp = (short) (((short [])aRow)[j] + 256);
				outWriter.print(tmp);
			    }
                        }
                        break;
                    case (int)CDF_INT4:
                        aRow = (int [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            outWriter.print(((int [])aRow)[j]);
                        }
                        break;
                    case (int)CDF_UINT2:
                        aRow = (int [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            if (((int [])aRow)[j] >=0)
                                outWriter.print(((int [])aRow)[j]);
                            else {
                                int tmp = (int) (((int [])aRow)[j] + 65536);
                                outWriter.print(tmp);
                            }
                        }
                        break;
                    case (int)CDF_UINT4:
                        aRow = (long [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            if (((long [])aRow)[j] >=0)
                                outWriter.print(((long [])aRow)[j]);
                            else {
                                long tmp = (long) (((long [])aRow)[j]+
						   4294967296L);
                                outWriter.print(tmp);
                            }
                        }
                        break;
                    case (int)CDF_INT8:
                        aRow = (long [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            outWriter.print(((long [])aRow)[j]);
                        }
                        break;
                    case (int)CDF_REAL4:
                    case (int)CDF_FLOAT:
                        aRow = (float [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            outWriter.print(((float [])aRow)[j]);
                        }
                        break;
                    case (int)CDF_REAL8:
                    case (int)CDF_DOUBLE:
                        aRow = (double [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                            outWriter.print(((double [])aRow)[j]);
                        }
                        break;
                    case (int)CDF_EPOCH:
                        aRow = (double [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
			    outWriter.print((!iso8601)?
                                            Epoch.encode(((double [])aRow)[j]):
                                            (Epoch.encode4(((double [])aRow)[j])+
                                             (withz?"Z":"")));
                        }
                        break;
                    case (int)CDF_EPOCH16:
                        aRow = (double [])Array.get(subArrays[(int)nDims - 2], i);
			double[] twoDouble = new double[2];
                        for (int j=0,k=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
			    twoDouble[0] = ((double [])aRow)[k++];
			    twoDouble[1] = ((double [])aRow)[k++];
                            outWriter.print((!iso8601)?
                                            Epoch16.encode(twoDouble):
                                            (Epoch16.encode4(twoDouble)+
                                             (withz?"Z":"")));
                        }
                        break;
                    case (int)CDF_TIME_TT2000:
                        aRow = (long [])Array.get(subArrays[(int)nDims - 2], i);
                        for (int j=0; j<dimSizes[nDims - 1]; j++) {
                            if (j>0) outWriter.print(elementDelimiter);
                              outWriter.print(
                                  CDFTT2000.encode(((long [])aRow)[j])+
                                  (withz?"Z":""));
                        }
                        break;
                    default:
                        break;
                    }      /* switch (dataType) */
                    n += dimSizes[nDims - 1];

                }          /* for (int i=0;i<dimSizes[(int)nDims-2];i++) */ 

                if (dataType == CDF_CHAR || dataType == CDF_UCHAR) indent--;
            }              /* while (n < boundary[0]) */

            if (dataType == CDF_CHAR || dataType == CDF_UCHAR) {
                outputIndentation (outWriter, indent, indentation);
                if (!elementFlag && useCDATA2) outWriter.print (CDATA_END);
            }
            outWriter.println (recEndIndicator);
        }
    }

    /**
     * Dumps variable data, one value, with its type, at a time per record.
     * For dimensional variable, the values are wrapped in "array" element.
     * utility for dumping data to a screen.  Data can be scalar or 
     * 1-dimensional or multi-dimensional array of any data type. All epoch
     * data are in ISO8601.<P>
     *
     * The following example retrieves the first record, comprised of
     * 3x5 (3 rows and 5 columns) array, into a generic object and dumps 
     * its contents to screen one row at a time.  In this case three rows
     *  will be displayed on a screen, each row containing 5 elements. 
     * <PRE>
     *     GetMyCDFData data;
     *     CDFData datax;
     *     long[] dimIndices   = {0,0};
     *     long[] dimIntervals = {3,5};
     *     long[] dimSizes     = {1,1}; <P>
     *     datax = var.getHyperDataObject(0L,         // record start
     *                                    1,          // record counts 
     *                                    1,          // record interval
     *                                    dimIndices,
     *                                    dimSizes,
     *                                    dimIntervals);
     *     data = GetMyCDFData.create(datax, var.getDataType(),
     *                                var.getNumDims(),var.getDimSizes(),
     *                                var.getNumElements());
     *     data.dumpData2(....);
     * </PRE>
     *
     */
    public void dumpData2(PrintWriter outWriter, 
                          long     dataType,
                          String   valueStart,
                          String   valueEnd,
                          int      indent,
                          String   indentation,
                          boolean  withz) {
        dumpData2(outWriter, dataType, valueStart, valueEnd,
                  indent, indentation, withz, true);
    }

    /**
     * Dumps variable data, one row at a time per record.  This is a generic
     * utility for dumping data to a screen.  Data can be scalar or 
     * 1-dimensional or multi-dimensional array of any data type. All epoch
     * data are in ISO8601.<P>
     *
     * The following example retrieves the first record, comprised of
     * 3x5 (3 rows and 5 columns) array, into a generic object and dumps 
     * its contents to screen one row at a time.  In this case three rows
     *  will be displayed on a screen, each row containing 5 elements. 
     * <PRE>
     *     GetMyCDFData data;
     *     CDFData datax;
     *     long[] dimIndices   = {0,0};
     *     long[] dimIntervals = {3,5};
     *     long[] dimSizes     = {1,1}; <P>
     *     datax = var.getHyperDataObject(0L,         // record start
     *                                    1,          // record counts 
     *                                    1,          // record interval
     *                                    dimIndices,
     *                                    dimSizes,
     *                                    dimIntervals);
     *     data = GetMyCDFData.create(datax, var.getDataType(),
     *                                var.getNumDims(),var.getDimSizes(),
     *                                var.getNumElements());
     *     data.dumpData2(....);
     * </PRE>
     *
     */
    public void dumpData2(PrintWriter outWriter, 
                          long     dataType,
                          String   valueStart,
                          String   valueEnd,
                          int      indent,
                          String   indentation,
                          boolean  withz,
                          boolean  useCDATA) {

        /////////////////////////////////////////////////////////////
        //                                                         //
        //                    Dump Scalar or 1D Arrays             //
        //                                                         //
        /////////////////////////////////////////////////////////////

        String dataTypeElem = GetMyCDFData.getDataTypeElement(dataType);
        indent++;
        boolean useCDATA2;
        if (nDims <= 1) {
            if (nDims == 0) {
                if (dataType == CDF_EPOCH) {
                    String value;
                    if (!_dataArray.getClass().isArray()) {
                      Double lEpoch = (Double) _dataArray;
                      outputIndentation (outWriter, indent, indentation);
                      String epoch = Epoch.encode4(lEpoch);
                      value = new StringBuffer(epoch).append(withz?"Z":"").
                                                      toString();
                      outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                         valueEnd);
                    } else {
                      double lEpoch = ((double[]) _dataArray)[0];
                      outputIndentation (outWriter, indent, indentation);
                      String epoch = Epoch.encode4(lEpoch);
                      value = new StringBuffer(epoch).append(withz?"Z":"").
                                                      toString();
                      outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                         valueEnd);
                    }
                } else if (dataType == CDF_EPOCH16) {
                    String value;
                    double[] lEpoch = (double[]) _dataArray;
                    outputIndentation (outWriter, indent, indentation);
                    String epoch = Epoch16.encode4(lEpoch);
                    value = new StringBuffer(epoch).append(withz?"Z":"").
                                                      toString();
                    outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                       valueEnd);
                } else if (dataType == CDF_TIME_TT2000) {
                    String value;
                    if (!_dataArray.getClass().isArray()) {
                      Long lEpoch = (Long) _dataArray;
                      outputIndentation (outWriter, indent, indentation);
                      String epoch = CDFTT2000.encode(lEpoch.longValue());
                      value = new StringBuffer(epoch).append(withz?"Z":"").
                                                      toString();
                      outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                         valueEnd);
                    } else {
                      long lEpoch = ((long[]) _dataArray)[0];
                      outputIndentation (outWriter, indent, indentation);
                      String epoch = CDFTT2000.encode(lEpoch);
                      value = new StringBuffer(epoch).append(withz?"Z":"").
                                                      toString();
                      outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                         valueEnd);
                    }
                } 
                else {
                    outputIndentation (outWriter, indent, indentation);
                    if (!_dataArray.getClass().isArray()) {
                       if (dataType != CDF_CHAR && dataType != CDF_UCHAR) 
                          outWriter.println(valueStart+dataTypeElem+"\">"+
                                            _dataArray+valueEnd);
                       else
                          outWriter.println(valueStart+dataTypeElem+"\">"+
                                            GetMyCDFData.replaceStringDataToXML(
                                                            _dataArray)+
                                            valueEnd);
                    } else {
                       Object ttt = Array.get(_dataArray,0);
                       if (dataType != CDF_CHAR && dataType != CDF_UCHAR)
                         outWriter.println(valueStart+dataTypeElem+"\">"+
                                           ttt+valueEnd);
                       else
                         outWriter.println(valueStart+dataTypeElem+"\">"+
                                           GetMyCDFData.replaceStringDataToXML(ttt)+
                                           valueEnd);
                    }
                }
            } else { // 1-D
                outputIndentation (outWriter, indent, indentation);
                outWriter.println ("<array>");
                switch ((int) dataType) {
                case (int)CDF_CHAR:
                case (int)CDF_UCHAR: {
                    Object value;
                    int lastElement = dimSizes[nDims-1];
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        if (indent != -99)
                            outputIndentation (outWriter, indent+1, indentation);
                        value = GetMyCDFData.replaceStringDataToXML(
                                                    ((String [])_dataArray)[j]);
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_BYTE:
                case (int)CDF_INT1: {
                    byte value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        value = ((byte [])_dataArray)[j];
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_INT2: {
                    short value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        value = ((short [])_dataArray)[j];
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_UINT1: {
                    short value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        if (((short [])_dataArray)[j] >=0) 
                            value = ((short [])_dataArray)[j];
			else
                            value = (short) (((short [])_dataArray)[j]+256);
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_INT4: {
                    int value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        value = ((int [])_dataArray)[j];
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_UINT2: {
                    int value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        if (((int [])_dataArray)[j] >=0)
                            value = ((int [])_dataArray)[j];
                        else
                            value = ((int [])_dataArray)[j]+65536;
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_UINT4: {
                    long value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        if (((long [])_dataArray)[j] >=0)
                            value = ((long [])_dataArray)[j];
                        else
                            value = ((long [])_dataArray)[j]+4294967296L;
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_INT8: {
                    long value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        value = ((long [])_dataArray)[j];
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_REAL4:
                case (int)CDF_FLOAT: {
                    float value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        value = ((float [])_dataArray)[j];
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_REAL8:
                case (int)CDF_DOUBLE: {
                    double value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        value = ((double [])_dataArray)[j];
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_EPOCH: {
                    String value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        String epoch = Epoch.encode4(((double [])_dataArray)[j]);
                        value = new StringBuffer(epoch).append(withz?"Z":"").
                                                        toString();
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_EPOCH16: {
                    String value;
		    double[] twoDouble = new double[2];
                    for (int j=0, k=0; j<dimSizes[nDims - 1]; j++) {
			twoDouble[0] = ((double [])_dataArray)[k++];
			twoDouble[1] = ((double [])_dataArray)[k++];
                        outputIndentation (outWriter, indent+1, indentation);
                        String epoch = Epoch16.encode4(twoDouble);
                        value = new StringBuffer(epoch).append(withz?"Z":"").
                                                      toString();
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                case (int)CDF_TIME_TT2000: {
                    String value;
                    for (int j=0; j<dimSizes[nDims - 1]; j++) {
                        outputIndentation (outWriter, indent+1, indentation);
                        String epoch = CDFTT2000.encode(((long [])_dataArray)[j]);
                        value = new StringBuffer(epoch).append(withz?"Z":"").
                                                        toString();
                        outWriter.println (valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                    }
                    break;
                }
                default:
                    break;
                } /* switch (dataType) */

            }
            if (nDims > 0) {
               outputIndentation (outWriter, indent, indentation);
               outWriter.println ("</array>");
            }
        /////////////////////////////////////////////////////////////
        //                                                         //
        //              Dump Multidimensional Arrays               //
        //                                                         //
        /////////////////////////////////////////////////////////////

        } else {
          int outer;
            /*
             * Setup the subArrays array
             * cIndex is the holds the index for the current subarray
             * boundary is the # of values in the subarray
             */
            Object aRow = null;
            Object [] subArrays = new Object[(int)nDims-1];
            int [] cIndex   = new int[(int)nDims-1];
            long [] boundary = new long[(int)nDims-1];
            int indent_keep;
            int jj=0;
            indent_keep = 0;
            subArrays[0] = _dataArray;
            cIndex[0] = 0;
	    boundary[0] = product(dimSizes,0,(int)nDims);

            for (int i=1; i<(int)nDims-1;i++) {
                subArrays[i] = Array.get(subArrays[i-1], 0);
                boundary[i] = product(dimSizes,i,(int)nDims);
                cIndex[i] = 0;
            }
            String className = _dataArray.getClass().getName();
            int n = 0; // The current element in the _data
            Object cObject = _dataArray;  // A temp object to hold a subarray
            boolean boundaryCrossed;
            outer = 0;
            boolean first;
            first = true;
            while (n < boundary[0]) {
                // Get the correct 2D subarray to print
                if (n!=0) {
                    jj++;      // Increment the counter for 3-D

                    for (int i = 0; i < (int)nDims-1; i++) {
                        boundaryCrossed = ((n % boundary[i]) == 0);
                        if (boundaryCrossed) {
                            // Get the next sub array
                            cIndex[i]+=1;
                            cObject = Array.get(cObject, cIndex[i]);
                            subArrays[i] = cObject;

                            // Get the first element of each
                            // subsequent subarray
                            for (int j=i+1;j<(int)nDims-1;j++) {
                                cIndex[j] = 0;
                                subArrays[j] =
                                    Array.get(subArrays[j-1],cIndex[j]);
                            }
                            break;

                        } else {
                            cObject = subArrays[i];
                        }
                    }
                }

                // Fill the correct elements of _data
                if (nDims > 2) {
                  outer = nDims - 1;
                  if (first) {
                    for (jj = 0; jj < outer; ++jj) {
                      outputIndentation (outWriter, indent+jj, indentation);
                      outWriter.println("<array>");
                    }
                    first = false;
                    indent = indent + outer - 1;
                    indent_keep=indent;
                  } else {
                    indent=indent_keep;
                    outputIndentation (outWriter, indent, indentation);
                    outWriter.println("<array>");
                  }
                } else {
                    outputIndentation (outWriter, indent, indentation);
                    outWriter.println("<array>");
                }

                for (int i=0;i<dimSizes[(int)nDims-2];i++) {
                    outputIndentation (outWriter, indent+1, indentation);
                    outWriter.println("<array>");
                    if (i > 0) { 
                        if (dataType == CDF_CHAR || dataType == CDF_UCHAR) 
                           indent--;
                    }
                    switch ((int) dataType) {
                    case (int)CDF_CHAR:
                    case (int)CDF_UCHAR: {
                      aRow =
                          (String [])Array.get(subArrays[(int)nDims - 2], i);
                      indent++;
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          if (indent != -99)
                              outputIndentation (outWriter, indent+2, 
                                                 indentation);
                          Object value = GetMyCDFData.replaceStringDataToXML(
                                                           ((String [])aRow)[j]);
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_BYTE:
                    case (int)CDF_INT1: {
                      byte value;
                      aRow = (byte [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          value = ((byte [])aRow)[j];
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                           valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_INT2: {
                      short value;
                      aRow = (short [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          value = ((short[])aRow)[j];
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_UINT1: {
                      short value;
                      aRow = (short [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          if (((short [])aRow)[j] >=0) 
                              value = ((short [])aRow)[j];
                          else
                              value = (short) (((short [])aRow)[j] + 256);
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_INT4: {
                      int value;
                      aRow = (int [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          value = ((int [])aRow)[j];
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_UINT2: {
                      int value;
                      aRow = (int [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          if (((int [])aRow)[j] >=0)
                              value = ((int [])aRow)[j];
                          else
                              value = (((int [])aRow)[j] + 65536);
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_UINT4: {
                      long value;
                      aRow = (long [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          if (((long [])aRow)[j] >=0)
                             value = ((long [])aRow)[j];
                          else
                             value = (long) (((long [])aRow)[j]+ 4294967296L);
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                        break;
                    }
                    case (int)CDF_INT8: {
                      long value;
                      aRow = (long [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                        value = ((long [])aRow)[j];
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_REAL4:
                    case (int)CDF_FLOAT: {
                      float value;
                      aRow = (float [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                        value = ((float [])aRow)[j];
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_REAL8:
                    case (int)CDF_DOUBLE: {
                      double value;
                      aRow = (double [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          value = ((double [])aRow)[j];
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_EPOCH: {
                      String value;
                      aRow = (double [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          String epoch = Epoch.encode4(((double [])aRow)[j]);
                          value = new StringBuffer(epoch).append(withz?"Z":"").
                                                          toString();
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_EPOCH16: {
                      String value;
                      aRow = (double [])Array.get(subArrays[(int)nDims - 2], i);
		      double[] twoDouble = new double[2];
                      for (int j=0,k=0; j<dimSizes[nDims - 1]; j++) {
	                  twoDouble[0] = ((double [])aRow)[k++];
	                  twoDouble[1] = ((double [])aRow)[k++];
                          outputIndentation (outWriter, indent+2, indentation);
                          String epoch = Epoch16.encode4(twoDouble);
                          value = new StringBuffer(epoch).append(withz?"Z":"").
                                                          toString();
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    case (int)CDF_TIME_TT2000: {
                      String value;
                      aRow = (long [])Array.get(subArrays[(int)nDims - 2], i);
                      for (int j=0; j<dimSizes[nDims - 1]; j++) {
                          outputIndentation (outWriter, indent+2, indentation);
                          String epoch = CDFTT2000.encode(((long [])aRow)[j]);
                          value = new StringBuffer(epoch).append(withz?"Z":"").
                                                          toString();
                          outWriter.println(valueStart+dataTypeElem+"\">"+value+
                                            valueEnd);
                      }
                      break;
                    }
                    default:
                        break;
                    }      /* switch (dataType) */
                    n += dimSizes[nDims - 1];
                    outputIndentation (outWriter, indent+1, indentation);
                    outWriter.println("</array>");

                }          /* for (int i=0;i<dimSizes[(int)nDims-2];i++) */ 
                outputIndentation (outWriter, indent, indentation);
                outWriter.println ("</array>");
            }              /* while (n < boundary[0]) */
            indent = indent - outer + 1;
            if (outer > 0) {
              for (jj = (outer-1); jj > 0; --jj) {
                outputIndentation (outWriter, indent+jj-1, indentation);
                outWriter.println("</array>");
              }
            }
        }
    }

}


