libdap  Updated for version 3.17.0
Grid.cc
00001 
00002 // -*- mode: c++; c-basic-offset:4 -*-
00003 
00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00005 // Access Protocol.
00006 
00007 // Copyright (c) 2002,2003 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 // (c) COPYRIGHT URI/MIT 1994-1999
00027 // Please read the full copyright statement in the file COPYRIGHT_URI.
00028 //
00029 // Authors:
00030 //      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
00031 
00032 // implementation for Grid.
00033 //
00034 // jhrg 9/15/94
00035 
00036 #include "config.h"
00037 
00038 // #define DODS_DEBUG
00039 
00040 #include <sstream>
00041 #include <functional>
00042 #include <algorithm>
00043 
00044 #include "Grid.h"
00045 #include "DDS.h"
00046 #include "Array.h"  // for downcasts
00047 #include "util.h"
00048 #include "InternalErr.h"
00049 #include "escaping.h"
00050 #include "XDRStreamMarshaller.h"
00051 #include "debug.h"
00052 
00053 #include "XMLWriter.h"
00054 #include "DMR.h"
00055 #include "D4Group.h"
00056 #include "D4Maps.h"
00057 #include "D4Attributes.h"
00058 
00059 using namespace std;
00060 
00061 namespace libdap {
00062 
00063 void
00064 Grid::m_duplicate(const Grid &s)
00065 {
00066     // TODO revisit this code once/if the class is switched from using it's
00067     // own vars to those in Constructor. jhrg 4/3/13
00068 
00069         // copy the weak pointer - Constructor will take care of copying
00070         // the 'strong' pointers.
00071         //d_array_var = s.d_array_var;
00072         d_is_array_set = s.d_is_array_set;
00073 }
00074 
00084 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
00085 {}
00086 
00098 Grid::Grid(const string &n, const string &d)
00099     : Constructor(n, d, dods_grid_c), d_is_array_set(false)
00100 {}
00101 
00103 Grid::Grid(const Grid &rhs) : Constructor(rhs)
00104 {
00105     m_duplicate(rhs);
00106 }
00107 
00108 Grid::~Grid()
00109 {
00110         //d_array_var = 0;      // Weak pointer; object will be freed by Constructor
00111 }
00112 
00113 BaseType *
00114 Grid::ptr_duplicate()
00115 {
00116     return new Grid(*this);
00117 }
00118 
00119 Grid &
00120 Grid::operator=(const Grid &rhs)
00121 {
00122     if (this == &rhs)
00123         return *this;
00124 
00125     // Removed this; it makes this operator= work differently than the rest
00126 #if 0
00127     delete d_array_var; d_array_var = 0;
00128 
00129     for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
00130         BaseType *btp = *i ;
00131         delete btp ;
00132     }
00133 #endif
00134 
00135     dynamic_cast<Constructor &>(*this) = rhs;
00136 
00137     m_duplicate(rhs);
00138 
00139     return *this;
00140 }
00141 
00142 // FIXME transform_to_dap4 probably needs to run for side effect only.
00143 // drop the return BT and add variables to the D4Group that is passed
00144 // in instead of the DMR.
00145 //
00146 // Also need to handle the case where a Grid is part of a Structure
00147 BaseType *
00148 Grid::transform_to_dap4(D4Group *root, Constructor *container)
00149 {
00150     BaseType *btp = array_var()->transform_to_dap4(root, container);
00151     Array *coverage = static_cast<Array*>(btp);
00152     if (!coverage)
00153         throw InternalErr(__FILE__, __LINE__, "Expected an Array while transforming a Grid (coverage)");
00154 
00155         coverage->set_parent(container);
00156 
00157         // Next find the maps; add them to the coverage and to the container,
00158         // the latter only on the condition that they are not already there.
00159 
00160         for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
00161         btp = (*i)->transform_to_dap4(root, container);
00162         Array *map = static_cast<Array*>(btp);
00163         if (!map)
00164                 throw InternalErr(__FILE__, __LINE__, "Expected an Array while transforming a Grid (map)");
00165 
00166         // map must be non-null (Grids cannot contain Grids in DAP2)
00167                 if (map) {
00168                         // Only add the map/array if it not already present; given the scoping rules
00169                         // for DAP2 and the assumption the DDS is valid, testing for the same name
00170                         // is good enough.
00171                         if (!root->var(map->name())) {
00172                                 map->set_parent(container);
00173                                 container->add_var_nocopy(map); // this adds the array to the container
00174                         }
00175                         D4Map *dap4_map = new D4Map(map->name(), map, coverage);        // bind the 'map' to the coverage
00176                         coverage->maps()->add_map(dap4_map);    // bind the coverage to the map
00177                 }
00178                 else {
00179                         throw InternalErr(__FILE__, __LINE__,
00180                                         "transform_to_dap4() returned a null value where there can be no Grid.");
00181                 }
00182         }
00183 
00184         container->add_var_nocopy(coverage);
00185 
00186     // Since a Grid (DAP2) to a Coverage (DAP4) removes a lexical scope
00187     // in favor of a set of relations, Grid::transform_to_dap4() does not
00188     // return a BaseType*. Callers should assume it has correctly added
00189     // stuff to the container and group.
00190     return 0;
00191 }
00192 
00193 
00199 bool
00200 Grid::is_dap2_only_type()
00201 {
00202     return true;
00203 }
00204 
00217 void
00218 Grid::add_var(BaseType *bt, Part part)
00219 {
00220     if (!bt)
00221         throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
00222 
00223     if (part == array && d_is_array_set/*get_array()*/) {
00224       // Avoid leaking memory...  Function is add, not set, so it is an error to call again for the array part.
00225       throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
00226     }
00227 
00228     // avoid obvious broken semantics
00229     if (!dynamic_cast<Array*>(bt)) {
00230       throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
00231     }
00232 
00233     // Set to the clone of bt if we get that far.
00234     BaseType* bt_clone = 0;
00235 
00236     switch (part) {
00237 
00238     case array: {
00239         // Add it as a copy to preserve old semantics.  This sets parent too.
00240         bt_clone = bt->ptr_duplicate();
00241         set_array(static_cast<Array*>(bt_clone));
00242     }
00243     break;
00244 
00245     case maps: {
00246             bt_clone = bt->ptr_duplicate();
00247             bt_clone->set_parent(this);
00248             d_vars.push_back(bt_clone);
00249         }
00250     break;
00251 
00252     default: {
00253         if (!d_is_array_set) {
00254             // Add it as a copy to preserve old semantics.  This sets parent too.
00255             bt_clone = bt->ptr_duplicate();
00256             set_array(static_cast<Array*>(bt_clone));
00257         }
00258         else {
00259             bt_clone = bt->ptr_duplicate();
00260             bt_clone->set_parent(this);
00261             d_vars.push_back(bt_clone);
00262         }
00263     }
00264     break;
00265   }
00266 }
00267 
00283 void
00284 Grid::add_var_nocopy(BaseType *bt, Part part)
00285 {
00286     if (!bt)
00287         throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
00288 
00289     if (part == array && d_is_array_set/*get_array()*/) {
00290       // Avoid leaking memory...  Function is add, not set, so it is an error to call again for the array part.
00291       throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
00292     }
00293 
00294     // avoid obvious broken semantics
00295     if (!dynamic_cast<Array*>(bt)) {
00296       throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
00297     }
00298 
00299     bt->set_parent(this);
00300 
00301     switch (part) {
00302 
00303     case array: {
00304         // Refactored to use new set_array ([mjohnson 11 nov 2009])
00305         set_array(static_cast<Array*>(bt));
00306     }
00307     break;
00308 
00309     case maps: {
00310         // FIXME Why is this commented out?
00311             //bt->set_parent(this);
00312             d_vars.push_back(bt);
00313         }
00314     break;
00315 
00316     default: {
00317         if (!d_is_array_set) {
00318             // Refactored to use new set_array ([mjohnson 11 nov 2009])
00319             // avoid obvious broken semantics
00320             set_array(static_cast<Array*>(bt));
00321         }
00322         else {
00323             d_vars.push_back(bt);
00324         }
00325     }
00326     break;
00327   }
00328 }
00329 
00343 void Grid::set_array(Array* p_new_arr)
00344 {
00345         if (!p_new_arr) {
00346                 throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
00347         }
00348 
00349         // Make sure not same memory, this would be evil.
00350         if (p_new_arr == get_array()) {
00351                 return;
00352         }
00353 
00354         p_new_arr->set_parent(this);
00355 
00356         // Three cases: 1. There are no variables set for this grid at all
00357         // 2. There are maps but no array
00358         // 3. There is already an array set (and maybe maps).
00359         // NB: d_array_var is a weak pointer to the Grid's Array
00360         if (d_vars.size() == 0) {
00361                 d_vars.push_back(p_new_arr);
00362         }
00363         else if (!d_is_array_set) {
00364                 d_vars.insert(d_vars.begin(), p_new_arr);
00365         }
00366         else {
00367                 // clean out old array
00368                 delete get_array();
00369                 d_vars[0] = p_new_arr;
00370         }
00371 
00372         d_is_array_set = true;
00373 #if 0
00374         // store the array pointer locally
00375         d_array_var = p_new_arr;
00376 
00377         // Set the  parent
00378         d_array_var->set_parent(this);
00379 #endif
00380 }
00381 
00408 Array*
00409 Grid::add_map(Array* p_new_map, bool add_as_copy)
00410 {
00411   if (!p_new_map)
00412     throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
00413 
00414   if (add_as_copy)
00415     p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00416 
00417   p_new_map->set_parent(this);
00418 
00419   d_vars.push_back(p_new_map);
00420 
00421   // return the one that got put into the Grid.
00422   return p_new_map;
00423 }
00424 
00437 Array*
00438 Grid::prepend_map(Array* p_new_map, bool add_copy)
00439 {
00440   if (add_copy)
00441     {
00442       p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00443     }
00444 
00445   p_new_map->set_parent(this);
00446   d_vars.insert(map_begin(), p_new_map);
00447 
00448   return p_new_map;
00449 }
00450 
00454 BaseType *
00455 Grid::array_var()
00456 {
00457     //return d_array_var;
00458         // FIXME Should really test that the array has not be set; maps might be added first. jhrg 5/9/13
00459 #if 0
00460         if (d_array_var)
00461                 cerr << "In array_var(), d_array_var holds a " << d_array_var->type_name() << endl;
00462         else
00463                 cerr << "In array_var(), d_array_var is null" << endl;
00464 #endif
00465         return d_is_array_set /*d_vars.size() > 0*/ ? *d_vars.begin() : 0;
00466 }
00467 
00471 Array *
00472 Grid::get_array()
00473 {
00474     return dynamic_cast<Array*>(array_var());
00475 }
00476 
00478 Grid::Map_iter
00479 Grid::map_begin()
00480 {
00481     // The maps are stored in the second and subsequent elements of the
00482     // d_var vector<BaseType*> of Constructor _unless_ the Array part
00483     // has yet to be set. In the latter case, there are only maps in
00484     // d_vars
00485     return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.begin() + 1: d_vars.begin();
00486 }
00487 
00490 Grid::Map_iter
00491 Grid::map_end()
00492 {
00493     return d_vars.end();
00494 }
00495 
00497 Grid::Map_riter
00498 Grid::map_rbegin()
00499 {
00500     // see above
00501     // return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.rbegin() + 1: d_vars.rbegin();
00502     return d_vars.rbegin();
00503 }
00504 
00507 Grid::Map_riter
00508 Grid::map_rend()
00509 {
00510     return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
00511 }
00512 
00516 Grid::Map_iter
00517 Grid::get_map_iter(int i)
00518 {
00519     // return map_begin() + i;
00520     return d_is_array_set ? map_begin() + 1 + i : map_begin() + i;
00521 }
00522 
00538 int
00539 Grid::components(bool constrained)
00540 {
00541     int comp;
00542 
00543     if (constrained) {
00544         comp = get_array()->send_p() ? 1 : 0;
00545 
00546         for (Map_iter i = map_begin(); i != map_end(); i++) {
00547             if ((*i)->send_p()) {
00548                 comp++;
00549             }
00550         }
00551     }
00552     else {
00553         comp = d_vars.size();
00554     }
00555 
00556     return comp;
00557 }
00558 
00559 void Grid::transfer_attributes(AttrTable *at_container)
00560 {
00561         AttrTable *at = at_container->get_attr_table(name());
00562 
00563         if (at) {
00564                 at->set_is_global_attribute(false);
00565 
00566                 array_var()->transfer_attributes(at);
00567 
00568                 Map_iter map = map_begin();
00569                 while (map != map_end()) {
00570                         (*map)->transfer_attributes(at);
00571                         map++;
00572                 }
00573 
00574                 // Trick: If an attribute that's within the container 'at' still has its
00575                 // is_global_attribute property set, then it's not really a global attr
00576                 // but instead an attribute that belongs to this Grid.
00577                 AttrTable::Attr_iter at_p = at->attr_begin();
00578                 while (at_p != at->attr_end()) {
00579                         if (at->is_global_attribute(at_p)) {
00580                                 if (at->get_attr_type(at_p) == Attr_container)
00581                                         get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
00582                                 else
00583                                         get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
00584                         }
00585 
00586                         at_p++;
00587                 }
00588         }
00589 }
00590 
00591 // When projected (using whatever the current constraint provides in the way
00592 // of a projection), is the object still a Grid?
00593 
00610 bool
00611 Grid::projection_yields_grid()
00612 {
00613     // For each dimension in the Array part, check the corresponding Map
00614     // vector to make sure it is present in the projected Grid. If for each
00615     // projected dimension in the Array component, there is a matching Map
00616     // vector, then the Grid is valid.
00617     bool valid = true;
00618     Array *a = get_array();
00619 
00620     // Don't bother checking if the Array component is not included.
00621     if (!a->send_p())
00622         return false;
00623 
00624     // If only one part is being sent, it's clearly not a grid (it must be
00625     // the array part of the Grid that's being sent (given that the above
00626     // test passed and the array is being sent).
00627     if (components(true) == 1)
00628         return false;
00629 
00630     Array::Dim_iter d = a->dim_begin() ;
00631     Map_iter m = map_begin() ;
00632 
00633     while (valid && d != a->dim_end() && m != map_end()) {
00634         Array &map = dynamic_cast<Array&>(**m);
00635         if (a->dimension_size(d, true) && map.send_p()) {
00636             // Check the matching Map vector; the Map projection must equal
00637             // the Array dimension projection
00638             Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
00639             valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
00640                     && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
00641                     && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
00642         }
00643         else {
00644            valid = false;
00645         }
00646 
00647         d++, m++;
00648     }
00649 
00650     return valid;
00651 }
00652 
00654 void
00655 Grid::clear_constraint()
00656 {
00657     get_array()->clear_constraint();
00658     for (Map_iter m = map_begin(); m != map_end(); ++m)
00659         dynamic_cast<Array&>(*(*m)).clear_constraint();
00660 }
00661 
00662 void
00663 Grid::print_decl(FILE *out, string space, bool print_semi,
00664                  bool constraint_info, bool constrained)
00665 {
00666     ostringstream oss;
00667     print_decl(oss, space, print_semi, constraint_info, constrained);
00668     fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
00669 }
00670 
00671 void
00672 Grid::print_decl(ostream &out, string space, bool print_semi,
00673                  bool constraint_info, bool constrained)
00674 {
00675     if (constrained && !send_p())
00676         return;
00677 
00678     // See comment for the FILE* version of this method.
00679     if (constrained && !projection_yields_grid()) {
00680         out << space << "Structure {\n" ;
00681 
00682         get_array()->print_decl(out, space + "    ", true, constraint_info,
00683                                constrained);
00684 
00685         for (Map_citer i = map_begin(); i != map_end(); i++) {
00686             (*i)->print_decl(out, space + "    ", true,
00687                              constraint_info, constrained);
00688         }
00689 
00690         out << space << "} " << id2www(name()) ;
00691     }
00692     else {
00693         // The number of elements in the (projected) Grid must be such that
00694         // we have a valid Grid object; send it as such.
00695         out << space << type_name() << " {\n" ;
00696 
00697         out << space << "  Array:\n" ;
00698         get_array()->print_decl(out, space + "    ", true, constraint_info,
00699                                constrained);
00700 
00701         out << space << "  Maps:\n" ;
00702         for (Map_citer i = map_begin(); i != map_end(); i++) {
00703             (*i)->print_decl(out, space + "    ", true,
00704                              constraint_info, constrained);
00705         }
00706 
00707         out << space << "} " << id2www(name()) ;
00708     }
00709 
00710     if (constraint_info) {
00711         if (send_p())
00712             out << ": Send True";
00713         else
00714             out << ": Send False";
00715     }
00716 
00717     if (print_semi)
00718         out << ";\n" ;
00719 
00720     return;
00721 }
00722 
00726 void
00727 Grid::print_xml(FILE *out, string space, bool constrained)
00728 {
00729     XMLWriter xml(space);
00730     print_xml_writer(xml, constrained);
00731     fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
00732 }
00733 
00737 void
00738 Grid::print_xml(ostream &out, string space, bool constrained)
00739 {
00740     XMLWriter xml(space);
00741     print_xml_writer(xml, constrained);
00742     out << xml.get_doc();
00743 }
00744 
00745 
00746 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
00747 {
00748     XMLWriter &d_xml;
00749     bool d_constrained;
00750     string d_tag;
00751 public:
00752     PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
00753             : d_xml(x), d_constrained(c), d_tag(t)
00754     {}
00755 
00756     void operator()(BaseType *btp)
00757     {
00758         Array *a = dynamic_cast<Array*>(btp);
00759         if (!a)
00760             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00761         a->print_xml_writer_core(d_xml, d_constrained, d_tag);
00762     }
00763 };
00764 
00765 void
00766 Grid::print_xml_writer(XMLWriter &xml, bool constrained)
00767 {
00768     if (constrained && !send_p())
00769         return;
00770 
00771     if (constrained && !projection_yields_grid()) {
00772         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
00773             throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
00774 
00775         if (!name().empty())
00776             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
00777                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
00778 
00779         get_attr_table().print_xml_writer(xml);
00780 
00781         get_array()->print_xml_writer(xml, constrained);
00782 
00783         for_each(map_begin(), map_end(),
00784                  PrintGridFieldXMLWriter(xml, constrained, "Array"));
00785 
00786         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
00787             throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
00788     }
00789     else {
00790         // The number of elements in the (projected) Grid must be such that
00791         // we have a valid Grid object; send it as such.
00792         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
00793             throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
00794 
00795         if (!name().empty())
00796             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
00797                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
00798 
00799         get_attr_table().print_xml_writer(xml);
00800 
00801         get_array()->print_xml_writer(xml, constrained);
00802 
00803         for_each(map_begin(), map_end(),
00804                  PrintGridFieldXMLWriter(xml, constrained, "Map"));
00805 
00806         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
00807             throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
00808     }
00809 }
00810 
00811 void
00812 Grid::print_val(FILE *out, string space, bool print_decl_p)
00813 {
00814     ostringstream oss;
00815     print_val(oss, space, print_decl_p);
00816     fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
00817 }
00818 
00819 void
00820 Grid::print_val(ostream &out, string space, bool print_decl_p)
00821 {
00822     if (print_decl_p) {
00823         print_decl(out, space, false);
00824         out << " = " ;
00825     }
00826 
00827     // If we are printing a value on the client-side, projection_yields_grid
00828     // should not be called since we don't *have* a projection without a
00829     // Constraint. I think that if we are here and send_p() is not true, then
00830     // the value of this function should be ignored. 4/6/2000 jhrg
00831     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
00832     if (pyg || !send_p())
00833         out << "{  Array: " ;
00834     else
00835         out << "{" ;
00836     get_array()->print_val(out, "", false);
00837     if (pyg || !send_p())
00838         out << "  Maps: " ;
00839     for (Map_citer i = map_begin(); i != map_end(); i++, (void)(i != map_end() && out << ", ")) {
00840         (*i)->print_val(out, "", false);
00841     }
00842     out << " }" ;
00843 
00844     if (print_decl_p)
00845         out << ";\n" ;
00846 }
00847 
00848 // Grids have ugly semantics.
00849 
00854 bool
00855 Grid::check_semantics(string &msg, bool all)
00856 {
00857     if (!BaseType::check_semantics(msg))
00858         return false;
00859 
00860     msg = "";
00861 
00862     if (!get_array()) {
00863         msg += "Null grid base array in `" + name() + "'\n";
00864         return false;
00865     }
00866 
00867     // Is it an array?
00868     if (get_array()->type() != dods_array_c) {
00869         msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
00870         return false;
00871     }
00872 
00873     Array *av = (Array *)get_array(); // past test above, must be an array
00874 
00875     // Array must be of a simple_type.
00876     if (!av->var()->is_simple_type()) {
00877         msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
00878         return false;
00879     }
00880 
00881     // enough maps?
00882     if ((unsigned)d_vars.size()-1 != av->dimensions()) {
00883         msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
00884         msg += av->name() + "'\n";
00885         return false;
00886     }
00887 
00888     const string array_var_name = av->name();
00889     Array::Dim_iter asi = av->dim_begin() ;
00890     for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
00891 
00892         BaseType *mv = *mvi;
00893 
00894         // check names
00895         if (array_var_name == mv->name()) {
00896             msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
00897             return false;
00898         }
00899         // check types
00900         if (mv->type() != dods_array_c) {
00901             msg += "Grid map variable  `" + mv->name() + "' is not an array\n";
00902             return false;
00903         }
00904 
00905         Array *mv_a = (Array *)mv; // downcast to (Array *)
00906 
00907         // Array must be of a simple_type.
00908         if (!mv_a->var()->is_simple_type()) {
00909             msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
00910             return false;
00911         }
00912 
00913         // check shape
00914         if (mv_a->dimensions() != 1) {// maps must have one dimension
00915             msg += "Grid map variable  `" + mv_a->name() + "' must be only one dimension\n";
00916             return false;
00917         }
00918         // size of map must match corresponding array dimension
00919         Array::Dim_iter mv_asi = mv_a->dim_begin() ;
00920         int mv_a_size = mv_a->dimension_size(mv_asi) ;
00921         int av_size = av->dimension_size(asi) ;
00922         if (mv_a_size != av_size) {
00923             msg += "Grid map variable  `" + mv_a->name() + "'s' size does not match the size of array variable '";
00924             msg += get_array()->name() + "'s' cooresponding dimension\n";
00925             return false;
00926         }
00927     }
00928 
00929     if (all) {
00930         if (!get_array()->check_semantics(msg, true))
00931             return false;
00932         for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
00933             if (!(*mvi)->check_semantics(msg, true)) {
00934                 return false;
00935             }
00936         }
00937     }
00938 
00939     return true;
00940 }
00941 
00950 void
00951 Grid::dump(ostream &strm) const
00952 {
00953     strm << DapIndent::LMarg << "Grid::dump - ("
00954     << (void *)this << ")" << endl ;
00955     DapIndent::Indent() ;
00956     Constructor::dump(strm) ;
00957 
00958     DapIndent::UnIndent() ;
00959 }
00960 
00961 } // namespace libdap
00962