libdap++  Updated for version 3.8.2
Grid.cc
Go to the documentation of this file.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 <functional>
00041 #include <algorithm>
00042 
00043 #include "Grid.h"
00044 #include "DDS.h"
00045 #include "Array.h"  // for downcasts
00046 #include "util.h"
00047 #include "InternalErr.h"
00048 #include "escaping.h"
00049 
00050 #include "debug.h"
00051 
00052 using namespace std;
00053 
00054 namespace libdap {
00055 
00056 void
00057 Grid::_duplicate(const Grid &s)
00058 {
00059     // Clear out any spurious vars in Constructor::_vars
00060     _vars.clear(); // [mjohnson 10 Sep 2009]
00061 
00062     _array_var = s._array_var->ptr_duplicate();
00063     _array_var->set_parent(this);
00064     _vars.push_back(_array_var); // so the Constructor::Vars_Iter sees it [mjohnson 10 Sep 2009]
00065 
00066     Grid &cs = const_cast<Grid &>(s);
00067 
00068     for (Map_iter i = cs._map_vars.begin(); i != cs._map_vars.end(); i++) {
00069         BaseType *btp = (*i)->ptr_duplicate();
00070         btp->set_parent(this);
00071         _map_vars.push_back(btp);
00072         _vars.push_back(btp); // push all map vectors as weak refs into super::_vars which won't delete them [mjohnson 10 Sep 2009]
00073     }
00074 
00075 }
00076 
00086 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), _array_var(0)
00087 {}
00088 
00100 Grid::Grid(const string &n, const string &d)
00101     : Constructor(n, d, dods_grid_c), _array_var(0)
00102 {}
00103 
00105 Grid::Grid(const Grid &rhs) : Constructor(rhs)
00106 {
00107     _duplicate(rhs);
00108 }
00109 
00110 Grid::~Grid()
00111 {
00112     delete _array_var; _array_var = 0;
00113 
00114     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00115         BaseType *btp = *i ;
00116         delete btp ; btp = 0;
00117     }
00118 }
00119 
00120 BaseType *
00121 Grid::ptr_duplicate()
00122 {
00123     return new Grid(*this);
00124 }
00125 
00126 Grid &
00127 Grid::operator=(const Grid &rhs)
00128 {
00129     if (this == &rhs)
00130         return *this;
00131 
00132     delete _array_var; _array_var = 0;
00133 
00134     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00135         BaseType *btp = *i ;
00136         delete btp ;
00137     }
00138 
00139     // this doesn't copy Constructor::_vars so...
00140     dynamic_cast<Constructor &>(*this) = rhs;
00141 
00142     // we do it in here...
00143     _duplicate(rhs);
00144 
00145     return *this;
00146 }
00147 
00148 int
00149 Grid::element_count(bool leaves)
00150 {
00151     if (!leaves)
00152         return _map_vars.size() + 1;
00153     else {
00154         int i = 0;
00155         for (Map_iter j = _map_vars.begin(); j != _map_vars.end(); j++) {
00156             j += (*j)->element_count(leaves);
00157         }
00158 
00159                 if (!get_array())
00160                         throw InternalErr(__FILE__, __LINE__, "No Grid arry!");
00161 
00162         i += get_array()->element_count(leaves);
00163         return i;
00164     }
00165 }
00166 
00167 void
00168 Grid::set_send_p(bool state)
00169 {
00170     _array_var->set_send_p(state);
00171 
00172     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00173         (*i)->set_send_p(state);
00174     }
00175 
00176     BaseType::set_send_p(state);
00177 }
00178 
00179 void
00180 Grid::set_read_p(bool state)
00181 {
00182     _array_var->set_read_p(state);
00183 
00184     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00185         (*i)->set_read_p(state);
00186     }
00187 
00188     BaseType::set_read_p(state);
00189 }
00190 
00191 void
00192 Grid::set_in_selection(bool state)
00193 {
00194     _array_var->set_in_selection(state);
00195 
00196     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00197         (*i)->set_in_selection(state);
00198     }
00199 
00200     BaseType::set_in_selection(state);
00201 }
00202 
00203 unsigned int
00204 Grid::width()
00205 {
00206     unsigned int sz = _array_var->width();
00207 
00208     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00209         sz += (*i)->width();
00210     }
00211 
00212     return sz;
00213 }
00214 
00222 unsigned int
00223 Grid::width(bool constrained)
00224 {
00225     unsigned int sz = 0;
00226 
00227     if (constrained) {
00228         if (_array_var->send_p())
00229                 sz = _array_var->width(constrained);
00230     }
00231     else {
00232         sz = _array_var->width(constrained);
00233     }
00234 
00235     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00236         if (constrained) {
00237                 if ((*i)->send_p())
00238                         sz += (*i)->width(constrained);
00239         }
00240         else {
00241                 sz += (*i)->width(constrained);
00242         }
00243     }
00244 
00245     return sz;
00246 }
00247 
00248 void
00249 Grid::intern_data(ConstraintEvaluator &eval, DDS &dds)
00250 {
00251     dds.timeout_on();
00252 
00253     if (!read_p())
00254         read();  // read() throws Error and InternalErr
00255 
00256     dds.timeout_off();
00257 
00258     if (_array_var->send_p())
00259         _array_var->intern_data(eval, dds);
00260 
00261     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00262         if ((*i)->send_p()) {
00263             (*i)->intern_data(eval, dds);
00264         }
00265     }
00266 }
00267 
00268 bool
00269 Grid::serialize(ConstraintEvaluator &eval, DDS &dds,
00270                 Marshaller &m, bool ce_eval)
00271 {
00272     dds.timeout_on();
00273 
00274     // Re ticket 560: Get an object from eval that describes how to sample
00275     // and rearrange the data, then perform those actions. Alternative:
00276     // implement this as a selection function.
00277 
00278     if (!read_p())
00279         read();  // read() throws Error and InternalErr
00280 
00281 #if EVAL
00282     if (ce_eval && !eval.eval_selection(dds, dataset()))
00283         return true;
00284 #endif
00285 
00286     dds.timeout_off();
00287 
00288     if (_array_var->send_p())
00289         _array_var->serialize(eval, dds, m, false);
00290 
00291     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00292         if ((*i)->send_p()) {
00293             (*i)->serialize(eval, dds, m, false);
00294         }
00295     }
00296 
00297     return true;
00298 }
00299 
00300 bool
00301 Grid::deserialize(UnMarshaller &um, DDS *dds, bool reuse)
00302 {
00303     _array_var->deserialize(um, dds, reuse);
00304 
00305     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00306         (*i)->deserialize(um, dds, reuse);
00307     }
00308 
00309     return false;
00310 }
00311 
00319 unsigned int
00320 Grid::val2buf(void *, bool)
00321 {
00322     return sizeof(Grid);
00323 }
00324 
00328 unsigned int
00329 Grid::buf2val(void **)
00330 {
00331     return sizeof(Grid);
00332 }
00333 
00334 BaseType *
00335 Grid::var(const string &n, btp_stack &s)
00336 {
00337     return var(n, true, &s);
00338 }
00339 
00344 BaseType *
00345 Grid::var(const string &n, bool, btp_stack *s)
00346 {
00347     string name = www2id(n);
00348 
00349     if (_array_var->name() == name) {
00350         if (s)
00351             s->push(static_cast<BaseType *>(this));
00352         return _array_var;
00353     }
00354 
00355     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00356         if ((*i)->name() == name) {
00357             if (s)
00358                 s->push(static_cast<BaseType *>(this));
00359             return *i;
00360         }
00361     }
00362 
00363     return 0;
00364 }
00365 
00378 void
00379 Grid::add_var(BaseType *bt, Part part)
00380 {
00381     if (!bt) {
00382         throw InternalErr(__FILE__, __LINE__,
00383                           "Passing NULL pointer as variable to be added.");
00384     }
00385 
00386     if (part == array && _array_var) {
00387       // Avoid leaking memory...  Function is add, not set, so it is an error to call again for the array part.
00388       throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
00389     }
00390 
00391     // Set to the clone of bt if we get that far.
00392     BaseType* bt_clone = 0;
00393 
00394     switch (part) {
00395 
00396     case array: {
00397         // Refactored to use new set_array ([mjohnson 11 nov 2009])
00398         Array* p_arr = dynamic_cast<Array*>(bt);
00399         // avoid obvious broken semantics
00400         if (!p_arr) {
00401           throw InternalErr(__FILE__, __LINE__,
00402               "Grid::add_var(): with Part==array: object is not an Array!");
00403         }
00404         // Add it as a copy to preserve old semantics.  This sets parent too.
00405         bt_clone = p_arr->ptr_duplicate();
00406         set_array(static_cast<Array*>(bt_clone));
00407     }
00408     break;
00409 
00410     case maps: {
00411             bt_clone = bt->ptr_duplicate();
00412             bt_clone->set_parent(this);
00413             _map_vars.push_back(bt_clone);
00414         }
00415     break;
00416 
00417     default: {
00418         if (!_array_var) {
00419             // Refactored to use new set_array ([mjohnson 11 nov 2009])
00420             Array* p_arr = dynamic_cast<Array*>(bt);
00421             // avoid obvious broken semantics
00422             if (!p_arr) {
00423               throw InternalErr(__FILE__, __LINE__,
00424                   "Grid::add_var(): with Part==array: object is not an Array!");
00425             }
00426             // Add it as a copy to preserve old semantics.  This sets parent too.
00427             bt_clone = p_arr->ptr_duplicate();
00428             set_array(static_cast<Array*>(bt_clone));
00429         }
00430         else {
00431             bt_clone = bt->ptr_duplicate();
00432             bt_clone->set_parent(this);
00433             _map_vars.push_back(bt_clone);
00434         }
00435     }
00436     break;
00437   }// switch
00438 
00439   // if we get ehre without exception, add the cloned object to the superclass variable iterator
00440   // mjohnson 10 Sep 2009
00441   // Add it to the superclass _vars list so we can iterate on superclass vars
00442   if (bt_clone) {
00443     _vars.push_back(bt_clone);
00444   }
00445 }
00446 
00462 void
00463 Grid::add_var_nocopy(BaseType *bt, Part part)
00464 {
00465     if (!bt) {
00466         throw InternalErr(__FILE__, __LINE__,
00467                           "Passing NULL pointer as variable to be added.");
00468     }
00469 
00470     if (part == array && _array_var) {
00471       // Avoid leaking memory...  Function is add, not set, so it is an error to call again for the array part.
00472       throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
00473     }
00474 
00475     bt->set_parent(this);
00476 
00477     switch (part) {
00478 
00479     case array: {
00480         // Refactored to use new set_array ([mjohnson 11 nov 2009])
00481         Array* p_arr = dynamic_cast<Array*>(bt);
00482         // avoid obvious broken semantics
00483         if (!p_arr) {
00484           throw InternalErr(__FILE__, __LINE__,
00485               "Grid::add_var(): with Part==array: object is not an Array!");
00486         }
00487         set_array(static_cast<Array*>(bt));
00488     }
00489     break;
00490 
00491     case maps: {
00492             //bt->set_parent(this);
00493             _map_vars.push_back(bt);
00494         }
00495     break;
00496 
00497     default: {
00498         if (!_array_var) {
00499             // Refactored to use new set_array ([mjohnson 11 nov 2009])
00500             Array* p_arr = dynamic_cast<Array*>(bt);
00501             // avoid obvious broken semantics
00502             if (!p_arr) {
00503               throw InternalErr(__FILE__, __LINE__,
00504                   "Grid::add_var(): with Part==array: object is not an Array!");
00505             }
00506             set_array(static_cast<Array*>(bt));
00507         }
00508         else {
00509             _map_vars.push_back(bt);
00510         }
00511     }
00512     break;
00513   }// switch
00514 
00515   // if we get here without exception, add the cloned object to the superclass variable iterator
00516   // mjohnson 10 Sep 2009
00517   // Add it to the superclass _vars list so we can iterate on superclass vars
00518   if (bt) {
00519     _vars.push_back(bt);
00520   }
00521 }
00522 
00532 void
00533 Grid::set_array(Array* p_new_arr)
00534 {
00535   if (!p_new_arr) {
00536     throw InternalErr(__FILE__, __LINE__,
00537         "Grid::set_array(): Cannot set to null!");
00538   }
00539   // Make sure not same memory, this would be evil.
00540   if (p_new_arr == _array_var) {
00541       return;
00542    }
00543   // clean out any old array
00544   delete _array_var; _array_var = 0;
00545   // Set the new, with parent
00546   _array_var = p_new_arr;
00547   _array_var->set_parent(this);
00548 }
00549 
00576 Array*
00577 Grid::add_map(Array* p_new_map, bool add_as_copy)
00578 {
00579   if (!p_new_map) {
00580     throw InternalErr(__FILE__, __LINE__,
00581         "Grid::add_map(): cannot have p_new_map null!");
00582   }
00583 
00584   if (add_as_copy) {
00585     p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00586   }
00587 
00588   p_new_map->set_parent(this);
00589   _map_vars.push_back(p_new_map);
00590   _vars.push_back(p_new_map); // allow superclass iter to work as well.
00591 
00592   // return the one that got put into the Grid.
00593   return p_new_map;
00594 }
00595 
00608 Array*
00609 Grid::prepend_map(Array* p_new_map, bool add_copy)
00610 {
00611   if (add_copy)
00612     {
00613       p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00614     }
00615 
00616   p_new_map->set_parent(this);
00617   _map_vars.insert(_map_vars.begin(), p_new_map);
00618   _vars.insert(_vars.begin(), p_new_map); // allow superclass iter to work as well.
00619 
00620    // return the one that got put into the Grid.
00621    return p_new_map;
00622 }
00623 
00627 BaseType *
00628 Grid::array_var()
00629 {
00630     return _array_var;
00631 }
00632 
00636 Array *
00637 Grid::get_array()
00638 {
00639     Array *a = dynamic_cast<Array*>(_array_var);
00640     if (a)
00641         return a;
00642     else
00643         throw InternalErr(__FILE__, __LINE__, "bad Cast");
00644 }
00645 
00647 Grid::Map_iter
00648 Grid::map_begin()
00649 {
00650     return _map_vars.begin() ;
00651 }
00652 
00655 Grid::Map_iter
00656 Grid::map_end()
00657 {
00658     return _map_vars.end() ;
00659 }
00660 
00662 Grid::Map_riter
00663 Grid::map_rbegin()
00664 {
00665     return _map_vars.rbegin() ;
00666 }
00667 
00670 Grid::Map_riter
00671 Grid::map_rend()
00672 {
00673     return _map_vars.rend() ;
00674 }
00675 
00679 Grid::Map_iter
00680 Grid::get_map_iter(int i)
00681 {
00682     return _map_vars.begin() + i;
00683 }
00684 
00700 int
00701 Grid::components(bool constrained)
00702 {
00703     int comp;
00704 
00705     if (constrained) {
00706         comp = _array_var->send_p() ? 1 : 0;
00707 
00708         for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00709             if ((*i)->send_p()) {
00710                 comp++;
00711             }
00712         }
00713     }
00714     else {
00715         comp = 1 + _map_vars.size();
00716     }
00717 
00718     return comp;
00719 }
00720 
00721 void Grid::transfer_attributes(AttrTable *at_container)
00722 {
00723     AttrTable *at = at_container->get_attr_table(name());
00724 
00725     if (at) {
00726         at->set_is_global_attribute(false);
00727 
00728         array_var()->transfer_attributes(at);
00729 
00730         Map_iter map = map_begin();
00731         while (map != map_end()) {
00732             (*map)->transfer_attributes(at);
00733             map++;
00734         }
00735 
00736         // Trick: If an attribute that's within the container 'at' still has its
00737         // is_global_attribute property set, then it's not really a global attr
00738         // but instead an attribute that belongs to this Grid.
00739         AttrTable::Attr_iter at_p = at->attr_begin();
00740         while (at_p != at->attr_end()) {
00741             if (at->is_global_attribute(at_p)) {
00742                 if (at->get_attr_type(at_p) == Attr_container)
00743                     get_attr_table().append_container(new AttrTable(
00744                             *at->get_attr_table(at_p)), at->get_name(at_p));
00745                 else
00746                     get_attr_table().append_attr(at->get_name(at_p),
00747                             at->get_type(at_p), at->get_attr_vector(at_p));
00748             }
00749 
00750             at_p++;
00751         }
00752     }
00753 }
00754 
00755 // When projected (using whatever the current constraint provides in the way
00756 // of a projection), is the object still a Grid?
00757 
00774 bool
00775 Grid::projection_yields_grid()
00776 {
00777     // For each dimension in the Array part, check the corresponding Map
00778     // vector to make sure it is present in the projected Grid. If for each
00779     // projected dimension in the Array component, there is a matching Map
00780     // vector, then the Grid is valid.
00781     bool valid = true;
00782     Array *a = (Array *)_array_var;
00783 
00784     // Don't bother checking if the Array component is not included.
00785     if (!a->send_p())
00786         return false;
00787 
00788     // If only one part is being sent, it's clearly not a grid (it must be
00789     // the array part of the Grid that's being sent (given that the above
00790     // test passed and the array is being sent).
00791     if (components(true) == 1)
00792         return false;
00793 
00794     Array::Dim_iter d = a->dim_begin() ;
00795     Map_iter m = map_begin() ;
00796 
00797     while (valid && d != a->dim_end() && m != map_end()) {
00798         Array &map = dynamic_cast<Array&>(**m);
00799         if (a->dimension_size(d, true) && map.send_p()) {
00800             // Check the matching Map vector; the Map projection must equal
00801             // the Array dimension projection
00802             Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
00803             valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
00804                     && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
00805                     && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
00806         }
00807         else {
00808            valid = false;
00809         }
00810 
00811         d++, m++;
00812     }
00813 
00814     return valid;
00815 }
00816 
00818 void
00819 Grid::clear_constraint()
00820 {
00821     dynamic_cast<Array&>(*_array_var).clear_constraint();
00822     for (Map_iter m = map_begin(); m != map_end(); ++m)
00823         dynamic_cast<Array&>(*(*m)).clear_constraint();
00824 }
00825 
00826 #if FILE_METHODS
00827 void
00828 Grid::print_decl(FILE *out, string space, bool print_semi,
00829                  bool constraint_info, bool constrained)
00830 {
00831     if (constrained && !send_p())
00832         return;
00833 
00834     // The problem with the above is that if two Grids are projected and each
00835     // contain one variable, say a map, and it happens to have the same name
00836     // in each Grid, then without the enclosing Structures, the returned dataset
00837     // has two variables with the same name at the same lexical level. So I'm
00838     // removing the code above.
00839     if (constrained && !projection_yields_grid()) {
00840         fprintf(out, "%sStructure {\n", space.c_str()) ;
00841 
00842         _array_var->print_decl(out, space + "    ", true, constraint_info,
00843                                constrained);
00844 
00845         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00846             (*i)->print_decl(out, space + "    ", true,
00847                              constraint_info, constrained);
00848         }
00849 
00850         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00851     }
00852     else {
00853         // The number of elements in the (projected) Grid must be such that
00854         // we have a valid Grid object; send it as such.
00855         fprintf(out, "%s%s {\n", space.c_str(), type_name().c_str()) ;
00856 
00857         fprintf(out, "%s  Array:\n", space.c_str()) ;
00858         _array_var->print_decl(out, space + "    ", true, constraint_info,
00859                                constrained);
00860 
00861         fprintf(out, "%s  Maps:\n", space.c_str()) ;
00862         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00863             (*i)->print_decl(out, space + "    ", true,
00864                              constraint_info, constrained);
00865         }
00866 
00867         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00868     }
00869 
00870     if (constraint_info) {
00871         if (send_p())
00872             fprintf( out, ": Send True");
00873         else
00874             fprintf( out, ": Send False");
00875     }
00876 
00877     if (print_semi)
00878         fprintf(out, ";\n") ;
00879 
00880     return;
00881 }
00882 #endif
00883 
00884 void
00885 Grid::print_decl(ostream &out, string space, bool print_semi,
00886                  bool constraint_info, bool constrained)
00887 {
00888     if (constrained && !send_p())
00889         return;
00890 
00891     // See comment for the FILE* version of this method.
00892     if (constrained && !projection_yields_grid()) {
00893         out << space << "Structure {\n" ;
00894 
00895         _array_var->print_decl(out, space + "    ", true, constraint_info,
00896                                constrained);
00897 
00898         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00899             (*i)->print_decl(out, space + "    ", true,
00900                              constraint_info, constrained);
00901         }
00902 
00903         out << space << "} " << id2www(name()) ;
00904     }
00905     else {
00906         // The number of elements in the (projected) Grid must be such that
00907         // we have a valid Grid object; send it as such.
00908         out << space << type_name() << " {\n" ;
00909 
00910         out << space << "  Array:\n" ;
00911         _array_var->print_decl(out, space + "    ", true, constraint_info,
00912                                constrained);
00913 
00914         out << space << "  Maps:\n" ;
00915         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00916             (*i)->print_decl(out, space + "    ", true,
00917                              constraint_info, constrained);
00918         }
00919 
00920         out << space << "} " << id2www(name()) ;
00921     }
00922 
00923     if (constraint_info) {
00924         if (send_p())
00925             out << ": Send True";
00926         else
00927             out << ": Send False";
00928     }
00929 
00930     if (print_semi)
00931         out << ";\n" ;
00932 
00933     return;
00934 }
00935 
00936 #if FILE_METHODS
00937 class PrintMapField : public unary_function<BaseType *, void>
00938 {
00939     FILE *d_out;
00940     string d_space;
00941     bool d_constrained;
00942     string d_tag;
00943 public:
00944     PrintMapField(FILE *o, string s, bool c, const string &t = "Map")
00945             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
00946     {}
00947 
00948     void operator()(BaseType *btp)
00949     {
00950         Array *a = dynamic_cast<Array*>(btp);
00951         if (!a)
00952             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00953         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
00954     }
00955 };
00956 
00960 void
00961 Grid::print_xml(FILE *out, string space, bool constrained)
00962 {
00963     if (constrained && !send_p())
00964          return;
00965 
00966      if (constrained && !projection_yields_grid()) {
00967          fprintf(out, "%s<Structure", space.c_str());
00968          if (!name().empty())
00969              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00970 
00971          fprintf(out, ">\n");
00972 
00973          get_attr_table().print_xml(out, space + "    ", constrained);
00974 
00975          get_array()->print_xml(out, space + "    ", constrained);
00976 
00977          for_each(map_begin(), map_end(),
00978                   PrintMapField(out, space + "    ", constrained, "Array"));
00979 
00980          fprintf(out, "%s</Structure>\n", space.c_str());
00981      }
00982      else {
00983          // The number of elements in the (projected) Grid must be such that
00984          // we have a valid Grid object; send it as such.
00985          fprintf(out, "%s<Grid", space.c_str());
00986          if (!name().empty())
00987              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00988 
00989          fprintf(out, ">\n");
00990 
00991          get_attr_table().print_xml(out, space + "    ", constrained);
00992 
00993          get_array()->print_xml(out, space + "    ", constrained);
00994 
00995          for_each(map_begin(), map_end(),
00996                   PrintMapField(out, space + "    ", constrained));
00997 
00998          fprintf(out, "%s</Grid>\n", space.c_str());
00999      }
01000 }
01001 #endif
01002 
01003 class PrintMapFieldStrm : public unary_function<BaseType *, void>
01004 {
01005     ostream &d_out;
01006     string d_space;
01007     bool d_constrained;
01008     string d_tag;
01009 public:
01010     PrintMapFieldStrm(ostream &o, string s, bool c, const string &t = "Map")
01011             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
01012     {}
01013 
01014     void operator()(BaseType *btp)
01015     {
01016         Array *a = dynamic_cast<Array*>(btp);
01017         if (!a)
01018             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
01019         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
01020     }
01021 };
01022 
01026 void
01027 Grid::print_xml(ostream &out, string space, bool constrained)
01028 {
01029     if (constrained && !send_p())
01030         return;
01031 
01032     if (constrained && !projection_yields_grid()) {
01033         out << space << "<Structure" ;
01034         if (!name().empty())
01035             out << " name=\"" << id2xml(name()) << "\"" ;
01036 
01037         out << ">\n" ;
01038 
01039         get_attr_table().print_xml(out, space + "    ", constrained);
01040 
01041         get_array()->print_xml(out, space + "    ", constrained);
01042 
01043         for_each(map_begin(), map_end(),
01044                  PrintMapFieldStrm(out, space + "    ", constrained, "Array"));
01045 
01046         out << space << "</Structure>\n" ;
01047     }
01048     else {
01049         // The number of elements in the (projected) Grid must be such that
01050         // we have a valid Grid object; send it as such.
01051         out << space << "<Grid" ;
01052         if (!name().empty())
01053             out << " name=\"" << id2xml(name()) << "\"" ;
01054 
01055         out << ">\n" ;
01056 
01057         get_attr_table().print_xml(out, space + "    ", constrained);
01058 
01059         get_array()->print_xml(out, space + "    ", constrained);
01060 
01061         for_each(map_begin(), map_end(),
01062                  PrintMapFieldStrm(out, space + "    ", constrained));
01063 
01064         out << space << "</Grid>\n" ;
01065     }
01066 }
01067 
01068 
01069 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
01070 {
01071     XMLWriter &d_xml;
01072     bool d_constrained;
01073     string d_tag;
01074 public:
01075     PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
01076             : d_xml(x), d_constrained(c), d_tag(t)
01077     {}
01078 
01079     void operator()(BaseType *btp)
01080     {
01081         Array *a = dynamic_cast<Array*>(btp);
01082         if (!a)
01083             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
01084         a->print_xml_writer_core(d_xml, d_constrained, d_tag);
01085     }
01086 };
01087 
01088 void
01089 Grid::print_xml_writer(XMLWriter &xml, bool constrained)
01090 {
01091     if (constrained && !send_p())
01092         return;
01093 
01094     if (constrained && !projection_yields_grid()) {
01095         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
01096             throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
01097 
01098         if (!name().empty())
01099             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
01100                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01101 
01102         get_attr_table().print_xml_writer(xml);
01103 
01104         get_array()->print_xml_writer(xml, constrained);
01105 
01106         for_each(map_begin(), map_end(),
01107                  PrintGridFieldXMLWriter(xml, constrained, "Array"));
01108 
01109         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01110             throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
01111     }
01112     else {
01113         // The number of elements in the (projected) Grid must be such that
01114         // we have a valid Grid object; send it as such.
01115         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
01116             throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
01117 
01118         if (!name().empty())
01119             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
01120                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01121 
01122         get_attr_table().print_xml_writer(xml);
01123 
01124         get_array()->print_xml_writer(xml, constrained);
01125 
01126         for_each(map_begin(), map_end(),
01127                  PrintGridFieldXMLWriter(xml, constrained, "Map"));
01128 
01129         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01130             throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
01131     }
01132 }
01133 
01134 #if FILE_METHODS
01135 void
01136 Grid::print_val(FILE *out, string space, bool print_decl_p)
01137 {
01138     if (print_decl_p) {
01139         print_decl(out, space, false);
01140         fprintf(out, " = ") ;
01141     }
01142 
01143     // If we are printing a value on the client-side, projection_yields_grid
01144     // should not be called since we don't *have* a projection without a
01145     // contraint. I think that if we are here and send_p() is not true, then
01146     // the value of this function should be ignored. 4/6/2000 jhrg
01147     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
01148     if (pyg || !send_p())
01149         fprintf(out, "{  Array: ") ;
01150     else
01151         fprintf(out, "{") ;
01152     _array_var->print_val(out, "", false);
01153     if (pyg || !send_p())
01154         fprintf(out, "  Maps: ") ;
01155     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
01156          i++, (void)(i != _map_vars.end() && fprintf(out, ", "))) {
01157         (*i)->print_val(out, "", false);
01158     }
01159     fprintf(out, " }") ;
01160 
01161     if (print_decl_p)
01162         fprintf(out, ";\n") ;
01163 }
01164 #endif
01165 
01166 void
01167 Grid::print_val(ostream &out, string space, bool print_decl_p)
01168 {
01169     if (print_decl_p) {
01170         print_decl(out, space, false);
01171         out << " = " ;
01172     }
01173 
01174     // If we are printing a value on the client-side, projection_yields_grid
01175     // should not be called since we don't *have* a projection without a
01176     // Constraint. I think that if we are here and send_p() is not true, then
01177     // the value of this function should be ignored. 4/6/2000 jhrg
01178     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
01179     if (pyg || !send_p())
01180         out << "{  Array: " ;
01181     else
01182         out << "{" ;
01183     _array_var->print_val(out, "", false);
01184     if (pyg || !send_p())
01185         out << "  Maps: " ;
01186     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
01187          i++, (void)(i != _map_vars.end() && out << ", ")) {
01188         (*i)->print_val(out, "", false);
01189     }
01190     out << " }" ;
01191 
01192     if (print_decl_p)
01193         out << ";\n" ;
01194 }
01195 
01196 // Grids have ugly semantics.
01197 
01202 bool
01203 Grid::check_semantics(string &msg, bool all)
01204 {
01205     if (!BaseType::check_semantics(msg))
01206         return false;
01207 
01208     msg = "";
01209 
01210     if (!_array_var) {
01211         msg += "Null grid base array in `" + name() + "'\n";
01212         return false;
01213     }
01214 
01215     // Is it an array?
01216     if (_array_var->type() != dods_array_c) {
01217         msg += "Grid `" + name() + "'s' member `" + _array_var->name() + "' must be an array\n";
01218         return false;
01219     }
01220 
01221     Array *av = (Array *)_array_var; // past test above, must be an array
01222 
01223     // Array must be of a simple_type.
01224     if (!av->var()->is_simple_type()) {
01225         msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01226         return false;
01227     }
01228 
01229     // enough maps?
01230     if ((unsigned)_map_vars.size() != av->dimensions()) {
01231         msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
01232         msg += av->name() + "'\n";
01233         return false;
01234     }
01235 
01236     const string array_var_name = av->name();
01237     Array::Dim_iter asi = av->dim_begin() ;
01238     for (Map_iter mvi = _map_vars.begin();
01239          mvi != _map_vars.end(); mvi++, asi++) {
01240 
01241         BaseType *mv = *mvi;
01242 
01243         // check names
01244         if (array_var_name == mv->name()) {
01245             msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
01246             return false;
01247         }
01248         // check types
01249         if (mv->type() != dods_array_c) {
01250             msg += "Grid map variable  `" + mv->name() + "' is not an array\n";
01251             return false;
01252         }
01253 
01254         Array *mv_a = (Array *)mv; // downcast to (Array *)
01255 
01256         // Array must be of a simple_type.
01257         if (!mv_a->var()->is_simple_type()) {
01258             msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01259             return false;
01260         }
01261 
01262         // check shape
01263         if (mv_a->dimensions() != 1) {// maps must have one dimension
01264             msg += "Grid map variable  `" + mv_a->name() + "' must be only one dimension\n";
01265             return false;
01266         }
01267         // size of map must match corresponding array dimension
01268         Array::Dim_iter mv_asi = mv_a->dim_begin() ;
01269         int mv_a_size = mv_a->dimension_size(mv_asi) ;
01270         int av_size = av->dimension_size(asi) ;
01271         if (mv_a_size != av_size) {
01272             msg += "Grid map variable  `" + mv_a->name() + "'s' size does not match the size of array variable '";
01273             msg += _array_var->name() + "'s' cooresponding dimension\n";
01274             return false;
01275         }
01276     }
01277 
01278     if (all) {
01279         if (!_array_var->check_semantics(msg, true))
01280             return false;
01281         for (Map_iter mvi = _map_vars.begin(); mvi != _map_vars.end(); mvi++) {
01282             if (!(*mvi)->check_semantics(msg, true)) {
01283                 return false;
01284             }
01285         }
01286     }
01287 
01288     return true;
01289 }
01290 
01299 void
01300 Grid::dump(ostream &strm) const
01301 {
01302     strm << DapIndent::LMarg << "Grid::dump - ("
01303     << (void *)this << ")" << endl ;
01304     DapIndent::Indent() ;
01305     Constructor::dump(strm) ;
01306     if (_array_var) {
01307         strm << DapIndent::LMarg << "array var: " << endl ;
01308         DapIndent::Indent() ;
01309         _array_var->dump(strm) ;
01310         DapIndent::UnIndent() ;
01311     }
01312     else {
01313         strm << DapIndent::LMarg << "array var: null" << endl ;
01314     }
01315     strm << DapIndent::LMarg << "map var: " << endl ;
01316     DapIndent::Indent() ;
01317     Map_citer i = _map_vars.begin() ;
01318     Map_citer ie = _map_vars.end() ;
01319     for (; i != ie; i++) {
01320         (*i)->dump(strm) ;
01321     }
01322     DapIndent::UnIndent() ;
01323     DapIndent::UnIndent() ;
01324 }
01325 
01326 } // namespace libdap
01327