// $Id: DODSStructure.java,v 1.12 2004/11/18 23:24:58 caron Exp $
/*
 * Copyright 1997-2004 Unidata Program Center/University Corporation for
 * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
 * support@unidata.ucar.edu.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, strlenwrite to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package ucar.nc2.dods;

import ucar.ma2.*;
import ucar.nc2.*;
import ucar.unidata.util.StringUtil;
import dods.dap.*;

import java.util.*;
import java.io.IOException;

/**
 * A DODS Structure.
 *
 * @author caron
 * @version $Revision: 1.12 $ $Date: 2004/11/18 23:24:58 $
 */

public class DODSStructure extends ucar.nc2.Structure {
  private DConstructor ds;
  protected DODSNetcdfFile dodsfile; // so we dont have to cast everywhere
  protected String dodsShortName;

  //protected DODSStructure( DODSNetcdfFile dodsfile, Structure parentStructure, String shortName) { // for subclasses
    //super(dodsfile, null, parentStructure, shortName);
  //}

  /* copy constructor
  protected DODSStructure( String shortName, DODSStructure from) { // for subclasses
    super(from.dodsfile, from.name);
    this.shortName = shortName;
    this.containers = from.containers;
    this.attributes = from.attributes;

    for (int i=0; i<from.variables.size(); i++) {
      DODSVariable fromv = (DODSVariable) from.variables.get(i);
      variables.add( new DODSVariable( fromv.getNameForDisplay(), fromv));
    }

    for (int i=0; i<from.structures.size(); i++) {
      DODSStructure froms = (DODSStructure) from.structures.get(i);
      if (froms instanceof DODSGrid)
        structures.add( new DODSGrid( froms.getNameShort(), (DODSGrid) froms));
      else if (froms instanceof DODSStructureArray)
        structures.add( new DODSStructureArray( froms.getNameShort(), (DODSStructureArray) froms));
      else if (froms instanceof DODSSequence)
        structures.add( new DODSSequence( froms.getNameShort(), (DODSSequence) froms));
      else
        structures.add( new DODSStructure( froms.getNameShort(), froms));
    }
  } */

  // constructor called from DODSNetcdfFile.makeVariable() for scalar Structure or Sequence
  DODSStructure( DODSNetcdfFile dodsfile, Group parentGroup, Structure parentStructure, String shortName,
         DODSNetcdfFile.DodsV dodsV) throws IOException {

    super(dodsfile, parentGroup, parentStructure, shortName);
    this.dodsfile = dodsfile;
    this.ds = (DConstructor) dodsV.bt;
    this.dodsShortName = shortName;

    if (ds instanceof DSequence) {
      this.dimensions.add( Dimension.UNKNOWN);
      this.shape = new int[1]; // scalar
    } else
      this.shape = new int[0]; // scalar

    this.ranges = Range.factory( shape);

    for (int i = 0; i < dodsV.children.size(); i++) {
      DODSNetcdfFile.DodsV nested = (DODSNetcdfFile.DodsV) dodsV.children.get(i);
      dodsfile.addVariable( parentGroup, this, nested);
    }

    if (ds instanceof DSequence)
      isVlen = true;
  }

  // constructor called from DODSNetcdfFile.makeVariable() for array of Structure
  DODSStructure( DODSNetcdfFile dodsfile, Group parentGroup, Structure parentStructure, String shortName,
                 DArray dodsArray, DODSNetcdfFile.DodsV dodsV) throws IOException {
    this( dodsfile, parentGroup, parentStructure, shortName, dodsV);
    ArrayList dims = dodsfile.constructDimensions( parentGroup, dodsArray);
    setDimensions(dims);
  }

  DConstructor getDConstructor() { return ds; }

  // package access needed
  protected void calcIsCoordinateVariable() { super.calcIsCoordinateVariable(); }

  /** Let the Structure fill in here. */
  public String writeCDL(String space, boolean useFullName, boolean strict) {
    return super.writeCDL( space, useFullName, strict);
  }

  protected String getDODSshortName() { return dodsShortName; }


  ///////////////////////////////////////////////////////////////////////
  /**
   * Return an iterator over the set of repeated structures. The iterator
   * will return an object of type Structure. When you call this method, the
   * Sequence will be read using the given constraint expression, and the data
   * returned sequentially.
   *
   * <br> If the data has been cached by a read() to an enclosing container, you must
   * leave the CE null. Otherwise a new call will be made to the server.
   *
   * @param CE constraint expression, or null.
   * @return iterator over type DODSStructure.
   * @see DODSStructure
   */
  public Structure.Iterator getStructureIterator(String CE) throws java.io.IOException {
    return new SequenceIterator(CE);
  }

  //void setCache( DSequence seq) { this.seq = seq; }

  //private DSequence seq = null;
  private class SequenceIterator extends Structure.Iterator {
    private int row = 0;
    private DSequence seq = null;

    SequenceIterator(String CE) throws java.io.IOException {

      if (CE != null)
        CE = getDODSshortName() + CE;
      else {
        CE = getDODSshortName();
      }

        // contact the server
      try {
        dods.dap.DataDDS dataDDS = dodsfile.readDataDDSfromServer(CE);
        seq = (DSequence) dataDDS.getVariable(shortName);

      } catch (Exception e) {
        System.out.println("DODSSequence read failed on "+getDODSshortName()+"\n"+e);
        e.printStackTrace(System.out);
        throw new IOException( e.getMessage());
      }
    }

    public boolean hasNext() {
      return row < seq.getRowCount();
    }

    public StructureData next() {
      Vector v = seq.getRow(row);

    // unpack all of the data that comes back
      Enumeration enumVars = v.elements();
      StructureData data = dodsfile.convertStructureData(enumVars, DODSStructure.this);

      row++;
      return data;
    }

    public void remove() { throw new UnsupportedOperationException(); }
  }

}

/* Change History:
   $Log: DODSStructure.java,v $
   Revision 1.12  2004/11/18 23:24:58  caron
   add sequence iterator to DODSequence

   Revision 1.11  2004/11/10 17:01:35  caron
   redo Grids

   Revision 1.10  2004/11/07 02:55:11  caron
   no message

   Revision 1.9  2004/10/29 00:14:10  caron
   no message

   Revision 1.8  2004/10/19 19:46:18  caron
   change if dimensions are shared

   Revision 1.7  2004/10/13 19:45:12  caron
   add strict NCDump

   Revision 1.6  2004/10/06 19:03:42  caron
   clean up javadoc
   change useV3 -> useRecordsAsStructure
   remove id, title, from NetcdfFile constructors
   add "in memory" NetcdfFile

   Revision 1.5  2004/08/26 17:55:08  caron
   no message

   Revision 1.4  2004/08/16 20:53:51  caron
   2.2 alpha (2)

   Revision 1.3  2004/07/12 23:40:18  caron
   2.2 alpha 1.0 checkin

   Revision 1.2  2004/07/06 19:28:12  caron
   pre-alpha checkin

   Revision 1.1.1.1  2003/12/04 21:05:28  caron
   checkin 2.2

   Revision 1.2  2003/06/03 20:06:14  caron
   fix javadocs

   Revision 1.1  2003/04/08 15:06:31  caron
   nc2 version 2.1

 */
