otsdaq  3.03.00
ConfigurationTree.cc
1 #include "otsdaq/ConfigurationInterface/ConfigurationTree.h"
2 
3 #include <typeinfo>
4 
5 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
6 #include "otsdaq/Macros/StringMacros.h"
7 #include "otsdaq/TableCore/TableBase.h"
8 
9 using namespace ots;
10 
11 #undef __MF_SUBJECT__
12 #define __MF_SUBJECT__ "ConfigurationTree"
13 
14 const std::string ConfigurationTree::DISCONNECTED_VALUE = "X";
15 const std::string ConfigurationTree::VALUE_TYPE_DISCONNECTED = "Disconnected";
16 const std::string ConfigurationTree::VALUE_TYPE_NODE = "Node";
17 const std::string ConfigurationTree::ROOT_NAME = "/";
18 time_t ConfigurationTree::LAST_NODE_DUMP_TIME = 0;
19 
20 //==============================================================================
22  : configMgr_(0)
23  , table_(0)
24  , groupId_("")
25  , linkParentTable_(0)
26  , linkColName_("")
27  , linkColValue_("")
28  , linkBackRow_(0)
29  , linkBackCol_(0)
30  , disconnectedTargetName_("")
31  , disconnectedLinkID_("")
32  , childLinkIndex_("")
33  , row_(0)
34  , col_(0)
35  , tableView_(0)
36 {
37  //__COUT__ << __E__;
38  //__COUT__ << "EMPTY CONSTRUCTOR ConfigManager: " << configMgr_ << " configuration: "
39  //<< table_ << __E__;
40 } // end empty constructor
41 
42 //==============================================================================
44  const TableBase* const& table)
45  : ConfigurationTree(configMgr,
46  table,
47  "" /*groupId_*/,
48  0 /*linkParentTable_*/,
49  "" /*linkColName_*/,
50  "" /*linkColValue_*/,
51  TableView::INVALID /*linkBackRow_*/,
52  TableView::INVALID /*linkBackCol_*/,
53  "" /*disconnectedTargetName_*/,
54  "" /*disconnectedLinkID_*/,
55  "" /*childLinkIndex_*/,
56  TableView::INVALID /*row_*/,
57  TableView::INVALID /*col_*/)
58 {
59  //__COUT__ << __E__;
60  //__COUT__ << "SHORT CONTRUCTOR ConfigManager: " << configMgr_ << " configuration: "
61  //<< table_ << __E__;
62 } // end short constructor
63 
64 //==============================================================================
66  const TableBase* const& table,
67  const std::string& groupId,
68  const TableBase* const& linkParentConfig,
69  const std::string& linkColName,
70  const std::string& linkColValue,
71  const unsigned int linkBackRow,
72  const unsigned int linkBackCol,
73  const std::string& disconnectedTargetName,
74  const std::string& disconnectedLinkID,
75  const std::string& childLinkIndex,
76  const unsigned int row,
77  const unsigned int col)
78  : configMgr_(configMgr)
79  , table_(table)
80  , groupId_(groupId)
81  , linkParentTable_(linkParentConfig)
82  , linkColName_(linkColName)
83  , linkColValue_(linkColValue)
84  , linkBackRow_(linkBackRow)
85  , linkBackCol_(linkBackCol)
86  , disconnectedTargetName_(disconnectedTargetName)
87  , disconnectedLinkID_(disconnectedLinkID)
88  , childLinkIndex_(childLinkIndex)
89  , row_(row)
90  , col_(col)
91  , tableView_(0)
92 {
93  if(!configMgr_)
94  {
95  __SS__ << "Invalid empty pointer given to tree!\n"
96  << "\n\tconfigMgr_=" << configMgr_ << "\n\tconfiguration_=" << table_
97  << "\n\tconfigView_=" << tableView_ << __E__;
98 
99  ss << nodeDump() << __E__;
100  __SS_THROW__;
101  }
102 
103  if(table_)
104  tableView_ = &(table_->getView());
105 
106  // verify UID column exists
107  if(tableView_ && tableView_->getColumnInfo(tableView_->getColUID()).getType() !=
109  {
110  __SS__ << "Missing UID column (must column of type "
112  << ") in config view : " << tableView_->getTableName() << __E__;
113 
114  ss << nodeDump() << __E__;
115  __SS_THROW__;
116  }
117 } // end full constructor
118 
119 //==============================================================================
122 {
123  //__COUT__ << __E__;
124 } // end destructor
125 
126 //==============================================================================
132 void ConfigurationTree::print(const unsigned int& depth, std::ostream& out) const
133 {
134  recursivePrint(*this, depth, out, "\t");
135 } // end print()
136 
137 //==============================================================================
138 void ConfigurationTree::recursivePrint(const ConfigurationTree& t,
139  unsigned int depth,
140  std::ostream& out,
141  std::string space)
142 {
143  if(t.isValueNode())
144  out << space << t.getValueName() << " :\t" << t.getValueAsString() << __E__;
145  else
146  {
147  if(t.isLinkNode())
148  {
149  out << space << t.getValueName();
150  if(t.isDisconnected())
151  {
152  out << " :\t" << t.getValueAsString() << __E__;
153  return;
154  }
155  out << " (" << (t.isGroupLinkNode() ? "Group" : "U")
156  << "ID=" << t.getValueAsString() << ") : " << __E__;
157  }
158  else
159  out << space << t.getValueAsString() << " : " << __E__;
160 
161  // if depth>=1 print all children
162  // child.print(depth-1)
163  if(depth >= 1)
164  {
165  auto C = t.getChildren();
166  if(!C.empty())
167  out << space << "{" << __E__;
168  for(auto& c : C)
169  recursivePrint(c.second, depth - 1, out, space + " ");
170  if(!C.empty())
171  out << space << "}" << __E__;
172  }
173  }
174 } // end recursivePrint()
175 
176 //==============================================================================
177 std::string ConfigurationTree::handleValidateValueForColumn(
178  const TableView* configView,
179  std::string value,
180  unsigned int col,
182 {
183  if(!configView)
184  {
185  __SS__ << "Null configView" << __E__;
186 
187  ss << nodeDump() << __E__;
188  __SS_THROW__;
189  }
190  __COUT__ << "handleValidateValueForColumn<string>" << __E__;
191  return configView->validateValueForColumn(value, col);
192 } // end std::string handleValidateValueForColumn()
193 
194 //==============================================================================
199 void ConfigurationTree::getValue(std::string& value) const
200 {
201  //__COUT__ << row_ << " " << col_ << " p: " << tableView_<< __E__;
202 
203  if(row_ != TableView::INVALID &&
204  col_ != TableView::INVALID) // this node is a value node
205  {
206  // attempt to interpret the value as a tree node path itself
207  try
208  {
209  ConfigurationTree valueAsTreeNode = getValueAsTreeNode();
210  // valueAsTreeNode.getValue<T>(value);
211  __COUT__ << "Success following path to tree node!" << __E__;
212  // value has been interpreted as a tree node value
213  // now verify result under the rules of this column
214  // if(typeid(std::string) == typeid(value))
215 
216  // Note: want to interpret table value as though it is in column of different
217  // table this allows a number to be read as a string, for example, without
218  // exceptions
219  value = tableView_->validateValueForColumn(valueAsTreeNode.getValueAsString(),
220  col_);
221 
222  __COUT__ << "Successful value!" << __E__;
223 
224  // else
225  // value = tableView_->validateValueForColumn<T>(
226  // valueAsTreeNode.getValueAsString(),col_);
227 
228  return;
229  }
230  catch(...) // tree node path interpretation failed
231  {
232  //__COUT__ << "Invalid path, just returning normal value." << __E__;
233  }
234 
235  // else normal return
236  tableView_->getValue(value, row_, col_);
237  }
238  else if(row_ == TableView::INVALID &&
239  col_ == TableView::INVALID) // this node is table node maybe with groupId
240  {
241  if(isLinkNode() && isDisconnected())
242  value = (groupId_ == "") ? getValueName() : groupId_; // a disconnected link
243  // still knows its table
244  // name or groupId
245  else
246  value = (groupId_ == "") ? table_->getTableName() : groupId_;
247  }
248  else if(row_ == TableView::INVALID)
249  {
250  __SS__ << "Malformed ConfigurationTree" << __E__;
251  __SS_THROW__;
252  }
253  else if(col_ == TableView::INVALID) // this node is uid node
254  tableView_->getValue(value, row_, tableView_->getColUID());
255  else
256  {
257  __SS__ << "Impossible." << __E__;
258  __SS_THROW__;
259  }
260 } // end getValue()
261 
262 //==============================================================================
275 std::string ConfigurationTree::getValue() const
276 {
277  std::string value;
279  return value;
280 } // end getValue()
281 //==============================================================================
294 std::string ConfigurationTree::getValueWithDefault(const std::string& defaultValue) const
295 {
296  if(isDefaultValue())
297  return defaultValue;
298  else
300 } // end getValueWithDefault()
301 
302 //==============================================================================
307 void ConfigurationTree::getValueAsBitMap(
309 {
310  __COUTS__(2) << row_ << " " << col_ << " p: " << tableView_ << __E__;
311 
312  if(row_ != TableView::INVALID &&
313  col_ != TableView::INVALID) // this node is a value node
314  {
315  std::string bitmapString;
316  tableView_->getValue(bitmapString, row_, col_);
317 
318  auto bmp = tableView_->getColumnInfo(col_).getBitMapInfo();
319 
320  __COUTV__(bitmapString);
321  if(bitmapString == TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
322  {
323  bitmap.isDefault_ = true;
324  //create empty bitmap so size is known
325  for(unsigned int r = 0; r < bmp.numOfRows_; ++r)
326  {
327  bitmap.bitmap_.push_back(std::vector<std::string>());
328  for(unsigned int c = 0; c < bmp.numOfColumns_; ++c)
329  bitmap.bitmap_[r].push_back(std::string());
330  }
331  return;
332  }
333  else
334  bitmap.isDefault_ = false;
335 
336  std::string value;
337 
338  std::map<std::string, size_t> valueMap;
339  if(bmp.mapsToStrings_)
340  {
341  std::vector<std::string> list =
342  StringMacros::getVectorFromString(bmp.mapToStrings_);
343  __COUTTV__(StringMacros::vectorToString(list));
344  for(size_t i = 0; i < list.size(); ++i)
345  valueMap.emplace(std::make_pair(list[i], i));
346  __COUTTV__(StringMacros::mapToString(valueMap));
347  }
348 
349  // extract bit map
350  {
351  bitmap.bitmap_.clear();
352  int row = -1;
353  bool openRow = false;
354  unsigned int startInt = -1;
355  for(unsigned int i = 0; i < bitmapString.length(); i++)
356  {
357  __COUTVS__(2, bitmapString[i]);
358  __COUTVS__(2, row);
359  __COUTVS__(2, openRow);
360  __COUTVS__(2, startInt);
361  __COUTVS__(2, i);
362 
363  if(!openRow) // need start of row
364  {
365  if(bitmapString[i] == '[')
366  { // open a new row
367  openRow = true;
368  ++row;
369  bitmap.bitmap_.push_back(std::vector<std::string>());
370  }
371  else if(bitmapString[i] == ']')
372  {
373  break; // ending bracket, done with string
374  }
375  else if(bitmapString[i] == ',') // end characters found not within
376  // row
377  {
378  //ignore ,'s outside of row [ ] array
379  continue;
380  }
381  }
382  else if(startInt == (unsigned int)-1) // need to find start of number
383  {
384  if(bitmapString[i] == ']') // found end of row, instead of start of
385  // number, assume row ended
386  {
387  openRow = false;
388  }
389  else if((bitmapString[i] >= '0' &&
390  bitmapString[i] <= '9') || // found start of number
391  (bmp.mapsToStrings_ && bitmapString[i] >= 'a' &&
392  bitmapString[i] <=
393  'z') || // found start of string in map-to-string mode
394  (bmp.mapsToStrings_ && bitmapString[i] >= 'A' &&
395  bitmapString[i] <= 'Z'))
396  {
397  startInt = i;
398  }
399  else if(bitmapString[i] == ',') // comma found without number
400  {
401  __SS__ << "Too many ',' characters in bit map configuration"
402  << __E__;
403 
404  ss << nodeDump() << __E__;
405  __SS_ONLY_THROW__;
406  }
407  }
408  else
409  {
410  // looking for end of number (or string map)
411 
412  if(bitmapString[i] ==
413  ']') // found end of row, assume row and number ended
414  {
415  openRow = false;
416 
417  //drop space or end quote
418  unsigned int ii = i;
419  while(ii - startInt > 2 && (bitmapString[ii - 1] == ' ' ||
420  bitmapString[ii - 1] == '\r' ||
421  bitmapString[ii - 1] == '\n' ||
422  bitmapString[ii - 1] == '\t' ||
423  bitmapString[ii - 1] == '"'))
424  --ii; //rewind to last character of string
425  __COUTVS__(2, bitmapString.substr(startInt, ii - startInt));
426  if(bmp.mapsToStrings_) //convert string to number (since this template function is assumed to handle numbers only; i.e., it is not the special strings version)
427  {
428  value =
429  valueMap.at(bitmapString.substr(startInt, ii - startInt));
430  __COUTVS__(2, value);
431  }
432  //ignore value map, and return raw string
433  bitmap.bitmap_[row].push_back(
434  bitmapString.substr(startInt, ii - startInt));
435 
436  startInt = -1;
437  }
438  else if(bitmapString[i] == ',') // comma found, assume end of number
439  {
440  //drop space or end quote
441  unsigned int ii = i;
442  while(ii - startInt > 2 && (bitmapString[ii - 1] == ' ' ||
443  bitmapString[ii - 1] == '\r' ||
444  bitmapString[ii - 1] == '\n' ||
445  bitmapString[ii - 1] == '\t' ||
446  bitmapString[ii - 1] == '"'))
447  --ii; //rewind to last character of string
448  __COUTVS__(2, bitmapString.substr(startInt, ii - startInt));
449  if(bmp.mapsToStrings_) //convert string to number (since this template function is assumed to handle numbers only; i.e., it is not the special strings version)
450  {
451  value =
452  valueMap.at(bitmapString.substr(startInt, ii - startInt));
453  __COUTVS__(2, value);
454  }
455  //ignore value map, and return raw string
456  bitmap.bitmap_[row].push_back(
457  bitmapString.substr(startInt, ii - startInt));
458 
459  startInt = -1;
460  }
461  }
462  } //ene main string parsing loop
463 
464  if(TTEST(1))
465  {
466  for(unsigned int r = 0; r < bitmap.bitmap_.size(); ++r)
467  {
468  for(unsigned int c = 0; c < bitmap.bitmap_[r].size(); ++c)
469  {
470  __COUTT__ << r << "," << c << " = " << bitmap.bitmap_[r][c]
471  << __E__;
472  }
473  __COUTT__ << "================" << __E__;
474  }
475  }
476  }
477 
478  if(bitmap.bitmap_.size() != bmp.numOfRows_ ||
479  (bmp.numOfRows_ && bitmap.bitmap_[0].size() != bmp.numOfColumns_))
480  {
481  __SS__
482  << "Illegal mismatch in number of rows and columns. Extracted data was "
483  << bitmap.bitmap_.size() << " x "
484  << (bitmap.bitmap_.size() ? bitmap.bitmap_[0].size() : 0)
485  << " and the expected size is " << bmp.numOfRows_ << " x "
486  << bmp.numOfColumns_ << __E__;
487  __SS_THROW__;
488  }
489  }
490  else
491  {
492  __SS__ << "Requesting getValue must be on a value node." << __E__;
493 
494  ss << nodeDump() << __E__;
495  __SS_THROW__;
496  }
497 } // end getValueAsBitMap()
498 
499 //==============================================================================
503 ConfigurationTree::BitMap<std::string> ConfigurationTree::getValueAsBitMap() const
504 {
506  ConfigurationTree::getValueAsBitMap(value);
507  return value;
508 } // end getValueAsBitMap()
509 
510 //==============================================================================
514 {
515  if(row_ != TableView::INVALID &&
516  col_ != TableView::INVALID) // this node is a value node
517  return tableView_->getEscapedValueAsString(row_, col_);
518 
519  __SS__ << "Can not get escaped value except from a value node!"
520  << " This node is type '" << getNodeType() << "." << __E__;
521 
522  ss << nodeDump() << __E__;
523  __SS_THROW__;
524 } // end getEscapedValue()
525 
526 //==============================================================================
528 const std::string& ConfigurationTree::getTableName(void) const
529 {
530  if(!table_)
531  {
532  __SS__ << "Can not get configuration name of node with no configuration pointer! "
533  << "Is there a broken link? " << __E__;
534  if(linkParentTable_)
535  {
536  ss << "Error occurred traversing from " << linkParentTable_->getTableName()
537  << " UID '"
538  << linkParentTable_->getView().getValueAsString(
539  linkBackRow_, linkParentTable_->getView().getColUID())
540  << "' at row " << linkBackRow_ << " col '"
541  << linkParentTable_->getView().getColumnInfo(linkBackCol_).getName()
542  << ".'" << __E__;
543 
544  ss << StringMacros::stackTrace() << __E__;
545  }
546 
547  __SS_ONLY_THROW__;
548  }
549  return table_->getTableName();
550 } // end getTableName()
551 
552 //==============================================================================
554 const std::string& ConfigurationTree::getParentTableName(void) const
555 {
556  if(linkParentTable_)
557  return linkParentTable_->getTableName();
558 
559  __SS__ << "Can not get parent table name of node with no parent table pointer! "
560  << "Was this node initialized correctly? " << __E__;
561  ss << ConfigurationTree::nodeDump(true /* forcePrintout */) << __E__;
562  __SS_ONLY_THROW__;
563 } // end getParentTableName()
564 
565 //==============================================================================
567 const std::string& ConfigurationTree::getParentRecordName(void) const
568 {
569  if(linkParentTable_ && linkBackRow_ != TableView::INVALID)
570  {
571  //return parent UID
572  return linkParentTable_->getView()
573  .getDataView()[linkBackRow_][linkParentTable_->getView().getColUID()];
574  }
575 
576  __SS__ << "Can not get parent record name of node without the parent table pointer "
577  << (linkParentTable_ ? "" : "= null ") << "and row (row = " << linkBackRow_
578  << ")! Was this node initialized correctly? " << __E__;
579  ss << ConfigurationTree::nodeDump(true /* forcePrintout */) << __E__;
580  __SS_ONLY_THROW__;
581 } // end getParentRecordName()
582 
583 //==============================================================================
585 const std::string& ConfigurationTree::getParentLinkColumnName(void) const
586 {
587  if(linkParentTable_ && linkBackRow_ != TableView::INVALID &&
588  linkBackCol_ != TableView::INVALID)
589  {
590  //return parent link column name
591  return linkParentTable_->getView().getColumnInfo(linkBackCol_).getName();
592  }
593 
594  __SS__
595  << "Can not get parent link column name of node without the parent table pointer "
596  << (linkParentTable_ ? "" : "= null ") << "and row (row = " << linkBackRow_
597  << ") and col (col = " << linkBackCol_
598  << ")! Was this node initialized correctly? " << __E__;
599  ss << ConfigurationTree::nodeDump(true /* forcePrintout */) << __E__;
600  __SS_ONLY_THROW__;
601 } // end getParentLinkColumnName()
602 
603 //==============================================================================
605 std::string ConfigurationTree::getParentLinkID(void) const
606 {
607  if(linkParentTable_ && linkBackRow_ != TableView::INVALID &&
608  linkBackCol_ != TableView::INVALID)
609  {
610  //get all info associated with the link
611  bool isGroup;
612  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/> linkPair;
613  linkParentTable_->getView().getChildLink(linkBackCol_, isGroup, linkPair);
614 
615  std::string linkId;
616  linkParentTable_->getView().getValue(
617  linkId, linkBackRow_, linkPair.second /* link id col */);
618 
619  return linkId;
620  }
621 
622  __SS__ << "Can not get parent link ID of node without the parent table pointer "
623  << (linkParentTable_ ? "" : "= null ") << "and row (row = " << linkBackRow_
624  << ") and col (col = " << linkBackCol_
625  << ")! Was this node initialized correctly? " << __E__;
626  ss << ConfigurationTree::nodeDump(true /* forcePrintout */) << __E__;
627  __SS_ONLY_THROW__;
628 } // end getParentLinkID()
629 
630 //==============================================================================
633 {
634  if(linkParentTable_ && linkBackRow_ != TableView::INVALID &&
635  linkBackCol_ != TableView::INVALID)
636  {
637  //return parent link index
638  return linkParentTable_->getView()
639  .getColumnInfo(linkBackCol_)
641  }
642 
643  __SS__ << "Can not get parent link index of node without the parent table pointer "
644  << (linkParentTable_ ? "" : "= null ") << "and row (row = " << linkBackRow_
645  << ") and col (col = " << linkBackCol_
646  << ")! Was this node initialized correctly? " << __E__;
647  ss << ConfigurationTree::nodeDump(true /* forcePrintout */) << __E__;
648  __SS_ONLY_THROW__;
649 } // end getParentLinkIndex()
650 
651 //==============================================================================
653 const unsigned int& ConfigurationTree::getNodeRow(void) const
654 {
655  if(isUIDNode() || isValueNode())
656  return row_;
657 
658  __SS__ << "Can only get row from a UID or value node!" << __E__;
659  if(linkParentTable_)
660  {
661  ss << "Error occurred traversing from " << linkParentTable_->getTableName()
662  << " UID '"
663  << linkParentTable_->getView().getValueAsString(
664  linkBackRow_, linkParentTable_->getView().getColUID())
665  << "' at row " << linkBackRow_ << " col '"
666  << linkParentTable_->getView().getColumnInfo(linkBackCol_).getName() << ".'"
667  << __E__;
668 
669  ss << StringMacros::stackTrace() << __E__;
670  }
671 
672  __SS_ONLY_THROW__;
673 
674 } // end getNodeRow()
675 
676 //==============================================================================
681 const std::string& ConfigurationTree::getFieldTableName(void) const
682 {
683  // if link node, need config name from parent
684  if(isLinkNode())
685  {
686  if(!linkParentTable_)
687  {
688  __SS__ << "Can not get configuration name of link node field with no parent "
689  "configuration pointer!"
690  << __E__;
691  ss << nodeDump() << __E__;
692  __SS_ONLY_THROW__;
693  }
694  return linkParentTable_->getTableName();
695  }
696  else
697  return getTableName();
698 } // end getFieldTableName()
699 
700 //==============================================================================
702 const std::string& ConfigurationTree::getDisconnectedTableName(void) const
703 {
704  if(isLinkNode() && isDisconnected())
705  return disconnectedTargetName_;
706 
707  __SS__ << "Can not get disconnected target name of node unless it is a disconnected "
708  "link node!"
709  << __E__;
710 
711  ss << nodeDump() << __E__;
712  __SS_ONLY_THROW__;
713 } // end getDisconnectedTableName()
714 
715 //==============================================================================
717 const std::string& ConfigurationTree::getDisconnectedLinkID(void) const
718 {
719  if(isLinkNode() && isDisconnected())
720  return disconnectedLinkID_;
721 
722  __SS__ << "Can not get disconnected target name of node unless it is a disconnected "
723  "link node!"
724  << __E__;
725 
726  ss << nodeDump() << __E__;
727  __SS_ONLY_THROW__;
728 } // end getDisconnectedLinkID()
729 
730 //==============================================================================
733 {
734  if(!tableView_)
735  {
736  __SS__ << "Can not get configuration version of node with no config view pointer!"
737  << __E__;
738 
739  ss << nodeDump() << __E__;
740  __SS_ONLY_THROW__;
741  }
742  return tableView_->getVersion();
743 } // end getTableVersion()
744 
745 //==============================================================================
748 {
749  if(!tableView_)
750  {
751  __SS__ << "Can not get configuration creation time of node with no config view "
752  "pointer!"
753  << __E__;
754 
755  ss << nodeDump() << __E__;
756  __SS_ONLY_THROW__;
757  }
758  return tableView_->getCreationTime();
759 } // end getTableCreationTime()
760 
761 //==============================================================================
764 std::set<std::string> ConfigurationTree::getSetOfGroupIDs(void) const
765 {
766  if(!isGroupIDNode())
767  {
768  __SS__ << "Can not get set of group IDs of node with value type of '"
769  << getNodeType() << ".' Node must be a GroupID node." << __E__;
770 
771  ss << nodeDump() << __E__;
772  __SS_ONLY_THROW__;
773  }
774 
775  return tableView_->getSetOfGroupIDs(col_, row_);
776 
777 } // end getSetOfGroupIDs()
778 
779 //==============================================================================
783 std::vector<std::string> ConfigurationTree::getFixedChoices(void) const
784 {
785  if(getValueType() != TableViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
786  getValueType() != TableViewColumnInfo::TYPE_BITMAP_DATA && !isLinkNode())
787  {
788  __SS__ << "Can not get fixed choices of node with value type of '"
789  << getValueType() << ".' Node must be a link or a value node with type '"
790  << TableViewColumnInfo::TYPE_BITMAP_DATA << "' or '"
791  << TableViewColumnInfo::TYPE_FIXED_CHOICE_DATA << ".'" << __E__;
792 
793  ss << nodeDump() << __E__;
794  __SS_ONLY_THROW__;
795  }
796 
797  std::vector<std::string> retVec;
798 
799  if(isLinkNode())
800  {
801  if(!linkParentTable_)
802  {
803  __SS__
804  << "Can not get fixed choices of node with no parent config view pointer!"
805  << __E__;
806 
807  ss << nodeDump() << __E__;
808  __SS_ONLY_THROW__;
809  }
810 
811  //__COUT__ << getChildLinkIndex() << __E__;
812  //__COUT__ << linkColName_ << __E__;
813 
814  // for links, col_ = -1, column c needs to change (to ChildLink column of pair)
815  // get column from parent config pointer
816 
817  const TableView* parentView = &(linkParentTable_->getView());
818  int c = parentView->findCol(linkColName_);
819 
820  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/> linkPair;
821  bool isGroupLink;
822  parentView->getChildLink(c, isGroupLink, linkPair);
823  c = linkPair.first;
824 
825  std::vector<std::string> choices = parentView->getColumnInfo(c).getDataChoices();
826  for(const auto& choice : choices)
827  retVec.push_back(choice);
828 
829  return retVec;
830  }
831 
832  if(!tableView_)
833  {
834  __SS__ << "Can not get fixed choices of node with no config view pointer!"
835  << __E__;
836 
837  ss << nodeDump() << __E__;
838  __SS_ONLY_THROW__;
839  }
840 
841  // return vector of default + data choices
842  retVec.push_back(tableView_->getColumnInfo(col_).getDefaultValue());
843  std::vector<std::string> choices = tableView_->getColumnInfo(col_).getDataChoices();
844  for(const auto& choice : choices)
845  retVec.push_back(choice);
846 
847  return retVec;
848 } // end getFixedChoices()
849 
850 //==============================================================================
853 {
854  auto commentNode = getNode(TableViewColumnInfo::COL_NAME_COMMENT);
855  std::string comment = commentNode.getValueAsString();
856  return comment != "" && comment != TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT &&
857  comment != TableViewColumnInfo::DATATYPE_COMMENT_OLD_DEFAULT &&
858  comment != commentNode.getColumnInfo().getDefaultValue();
859 } // end hasComment()
860 
861 //==============================================================================
863 const std::string& ConfigurationTree::getComment(void) const
864 {
865  return getNode(TableViewColumnInfo::COL_NAME_COMMENT).getValueAsString() == ""
866  ? TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT
867  : getNode(TableViewColumnInfo::COL_NAME_COMMENT).getValueAsString();
868 } // end getComment()
869 
870 //==============================================================================
872 const std::string& ConfigurationTree::getAuthor(void) const
873 {
874  return getNode(TableViewColumnInfo::COL_NAME_AUTHOR).getValueAsString();
875 } // end getAuthor()
876 
877 //==============================================================================
885 const std::string& ConfigurationTree::getValueAsString(bool returnLinkTableValue) const
886 {
887  //__COUTV__(col_);__COUTV__(row_);__COUTV__(table_);__COUTV__(tableView_);
888 
889  if(isLinkNode())
890  {
891  if(returnLinkTableValue)
892  return linkColValue_;
893  else if(isDisconnected())
894  return ConfigurationTree::DISCONNECTED_VALUE;
895  else if(row_ == TableView::INVALID &&
896  col_ == TableView::INVALID) // this link is groupId node
897  return (groupId_ == "") ? table_->getTableName() : groupId_;
898  else if(col_ == TableView::INVALID) // this link is uid node
899  return tableView_->getDataView()[row_][tableView_->getColUID()];
900  else
901  {
902  __SS__ << "Impossible Link." << __E__;
903 
904  ss << nodeDump() << __E__;
905  __SS_THROW__;
906  }
907  }
908  else if(row_ != TableView::INVALID &&
909  col_ != TableView::INVALID) // this node is a value node
910  return tableView_->getDataView()[row_][col_];
911  else if(row_ == TableView::INVALID &&
912  col_ == TableView::INVALID) // this node is table node maybe with groupId
913  {
914  // if root node, then no table defined
915  if(isRootNode())
916  return ConfigurationTree::ROOT_NAME;
917 
918  return (groupId_ == "") ? table_->getTableName() : groupId_;
919  }
920  else if(row_ == TableView::INVALID)
921  {
922  __SS__ << "Malformed ConfigurationTree" << __E__;
923 
924  ss << nodeDump() << __E__;
925  __SS_THROW__;
926  }
927  else if(col_ == TableView::INVALID) // this node is uid node
928  return tableView_->getDataView()[row_][tableView_->getColUID()];
929  else
930  {
931  __SS__ << "Impossible." << __E__;
932 
933  ss << nodeDump() << __E__;
934  __SS_THROW__;
935  }
936 } // end getValueAsString()
937 
938 //==============================================================================
942 const std::string& ConfigurationTree::getUIDAsString(void) const
943 {
944  if(isValueNode() || isUIDLinkNode() || isUIDNode())
945  return tableView_->getDataView()[row_][tableView_->getColUID()];
946 
947  {
948  __SS__ << "Can not get UID of node with type '" << getNodeType()
949  << ".' Node type must be '" << ConfigurationTree::NODE_TYPE_VALUE
950  << "' or '" << ConfigurationTree::NODE_TYPE_UID_LINK << ".'" << __E__;
951 
952  ss << nodeDump() << __E__;
953  __SS_ONLY_THROW__;
954  }
955 } // end getUIDAsString()
956 
957 //==============================================================================
960 const std::string& ConfigurationTree::getValueDataType(void) const
961 {
962  if(isValueNode())
963  return tableView_->getColumnInfo(col_).getDataType();
964  else // must be std::string
965  return TableViewColumnInfo::DATATYPE_STRING;
966 } // end getValueDataType()
967 
968 //==============================================================================
972 {
973  if(!isValueNode())
974  return false;
975 
976  if(getValueDataType() == TableViewColumnInfo::DATATYPE_STRING)
977  {
978  if(getValueType() == TableViewColumnInfo::TYPE_ON_OFF ||
979  getValueType() == TableViewColumnInfo::TYPE_TRUE_FALSE ||
980  getValueType() == TableViewColumnInfo::TYPE_YES_NO)
981  return getValueAsString() ==
982  TableViewColumnInfo::DATATYPE_BOOL_DEFAULT; // default to OFF, NO,
983  // FALSE
984  else if(getValueType() == TableViewColumnInfo::TYPE_COMMENT)
985  return getValueAsString() == TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT ||
986  getValueAsString() ==
987  ""; // in case people delete default comment, allow blank also
988  else
989  return getValueAsString() == TableViewColumnInfo::DATATYPE_STRING_DEFAULT;
990  }
992  return getValueAsString() == TableViewColumnInfo::DATATYPE_NUMBER_DEFAULT;
993  else if(getValueDataType() == TableViewColumnInfo::DATATYPE_TIME)
994  return getValueAsString() == TableViewColumnInfo::DATATYPE_TIME_DEFAULT;
995  else
996  return false;
997 } // end isDefaultValue()
998 
999 //==============================================================================
1003 const std::string& ConfigurationTree::getDefaultValue(void) const
1004 {
1005  if(!isValueNode())
1006  {
1007  __SS__ << "Can only get default value from a value node! "
1008  << "The node type is " << getNodeType() << __E__;
1009 
1010  ss << nodeDump() << __E__;
1011  __SS_THROW__;
1012  }
1013 
1014  if(getValueDataType() == TableViewColumnInfo::DATATYPE_STRING)
1015  {
1016  if(getValueType() == TableViewColumnInfo::TYPE_ON_OFF ||
1017  getValueType() == TableViewColumnInfo::TYPE_TRUE_FALSE ||
1018  getValueType() == TableViewColumnInfo::TYPE_YES_NO)
1019  return TableViewColumnInfo::DATATYPE_BOOL_DEFAULT; // default to OFF, NO,
1020  // FALSE
1021  else if(getValueType() == TableViewColumnInfo::TYPE_COMMENT)
1022  return TableViewColumnInfo::
1023  DATATYPE_COMMENT_DEFAULT; // in case people delete default comment, allow blank also
1024  else
1025  return TableViewColumnInfo::DATATYPE_STRING_DEFAULT;
1026  }
1028  return TableViewColumnInfo::DATATYPE_NUMBER_DEFAULT;
1029  else if(getValueDataType() == TableViewColumnInfo::DATATYPE_TIME)
1030  return TableViewColumnInfo::DATATYPE_TIME_DEFAULT;
1031 
1032  {
1033  __SS__ << "Can only get default value from a value node! "
1034  << "The node type is " << getNodeType() << __E__;
1035 
1036  ss << nodeDump() << __E__;
1037  __SS_THROW__;
1038  }
1039 } // end isDefaultValue()
1040 
1041 //==============================================================================
1044 const std::string& ConfigurationTree::getValueType(void) const
1045 {
1046  if(isValueNode())
1047  return tableView_->getColumnInfo(col_).getType();
1048  else if(isLinkNode() && isDisconnected())
1049  return ConfigurationTree::VALUE_TYPE_DISCONNECTED;
1050  else // just call all non-value nodes data
1051  return ConfigurationTree::VALUE_TYPE_NODE;
1052 } // end getValueType()
1053 
1054 //==============================================================================
1058 {
1059  if(isValueNode())
1060  return tableView_->getColumnInfo(col_);
1061  else
1062  {
1063  __SS__ << "Can only get column info from a value node! "
1064  << "The node type is " << getNodeType() << __E__;
1065 
1066  ss << nodeDump() << __E__;
1067  __SS_THROW__;
1068  }
1069 } // end getColumnInfo()
1070 
1071 //==============================================================================
1073 const unsigned int& ConfigurationTree::getRow(void) const { return row_; }
1074 
1075 //==============================================================================
1077 const unsigned int& ConfigurationTree::getColumn(void) const { return col_; }
1078 
1079 //==============================================================================
1082 const unsigned int& ConfigurationTree::getFieldRow(void) const
1083 {
1084  if(isLinkNode())
1085  {
1086  // for links, need to use parent info to determine
1087  return linkBackRow_;
1088  }
1089  else
1090  return row_;
1091 } // end getFieldRow()
1092 
1093 //==============================================================================
1096 const unsigned int& ConfigurationTree::getFieldColumn(void) const
1097 {
1098  if(isLinkNode())
1099  {
1100  // for links, need to use parent info to determine
1101  return linkBackCol_;
1102  }
1103  else
1104  return col_;
1105 } // end getFieldColumn()
1106 
1107 //==============================================================================
1109 const std::string& ConfigurationTree::getChildLinkIndex(void) const
1110 {
1111  if(!isLinkNode())
1112  {
1113  __SS__ << "Can only get link ID from a link! "
1114  << "The node type is " << getNodeType() << __E__;
1115 
1116  ss << nodeDump() << __E__;
1117  __SS_THROW__;
1118  }
1119  return childLinkIndex_;
1120 } // end getChildLinkIndex()
1121 
1122 //==============================================================================
1125 const std::string& ConfigurationTree::getValueName(void) const
1126 {
1127  if(isValueNode())
1128  return tableView_->getColumnInfo(col_).getName();
1129  else if(isLinkNode())
1130  return linkColName_;
1131  else
1132  {
1133  __SS__ << "Can only get value name of a value node!" << __E__;
1134 
1135  ss << nodeDump() << __E__;
1136  __SS_THROW__;
1137  }
1138 } // end getValueName()
1139 
1140 //==============================================================================
1143 ConfigurationTree ConfigurationTree::recurse(const ConfigurationTree& tree,
1144  const std::string& childPath,
1145  bool doNotThrowOnBrokenUIDLinks,
1146  const std::string& originalNodeString)
1147 {
1148  __COUTS__(50) << tree.row_ << " " << tree.col_ << __E__;
1149  __COUTS__(51) << "childPath=" << childPath << " " << childPath.length() << __E__;
1150  if(childPath.length() <= 1) // only "/" or ""
1151  return tree;
1152  return tree.recursiveGetNode(
1153  childPath, doNotThrowOnBrokenUIDLinks, originalNodeString);
1154 } // end recurse()
1155 
1156 //==============================================================================
1166 ConfigurationTree ConfigurationTree::getNode(const std::string& nodeString,
1167  bool doNotThrowOnBrokenUIDLinks) const
1168 {
1169  // __COUT__ << "nodeString=" << nodeString << " len=" << nodeString.length() << __E__;
1170  return recursiveGetNode(
1171  nodeString, doNotThrowOnBrokenUIDLinks, "" /*originalNodeString*/);
1172 } // end getNode() connected to recursiveGetNode()
1173 ConfigurationTree ConfigurationTree::recursiveGetNode(
1174  const std::string& nodeString,
1175  bool doNotThrowOnBrokenUIDLinks,
1176  const std::string& originalNodeString) const
1177 {
1178  __COUTS__(51) << "nodeString=" << nodeString << " len=" << nodeString.length()
1179  << __E__;
1180  __COUTS__(52) << "doNotThrowOnBrokenUIDLinks=" << doNotThrowOnBrokenUIDLinks << __E__;
1181 
1182  // get nodeName (in case of / syntax)
1183  if(nodeString.length() < 1)
1184  {
1185  __SS__ << "Invalid empty node name! Looking for child node '" << nodeString
1186  << "' from node '" << getValue() << "'..." << __E__;
1187 
1188  ss << nodeDump() << __E__;
1189  __SS_THROW__;
1190  }
1191 
1192  // ignore multiple starting slashes
1193  size_t startingIndex = 0;
1194  while(startingIndex < nodeString.length() && nodeString[startingIndex] == '/')
1195  ++startingIndex;
1196  size_t endingIndex = nodeString.find('/', startingIndex);
1197  if(endingIndex == std::string::npos)
1198  endingIndex = nodeString.length();
1199 
1200  std::string nodeName = nodeString.substr(startingIndex, endingIndex - startingIndex);
1201  __COUTS__(51) << "nodeName=" << nodeName << " len=" << nodeName.length() << __E__;
1202 
1203  ++endingIndex;
1204  std::string childPath =
1205  (endingIndex >= nodeString.length() ? "" : nodeString.substr(endingIndex));
1206  __COUTS__(51) << "childPath=" << childPath << " len=" << childPath.length()
1207  << " endingIndex=" << endingIndex
1208  << " nodeString.length()=" << nodeString.length() << __E__;
1209 
1210  // if this tree is beginning at a configuration.. then go to uid, and vice versa
1211 
1212  try
1213  {
1214  __COUTS__(50) << row_ << " " << col_ << " " << groupId_ << " " << tableView_
1215  << __E__;
1216  if(isRootNode())
1217  {
1218  // root node
1219  // so return table node
1220  return recurse(configMgr_->getNode(nodeName),
1221  childPath,
1222  doNotThrowOnBrokenUIDLinks,
1223  originalNodeString);
1224  }
1225  else if(row_ == TableView::INVALID && col_ == TableView::INVALID)
1226  {
1227  // table node
1228 
1229  if(!tableView_)
1230  {
1231  __SS__ << "Missing configView pointer! Likely attempting to access a "
1232  "child node through a disconnected link node."
1233  << __E__;
1234 
1235  ss << nodeDump() << __E__;
1236  __SS_THROW__;
1237  }
1238 
1239  // this node is table node, so return uid node considering groupid
1240  return recurse(
1242  configMgr_,
1243  table_,
1244  "", // no new groupId string, not a link
1245  0 /*linkParentTable_*/,
1246  "", // link node name, not a link
1247  "", // link node value, not a link
1248  TableView::INVALID /*linkBackRow_*/,
1249  TableView::INVALID /*linkBackCol_*/,
1250  "", // ignored disconnected target name, not a link
1251  "", // ignored disconnected link id, not a link
1252  "",
1253  // if this node is group table node, consider that when getting rows
1254  (groupId_ == "")
1255  ? tableView_->findRow(tableView_->getColUID(), nodeName)
1256  : tableView_->findRowInGroup(tableView_->getColUID(),
1257  nodeName,
1258  groupId_,
1259  childLinkIndex_)),
1260  childPath,
1261  doNotThrowOnBrokenUIDLinks,
1262  originalNodeString);
1263  }
1264  else if(row_ == TableView::INVALID)
1265  {
1266  __SS__ << "Malformed ConfigurationTree" << __E__;
1267 
1268  ss << nodeDump() << __E__;
1269  __SS_THROW__;
1270  }
1271  else if(col_ == TableView::INVALID)
1272  {
1273  // this node is uid node, so return link, group link, disconnected, or value
1274  // node
1275 
1276  __COUTS__(51) << "nodeName=" << nodeName << " " << nodeName.length() << __E__;
1277 
1278  // if the value is a unique link ..
1279  // return a uid node!
1280  // if the value is a group link
1281  // return a table node with group string
1282  // else.. return value node
1283 
1284  if(!tableView_)
1285  {
1286  __SS__ << "Missing configView pointer! Likely attempting to access a "
1287  "child node through a disconnected link node."
1288  << __E__;
1289 
1290  ss << nodeDump() << __E__;
1291  __SS_THROW__;
1292  }
1293 
1294  unsigned int c = tableView_->findCol(nodeName);
1295  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/> linkPair;
1296  bool isGroupLink, isLink;
1297  if((isLink = tableView_->getChildLink(c, isGroupLink, linkPair)) &&
1298  !isGroupLink)
1299  {
1300  __COUTS__(50) << "nodeName=" << nodeName << " " << nodeName.length()
1301  << __E__;
1302  //is a unique link, return uid node in new configuration
1303  // need new configuration pointer
1304  // and row of linkUID in new configuration
1305 
1306  const TableBase* childConfig;
1307  try
1308  {
1309  childConfig = configMgr_->getTableByName(
1310  tableView_->getDataView()[row_][linkPair.first]);
1311  childConfig->getView(); // get view as a test for an active view
1312 
1313  if(doNotThrowOnBrokenUIDLinks) // try a test of getting row
1314  {
1315  childConfig->getView().findRow(
1316  childConfig->getView().getColUID(),
1317  tableView_->getDataView()[row_][linkPair.second]);
1318  }
1319  }
1320  catch(...)
1321  {
1322  __COUTS__(50)
1323  << "Found disconnected node! (" << nodeName << ":"
1324  << tableView_->getDataView()[row_][linkPair.first] << ")"
1325  << " at entry with UID "
1326  << tableView_->getDataView()[row_][tableView_->getColUID()]
1327  << __E__;
1328  //do not recurse further
1329  return ConfigurationTree(
1330  configMgr_,
1331  0,
1332  "",
1333  table_, // linkParentTable_
1334  nodeName,
1335  tableView_->getDataView()[row_][c], // this the link node field
1336  // associated value (matches
1337  // targeted column)
1338  row_ /*linkBackRow_*/,
1339  c /*linkBackCol_*/,
1340  tableView_->getDataView()[row_][linkPair.first], // give
1341  // disconnected
1342  // target name
1343  tableView_->getDataView()[row_][linkPair.second], // give
1344  // disconnected
1345  // link ID
1346  tableView_->getColumnInfo(c).getChildLinkIndex());
1347  }
1348 
1349  return recurse(
1350  ConfigurationTree( // this is a link node
1351  configMgr_,
1352  childConfig,
1353  "", // no new groupId string
1354  table_, // linkParentTable_
1355  nodeName, // this is a link node
1356  tableView_->getDataView()[row_][c], // this the link node field
1357  // associated value (matches
1358  // targeted column)
1359  row_ /*linkBackRow_*/,
1360  c /*linkBackCol_*/,
1361  "", // ignore since is connected
1362  "", // ignore since is connected
1363  tableView_->getColumnInfo(c).getChildLinkIndex(),
1364  childConfig->getView().findRow(
1365  childConfig->getView().getColUID(),
1366  tableView_->getDataView()[row_][linkPair.second])),
1367  childPath,
1368  doNotThrowOnBrokenUIDLinks,
1369  originalNodeString);
1370  }
1371  else if(isLink)
1372  {
1373  __COUTS__(50) << "nodeName=" << nodeName << " " << nodeName.length()
1374  << __E__;
1375  // is a group link, return new configuration with group string
1376  // need new configuration pointer
1377  // and group string
1378 
1379  const TableBase* childConfig;
1380  try
1381  {
1382  childConfig = configMgr_->getTableByName(
1383  tableView_->getDataView()[row_][linkPair.first]);
1384  childConfig->getView(); // get view as a test for an active view
1385  }
1386  catch(...)
1387  {
1388  if(tableView_->getDataView()[row_][linkPair.first] !=
1389  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
1390  __COUT_WARN__
1391  << "Found disconnected node! Failed link target "
1392  "from nodeName="
1393  << nodeName << " to table:id="
1394  << tableView_->getDataView()[row_][linkPair.first] << ":"
1395  << tableView_->getDataView()[row_][linkPair.second] << __E__;
1396 
1397  // do not recurse further
1398  return ConfigurationTree(
1399  configMgr_,
1400  0,
1401  tableView_->getDataView()[row_][linkPair.second], // groupID
1402  table_, // linkParentTable_
1403  nodeName,
1404  tableView_->getDataView()[row_][c], // this the link node field
1405  // associated value (matches
1406  // targeted column)
1407  row_ /*linkBackRow_*/,
1408  c /*linkBackCol_*/,
1409  tableView_->getDataView()[row_][linkPair.first], // give
1410  // disconnected
1411  // target name
1412  tableView_->getDataView()[row_][linkPair.second], // give
1413  // disconnected
1414  // target name
1415  tableView_->getColumnInfo(c).getChildLinkIndex());
1416  }
1417 
1418  return recurse(
1419  ConfigurationTree( // this is a link node
1420  configMgr_,
1421  childConfig,
1422  tableView_
1423  ->getDataView()[row_][linkPair.second], // groupId string
1424  table_, // linkParentTable_
1425  nodeName, // this is a link node
1426  tableView_->getDataView()[row_][c], // this the link node field
1427  // associated value (matches
1428  // targeted column)
1429  row_ /*linkBackRow_*/,
1430  c /*linkBackCol_*/,
1431  "", // ignore since is connected
1432  "", // ignore since is connected
1433  tableView_->getColumnInfo(c).getChildLinkIndex()),
1434  childPath,
1435  doNotThrowOnBrokenUIDLinks,
1436  originalNodeString);
1437  }
1438  else
1439  {
1440  __COUTS__(50) << "nodeName=" << nodeName << " " << nodeName.length()
1441  << __E__;
1442  //return value node
1443  return ConfigurationTree(configMgr_,
1444  table_,
1445  "",
1446  0 /*linkParentTable_*/,
1447  "",
1448  "",
1449  TableView::INVALID /*linkBackRow_*/,
1450  TableView::INVALID /*linkBackCol_*/,
1451  "",
1452  "" /*disconnectedLinkID*/,
1453  "",
1454  row_,
1455  c);
1456  }
1457  }
1458  }
1459  catch(std::runtime_error& e)
1460  {
1461  __SS__ << "\n\nError occurred descending from node '" << getValue()
1462  << "' in table '" << getTableName() << "' looking for child '" << nodeName
1463  << "'\n\n"
1464  << __E__;
1465  ss << "The original node search string was '" << originalNodeString << ".'"
1466  << __E__;
1467  ss << "--- Additional error detail: \n\n" << e.what() << __E__;
1468 
1469  ss << nodeDump() << __E__;
1470  __SS_ONLY_THROW__;
1471  }
1472  catch(...)
1473  {
1474  __SS__ << "\n\nError occurred descending from node '" << getValue()
1475  << "' in table '" << getTableName() << "' looking for child '" << nodeName
1476  << "'\n\n"
1477  << __E__;
1478  ss << "The original node search string was '" << originalNodeString << ".'"
1479  << __E__;
1480  try
1481  {
1482  throw;
1483  } //one more try to printout extra info
1484  catch(const std::exception& e)
1485  {
1486  ss << "Exception message: " << e.what();
1487  }
1488  catch(...)
1489  {
1490  }
1491  ss << nodeDump() << __E__;
1492  __SS_ONLY_THROW__;
1493  }
1494 
1495  // this node is value node, so has no node to choose from
1496  __SS__
1497  << "\n\nError occurred descending from node '" << getValue() << "' in table '"
1498  << getTableName() << "' looking for child '" << nodeName << "'\n\n"
1499  << "Invalid depth! getNode() called from a value point in the Configuration Tree."
1500  << __E__;
1501  ss << "The original node search string was '" << originalNodeString << ".'" << __E__;
1502 
1503  ss << nodeDump() << __E__;
1504  __SS_ONLY_THROW__; // this node is value node, cant go any deeper!
1505 } // end recursiveGetNode()
1506 
1507 //==============================================================================
1509 std::map<std::string, ConfigurationTree> ConfigurationTree::getNodes(
1510  const std::string& nodeString) const
1511 {
1512  if(nodeString.length() < 1)
1513  {
1514  return getChildrenMap();
1515  }
1516 
1517  return getNode(nodeString).getChildrenMap();
1518 } //end getNodes()
1519 
1520 //==============================================================================
1523 std::string ConfigurationTree::nodeDump(bool forcePrintout) const
1524 {
1525  //block cascading node dumps for a couple seconds
1526  // so that user can see the lowest level failure more easily
1527  if(!forcePrintout && time(0) - ConfigurationTree::LAST_NODE_DUMP_TIME < 3)
1528  {
1529  __COUTS__(20) << "Blocking cascading node dumps... "
1530  "ConfigurationTree::LAST_NODE_DUMP_TIME = "
1531  << ConfigurationTree::LAST_NODE_DUMP_TIME << __E__;
1532  return "";
1533  }
1534  ConfigurationTree::LAST_NODE_DUMP_TIME = time(0);
1535 
1536  __SS__ << __E__ << __E__;
1537 
1538  ss << "Row=" << (int)row_ << ", Col=" << (int)col_ << ", TablePointer=" << table_
1539  << __E__;
1540 
1541  // stack trace can seg fault on demangle call!... ?
1542  try
1543  {
1544  ss << "\n\n" << StringMacros::stackTrace() << __E__ << __E__;
1545  }
1546  catch(...)
1547  {
1548  } // ignore errors
1549 
1550  ss << "ConfigurationTree::nodeDump() start"
1551  "=====================================\nConfigurationTree::nodeDump():"
1552  << __E__;
1553 
1554  // try each level of debug.. and ignore errors
1555  try
1556  {
1557  ss << "\t"
1558  << "Node dump initiated from node '" << getValueAsString() << "'..." << __E__;
1559  }
1560  catch(...)
1561  {
1562  } // ignore errors
1563  try
1564  {
1565  ss << "\t"
1566  << "Node dump initiated from node '" << getValue() << "' in table '"
1567  << getTableName() << ".'" << __E__;
1568  }
1569  catch(...)
1570  {
1571  } // ignore errors
1572  ss << __E__; //add newline in case of exceptions mid-stringstream
1573 
1574  try
1575  {
1576  //try to avoid recursive throwing of getChildrenNames() until death spiral
1577  if(isTableNode() || isGroupLinkNode())
1578  {
1579  auto children = getChildrenNames();
1580  ss << "\t"
1581  << "Here is the list of possible children (count = " << children.size()
1582  << "):" << __E__;
1583  for(auto& child : children)
1584  ss << "\t\t" << child << __E__;
1585  if(tableView_)
1586  {
1587  ss << "\n\nHere is the culprit table printout:\n\n";
1588  tableView_->print(ss);
1589  }
1590  }
1591 
1592  if(isLinkNode() && isDisconnected())
1593  {
1594  ss << "Is link node." << __E__;
1595  ss << "disconnectedTargetName_ = " << disconnectedTargetName_
1596  << ", disconnectedLinkID_ = " << disconnectedLinkID_ << __E__;
1597 
1598  auto tables = getConfigurationManager()->getActiveVersions();
1599  ss << "\n\t"
1600  << "Here is the list of active tables:" << __E__;
1601  for(auto& table : tables)
1602  ss << "\t\t" << table.first << __E__;
1603  }
1604  }
1605  catch(...)
1606  {
1607  } // ignore errors trying to show children
1608 
1609  ss << "\n\nConfigurationTree::nodeDump() end ====================================="
1610  << __E__;
1611 
1612  return ss.str();
1613 } // end nodeDump()
1614 
1615 //==============================================================================
1616 ConfigurationTree ConfigurationTree::getBackNode(std::string nodeName,
1617  unsigned int backSteps) const
1618 {
1619  for(unsigned int i = 0; i < backSteps; i++)
1620  nodeName = nodeName.substr(0, nodeName.find_last_of('/'));
1621 
1622  return getNode(nodeName);
1623 } // end getBackNode()
1624 
1625 //==============================================================================
1626 ConfigurationTree ConfigurationTree::getForwardNode(std::string nodeName,
1627  unsigned int forwardSteps) const
1628 {
1629  unsigned int s = 0;
1630 
1631  // skip all leading /'s
1632  while(s < nodeName.length() && nodeName[s] == '/')
1633  ++s;
1634 
1635  for(unsigned int i = 0; i < forwardSteps; i++)
1636  s = nodeName.find('/', s) + 1;
1637 
1638  return getNode(nodeName.substr(0, s));
1639 } // end getForwardNode()
1640 
1641 //==============================================================================
1645 {
1646  return (row_ != TableView::INVALID && col_ != TableView::INVALID);
1647 } // end isValueNode()
1648 
1649 //==============================================================================
1653 {
1654  return isValueNode() && tableView_->getColumnInfo(col_).isBoolType();
1655 } // end isValueBoolType()
1656 
1657 //==============================================================================
1661 {
1662  return isValueNode() && tableView_->getColumnInfo(col_).isNumberDataType();
1663 } // end isValueBoolType()
1664 
1665 //==============================================================================
1671 {
1672  if(!isLinkNode())
1673  {
1674  __SS__ << "\n\nError occurred testing link connection at node with value '"
1675  << getValue() << "' in table '" << getTableName() << "'\n\n"
1676  << __E__;
1677  ss << "This is not a Link node! It is node type '" << getNodeType()
1678  << ".' Only a Link node can be disconnected." << __E__;
1679 
1680  ss << nodeDump() << __E__;
1681  __SS_ONLY_THROW__;
1682  }
1683 
1684  return !table_ || !tableView_;
1685 } // end isDisconnected()
1686 
1687 //==============================================================================
1690 bool ConfigurationTree::isLinkNode(void) const { return linkColName_ != ""; }
1691 
1692 //==============================================================================
1695 const std::string ConfigurationTree::NODE_TYPE_GROUP_TABLE = "GroupTableNode";
1696 const std::string ConfigurationTree::NODE_TYPE_TABLE = "TableNode";
1697 const std::string ConfigurationTree::NODE_TYPE_GROUP_LINK = "GroupLinkNode";
1698 const std::string ConfigurationTree::NODE_TYPE_UID_LINK = "UIDLinkNode";
1699 const std::string ConfigurationTree::NODE_TYPE_VALUE = "ValueNode";
1700 const std::string ConfigurationTree::NODE_TYPE_UID = "UIDNode";
1701 const std::string ConfigurationTree::NODE_TYPE_ROOT = "RootNode";
1702 
1703 std::string ConfigurationTree::getNodeType(void) const
1704 {
1705  if(isRootNode())
1706  return ConfigurationTree::NODE_TYPE_ROOT;
1707  if(isTableNode() && groupId_ != "")
1709  if(isTableNode())
1710  return ConfigurationTree::NODE_TYPE_TABLE;
1711  if(isGroupLinkNode())
1712  return ConfigurationTree::NODE_TYPE_GROUP_LINK;
1713  if(isLinkNode())
1714  return ConfigurationTree::NODE_TYPE_UID_LINK;
1715  if(isValueNode())
1716  return ConfigurationTree::NODE_TYPE_VALUE;
1717  return ConfigurationTree::NODE_TYPE_UID;
1718 } // end getNodeType()
1719 
1720 //==============================================================================
1724 {
1725  return (isLinkNode() && groupId_ != "");
1726 }
1727 
1728 //==============================================================================
1732 {
1733  return (isLinkNode() && groupId_ == "");
1734 } // end isUIDLinkNode()
1735 
1736 //==============================================================================
1740 {
1741  return (isValueNode() && tableView_->getColumnInfo(col_).isGroupID());
1742 } // end isGroupIDNode()
1743 
1744 //==============================================================================
1748 {
1749  return (row_ != TableView::INVALID && col_ == TableView::INVALID);
1750 }
1751 
1752 //==============================================================================
1768 std::vector<ConfigurationTree::RecordField> ConfigurationTree::getCommonFields(
1769  const std::vector<std::string /*uid*/>& recordList,
1770  const std::vector<std::string /*relative-path*/>& fieldAcceptList,
1771  const std::vector<std::string /*relative-path*/>& fieldRejectList,
1772  unsigned int depth,
1773  bool autoSelectFilterFields) const
1774 {
1775  // enforce that starting point is a table node
1776  if(!isRootNode() && !isTableNode())
1777  {
1778  __SS__ << "Can only get getCommonFields from a root or table node! "
1779  << "The node type is " << getNodeType() << __E__;
1780 
1781  ss << nodeDump() << __E__;
1782  __SS_THROW__;
1783  }
1784 
1785  std::vector<ConfigurationTree::RecordField> fieldCandidateList;
1786  std::vector<int> fieldCount; //-1 := guaranteed, else count must match num of records
1787 
1788  --depth; // decrement for recursion
1789 
1790  // for each record in <record list>
1791  // loop through all record's children
1792  // if isValueNode (value nodes are possible field candidates!)
1793  // if first uid record
1794  // add field to <field candidates list> if in <field filter list>
1795  // mark <field count> as guaranteed -1 (all these fields must be common
1796  // for UIDs in same table)
1797  // else not first uid record, do not need to check, must be same as first
1798  // record! else if depth > 0 and UID-Link Node recursively (call
1799  // recursiveGetCommonFields())
1800  // =====================
1801  // Start recursiveGetCommonFields()
1802  // --depth;
1803  // loop through all children
1804  // if isValueNode (value nodes are possible field candidates!)
1805  // if first uid record
1806  // add field to <field candidates list> if in <field
1807  // filter list> initial mark <field count> as 1
1808  // else
1809  // if field is in <field candidates list>,
1810  // increment <field count> for field candidate
1811  // else if field is not in list, ignore field
1812  // else if depth > 0 and is UID-Link
1813  // if Link Table/UID pair is not found in <field candidates
1814  // list> (avoid endless loops through tree)
1815  // recursiveGetCommonFields()
1816  // =====================
1817  //
1818  //
1819  // loop through all field candidates
1820  // remove those with <field count> != num of records
1821  //
1822  //
1823  // return result
1824 
1825  bool found; // used in loops
1826  // auto tableName = isRootNode()?"/":getTableName(); //all records will share this
1827  // table name
1828 
1829  // if no records, just return table fields
1830  if(!recordList.size() && tableView_)
1831  {
1832  const std::vector<TableViewColumnInfo>& colInfo = tableView_->getColumnsInfo();
1833 
1834  for(unsigned int col = 0; col < colInfo.size(); ++col)
1835  {
1836  __COUTS__(11) << "Considering field " << colInfo[col].getName() << __E__;
1837 
1838  // check field accept filter list
1839  found = fieldAcceptList.size() ? false : true; // accept if no filter
1840  // list
1841  for(const auto& fieldFilter : fieldAcceptList)
1842  if(StringMacros::wildCardMatch(fieldFilter, colInfo[col].getName()))
1843  {
1844  found = true;
1845  break;
1846  }
1847 
1848  if(found)
1849  {
1850  // check field reject filter list
1851 
1852  found = true; // accept if no filter list
1853  for(const auto& fieldFilter : fieldRejectList)
1854  if(StringMacros::wildCardMatch(fieldFilter, colInfo[col].getName()))
1855  {
1856  found = false; // reject if match
1857  break;
1858  }
1859  }
1860 
1861  // if found, new field (since this is first record)
1862  if(found)
1863  {
1864  __COUTS__(11) << "FOUND field " << colInfo[col].getName() << __E__;
1865 
1866  if(colInfo[col].isChildLink())
1867  {
1868  __COUTS__(11)
1869  << "isGroupLinkNode " << colInfo[col].getName() << __E__;
1870 
1871  // must get column info differently for group link column
1872 
1873  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>
1874  linkPair;
1875  bool isGroupLink;
1876  tableView_->getChildLink(col, isGroupLink, linkPair);
1877 
1878  // add both link columns
1879 
1880  fieldCandidateList.push_back(ConfigurationTree::RecordField(
1881  table_->getTableName(),
1882  "", // uid
1883  tableView_->getColumnInfo(linkPair.first).getName(),
1884  "", // relative path, not including columnName_
1885  &tableView_->getColumnInfo(linkPair.first)));
1886  fieldCount.push_back(-1); // mark guaranteed field
1887 
1888  fieldCandidateList.push_back(ConfigurationTree::RecordField(
1889  table_->getTableName(),
1890  "", // uid
1891  tableView_->getColumnInfo(linkPair.second).getName(),
1892  "", // relative path, not including columnName_
1893  &tableView_->getColumnInfo(linkPair.second)));
1894  fieldCount.push_back(-1); // mark guaranteed field
1895  }
1896  else // value node
1897  {
1898  fieldCandidateList.push_back(ConfigurationTree::RecordField(
1899  table_->getTableName(),
1900  "", // uid
1901  colInfo[col].getName(),
1902  "", // relative path, not including columnName_
1903  &colInfo[col]));
1904  fieldCount.push_back(1); // init count to 1
1905  }
1906  }
1907  } // end table column loop
1908  } // end no record handling
1909 
1910  for(unsigned int i = 0; i < recordList.size(); ++i)
1911  {
1912  __COUTS__(11) << "Checking " << recordList[i] << __E__;
1913  ConfigurationTree node = getNode(recordList[i]);
1914 
1915  node.recursiveGetCommonFields(fieldCandidateList,
1916  fieldCount,
1917  fieldAcceptList,
1918  fieldRejectList,
1919  depth,
1920  "", // relativePathBase
1921  !i // continue inFirstRecord (or not) depth search
1922  );
1923 
1924  } // end record loop
1925 
1926  __COUT__ << "======================= check for count = " << (int)recordList.size()
1927  << __E__;
1928 
1929  // loop through all field candidates
1930  // remove those with <field count> != num of records
1931  for(unsigned int i = 0; i < fieldCandidateList.size(); ++i)
1932  {
1933  __COUTS__(11) << "Checking " << fieldCandidateList[i].relativePath_
1934  << fieldCandidateList[i].columnName_ << " = " << fieldCount[i]
1935  << __E__;
1936  if(recordList.size() != 0 && fieldCount[i] != -1 &&
1937  fieldCount[i] != (int)recordList.size())
1938  {
1939  __COUTS__(11) << "Erasing " << fieldCandidateList[i].relativePath_
1940  << fieldCandidateList[i].columnName_ << __E__;
1941 
1942  fieldCount.erase(fieldCount.begin() + i);
1943  fieldCandidateList.erase(fieldCandidateList.begin() + i);
1944  --i; // rewind to look at next after deleted
1945  }
1946  }
1947 
1948  for(unsigned int i = 0; i < fieldCandidateList.size(); ++i)
1949  __COUTS__(11) << "Pre-Final " << fieldCandidateList[i].relativePath_
1950  << fieldCandidateList[i].columnName_ << __E__;
1951 
1952  if(autoSelectFilterFields)
1953  {
1954  // filter for just 3 of the best filter fields
1955  // i.e. preference for GroupID, On/Off, and FixedChoice fields.
1956  std::set<std::pair<unsigned int /*fieldPriority*/, unsigned int /*fieldIndex*/>>
1957  prioritySet;
1958 
1959  unsigned int priorityPenalty;
1960  for(unsigned int i = 0; i < fieldCandidateList.size(); ++i)
1961  {
1962  __COUTS__(11) << "Option [" << i << "] "
1963  << fieldCandidateList[i].relativePath_
1964  << fieldCandidateList[i].columnName_ << " : "
1965  << fieldCandidateList[i].columnInfo_->getType() << ":"
1966  << fieldCandidateList[i].columnInfo_->getDataType() << __E__;
1967 
1968  priorityPenalty = std::count(fieldCandidateList[i].relativePath_.begin(),
1969  fieldCandidateList[i].relativePath_.end(),
1970  '/') *
1971  20; // penalize if not top level
1972 
1973  if(fieldCandidateList[i].columnInfo_->isBoolType() &&
1974  (fieldCandidateList[i].columnName_ ==
1975  TableViewColumnInfo::COL_NAME_STATUS ||
1976  fieldCandidateList[i].columnName_ ==
1977  TableViewColumnInfo::COL_NAME_ENABLED))
1978  {
1979  priorityPenalty += 0;
1980  }
1981  else if(fieldCandidateList[i].columnInfo_->isGroupID())
1982  {
1983  priorityPenalty += 1;
1984  }
1985  else if(fieldCandidateList[i].columnInfo_->isBoolType())
1986  {
1987  priorityPenalty += 3;
1988  }
1989  else if(fieldCandidateList[i].columnInfo_->getType() ==
1990  TableViewColumnInfo::TYPE_FIXED_CHOICE_DATA)
1991  {
1992  priorityPenalty += 3;
1993  }
1994  else if(fieldCandidateList[i].columnInfo_->getType() ==
1995  TableViewColumnInfo::TYPE_DATA)
1996  {
1997  priorityPenalty += 10;
1998  }
1999  else // skip other fields and mark for erasing
2000  {
2001  fieldCandidateList[i].tableName_ =
2002  ""; // clear table name as indicator for erase
2003  continue;
2004  }
2005  prioritySet.emplace(
2006  std::make_pair(priorityPenalty /*fieldPriority*/, i /*fieldIndex*/));
2007  __COUTS__(11) << "Option [" << i << "] "
2008  << fieldCandidateList[i].relativePath_
2009  << fieldCandidateList[i].columnName_ << " : "
2010  << fieldCandidateList[i].columnInfo_->getType() << ":"
2011  << fieldCandidateList[i].columnInfo_->getDataType()
2012  << "... priority = " << priorityPenalty << __E__;
2013 
2014  } // done ranking fields
2015 
2016  __COUTV__(StringMacros::setToString(prioritySet));
2017 
2018  // now choose the top 3, and delete the rest
2019  // clear table name to indicate field should be erased
2020  {
2021  unsigned int cnt = 0;
2022  for(const auto& priorityFieldIndex : prioritySet)
2023  if(++cnt > 3) // then mark for erasing
2024  {
2025  __COUTS__(11)
2026  << cnt << " marking "
2027  << fieldCandidateList[priorityFieldIndex.second].relativePath_
2028  << fieldCandidateList[priorityFieldIndex.second].columnName_
2029  << __E__;
2030  fieldCandidateList[priorityFieldIndex.second].tableName_ =
2031  ""; // clear table name as indicator for erase
2032  }
2033  }
2034 
2035  for(unsigned int i = 0; i < fieldCandidateList.size(); ++i)
2036  {
2037  if(fieldCandidateList[i].tableName_ == "") // then erase
2038  {
2039  __COUTS__(11) << "Erasing " << fieldCandidateList[i].relativePath_
2040  << fieldCandidateList[i].columnName_ << __E__;
2041  fieldCandidateList.erase(fieldCandidateList.begin() + i);
2042  --i; // rewind to look at next after deleted
2043  }
2044  }
2045  } // end AUTO filter field selection
2046 
2047  for(unsigned int i = 0; i < fieldCandidateList.size(); ++i)
2048  __COUT__ << "Final " << fieldCandidateList[i].relativePath_
2049  << fieldCandidateList[i].columnName_ << __E__;
2050 
2051  return fieldCandidateList;
2052 } // end getCommonFields()
2053 
2054 //==============================================================================
2060 std::set<std::string /*unique-value*/> ConfigurationTree::getUniqueValuesForField(
2061  const std::vector<std::string /*relative-path*/>& recordList,
2062  const std::string& fieldName,
2063  std::string* fieldGroupIDChildLinkIndex /* =0 */) const
2064 {
2065  if(fieldGroupIDChildLinkIndex)
2066  *fieldGroupIDChildLinkIndex = "";
2067 
2068  // enforce that starting point is a table node
2069  if(!isTableNode())
2070  {
2071  __SS__ << "Can only get getCommonFields from a table node! "
2072  << "The node type is " << getNodeType() << __E__;
2073 
2074  ss << nodeDump() << __E__;
2075  __SS_THROW__;
2076  }
2077 
2078  std::set<std::string /*unique-value*/> uniqueValues;
2079 
2080  // for each record in <record list>
2081  // emplace value at field into set
2082  //
2083  // return result
2084 
2085  // if no records, just return fieldGroupIDChildLinkIndex
2086  if(!recordList.size() && tableView_ && fieldGroupIDChildLinkIndex)
2087  {
2088  const TableViewColumnInfo& colInfo =
2089  tableView_->getColumnInfo(tableView_->findCol(fieldName));
2090 
2091  if(colInfo.isGroupID())
2092  *fieldGroupIDChildLinkIndex = colInfo.getChildLinkIndex();
2093 
2094  } // end no records
2095 
2096  for(unsigned int i = 0; i < recordList.size(); ++i)
2097  {
2098  //__COUT__ << "Checking " << recordList[i] << __E__;
2099 
2100  // Note: that ConfigurationTree maps both fields associated with a link
2101  // to the same node instance.
2102  // The behavior is likely not expected as response for this function..
2103  // so for links return actual value for field name specified
2104  // i.e. if Table of link is requested give that; if linkID is requested give
2105  // that. use TRUE in getValueAsString for proper behavior
2106 
2107  ConfigurationTree node = getNode(recordList[i]).getNode(fieldName);
2108 
2109  if(node.isGroupIDNode())
2110  {
2111  // handle groupID node special
2112 
2113  //__COUT__ << "GroupID field " << fieldName << __E__;
2114 
2115  // first time, get field's GroupID Child Link Index, if applicable
2116  if(i == 0 && fieldGroupIDChildLinkIndex)
2117  *fieldGroupIDChildLinkIndex = node.getColumnInfo().getChildLinkIndex();
2118 
2119  // return set of groupIDs individually
2120 
2121  std::set<std::string> setOfGroupIDs = node.getSetOfGroupIDs();
2122  for(auto& groupID : setOfGroupIDs)
2123  uniqueValues.emplace(groupID);
2124  }
2125  else // normal record, return value as string
2126  uniqueValues.emplace(node.getValueAsString(true));
2127 
2128  } // end record loop
2129 
2130  return uniqueValues;
2131 } // end getUniqueValuesForField()
2132 
2133 //==============================================================================
2136 void ConfigurationTree::recursiveGetCommonFields(
2137  std::vector<ConfigurationTree::RecordField>& fieldCandidateList,
2138  std::vector<int>& fieldCount,
2139  const std::vector<std::string /*relative-path*/>& fieldAcceptList,
2140  const std::vector<std::string /*relative-path*/>& fieldRejectList,
2141  unsigned int depth,
2142  const std::string& relativePathBase,
2143  bool inFirstRecord) const
2144 {
2145  //__COUT__ << depth << ":relativePathBase " << relativePathBase <<
2146  // " + " << inFirstRecord <<__E__;
2147  --depth;
2148 
2149  // clang-format off
2150  // =====================
2151  // Start recursiveGetCommonFields()
2152  // --depth;
2153  // loop through all children
2154  // if isValueNode (value nodes are possible field candidates!)
2155  // if first uid record
2156  // add field to <field candidates list> if in <field filter list>
2157  // initial mark <field count> as 1
2158  // else
2159  // if field is in list,
2160  // increment count for field candidate
2161  // //?increment fields in list count for record
2162  // else if field is not in list, discard field
2163  // else if depth > 0 and is UID-Link
2164  // if Link Table/UID pair is not found in <field candidates list>
2165  // (avoid endless loops through tree)
2166  // recursiveGetCommonFields()
2167  // =====================
2168  // clang-format on
2169 
2170  bool found; // used in loops
2171  auto tableName = getTableName(); // all fields will share this table name
2172  auto uid = getUIDAsString(); // all fields will share this uid
2173  unsigned int j;
2174 
2175  auto recordChildren = getChildren();
2176  for(const auto& fieldNode : recordChildren)
2177  {
2178  //__COUT__ << "All... " << fieldNode.second.getNodeType() <<
2179  // " -- " << (relativePathBase + fieldNode.first) <<
2180  // " + " << inFirstRecord <<__E__;
2181 
2182  if(fieldNode.second.isValueNode() || fieldNode.second.isGroupLinkNode())
2183  {
2184  // skip author and record insertion time
2185  if(fieldNode.second.isValueNode())
2186  {
2187  if(fieldNode.second.getColumnInfo().getType() ==
2188  TableViewColumnInfo::TYPE_AUTHOR ||
2189  fieldNode.second.getColumnInfo().getType() ==
2190  TableViewColumnInfo::TYPE_TIMESTAMP)
2191  continue;
2192 
2193  //__COUT__ << "isValueNode " << fieldNode.first << __E__;
2194  }
2195 
2196  if(inFirstRecord) // first uid record
2197  {
2198  //__COUT__ << "Checking... " << fieldNode.second.getNodeType() <<
2199  // " -- " << (relativePathBase + fieldNode.first) <<
2200  // "-- depth=" << depth << __E__;
2201 
2202  // check field accept filter list
2203  found = fieldAcceptList.size() ? false : true; // accept if no filter
2204  // list
2205  for(const auto& fieldFilter : fieldAcceptList)
2206  if(fieldFilter.find('/') != std::string::npos)
2207  {
2208  // filter is for full path, so add relative path base
2210  fieldFilter, relativePathBase + fieldNode.first))
2211  {
2212  found = true;
2213  break;
2214  }
2215  }
2216  else if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first))
2217  {
2218  found = true;
2219  break;
2220  }
2221 
2222  if(found)
2223  {
2224  // check field reject filter list
2225 
2226  found = true; // accept if no filter list
2227  for(const auto& fieldFilter : fieldRejectList)
2228  if(fieldFilter.find('/') != std::string::npos)
2229  {
2230  // filter is for full path, so add relative path base
2232  fieldFilter, relativePathBase + fieldNode.first))
2233  {
2234  found = false; // reject if match
2235  break;
2236  }
2237  }
2238  else if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first))
2239  {
2240  found = false; // reject if match
2241  break;
2242  }
2243  }
2244 
2245  // if found, new field (since this is first record)
2246  if(found)
2247  {
2248  //__COUT__ << "FOUND field " <<
2249  // (relativePathBase + fieldNode.first) << __E__;
2250 
2251  if(fieldNode.second.isGroupLinkNode())
2252  {
2253  //__COUT__ << "isGroupLinkNode " << fieldNode.first << __E__;
2254 
2255  // must get column info differently for group link column
2256 
2257  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>
2258  linkPair;
2259  bool isGroupLink;
2260  tableView_->getChildLink(
2261  tableView_->findCol(fieldNode.first), isGroupLink, linkPair);
2262 
2263  // add both link columns
2264 
2265  fieldCandidateList.push_back(ConfigurationTree::RecordField(
2266  table_->getTableName(),
2267  uid,
2268  tableView_->getColumnInfo(linkPair.first).getName(),
2269  relativePathBase, // relative path, not including columnName_
2270  &tableView_->getColumnInfo(linkPair.first)));
2271  fieldCount.push_back(1); // init count to 1
2272 
2273  fieldCandidateList.push_back(ConfigurationTree::RecordField(
2274  table_->getTableName(),
2275  uid,
2276  tableView_->getColumnInfo(linkPair.second).getName(),
2277  relativePathBase, // relative path, not including columnName_
2278  &tableView_->getColumnInfo(linkPair.second)));
2279  fieldCount.push_back(1); // init count to 1
2280  }
2281  else // value node
2282  {
2283  fieldCandidateList.push_back(ConfigurationTree::RecordField(
2284  tableName,
2285  uid,
2286  fieldNode.first,
2287  relativePathBase, // relative path, not including columnName_
2288  &fieldNode.second.getColumnInfo()));
2289  fieldCount.push_back(1); // init count to 1
2290  }
2291  }
2292  }
2293  else // not first record
2294  {
2295  // if field is in <field candidates list>, increment <field count>
2296  // else ignore
2297  for(j = 0; j < fieldCandidateList.size(); ++j)
2298  {
2299  if((relativePathBase + fieldNode.first) ==
2300  (fieldCandidateList[j].relativePath_ +
2301  fieldCandidateList[j].columnName_))
2302  {
2303  //__COUT__ << "incrementing " << j <<
2304  // " " << fieldCandidateList[j].relativePath_ << __E__;
2305  // found, so increment <field count>
2306  ++fieldCount[j];
2307  if(fieldNode.second.isGroupLinkNode() &&
2308  j + 1 < fieldCandidateList.size())
2309  ++fieldCount[j + 1]; // increment associated link index too!
2310  break;
2311  }
2312  }
2313  }
2314  } // end value and group link node handling
2315  else if(fieldNode.second.isUIDLinkNode())
2316  {
2317  //__COUT__ << "isUIDLinkNode " << (relativePathBase + fieldNode.first) <<
2318  // " + " << inFirstRecord << __E__;
2319 
2320  if(inFirstRecord) // first uid record
2321  {
2322  // check field accept filter list
2323  found =
2324  fieldAcceptList.size() ? false : true; // accept if no filter list
2325  for(const auto& fieldFilter : fieldAcceptList)
2326  if(fieldFilter.find('/') != std::string::npos)
2327  {
2328  // filter is for full path, so add relative path base
2330  fieldFilter, relativePathBase + fieldNode.first))
2331  {
2332  found = true;
2333  break;
2334  }
2335  }
2336  else if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first))
2337  {
2338  found = true;
2339  break;
2340  }
2341 
2342  if(found)
2343  {
2344  // check field reject filter list
2345 
2346  found = true; // accept if no filter list
2347  for(const auto& fieldFilter : fieldRejectList)
2348  if(fieldFilter.find('/') != std::string::npos)
2349  {
2350  // filter is for full path, so add relative path base
2352  fieldFilter, relativePathBase + fieldNode.first))
2353  {
2354  found = false; // reject if match
2355  break;
2356  }
2357  }
2358  else if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first))
2359  {
2360  found = false; // reject if match
2361  break;
2362  }
2363  }
2364 
2365  //__COUTV__(found);
2366 
2367  // if found, new field (since this is first record)
2368  if(found)
2369  {
2370  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>
2371  linkPair;
2372  bool isGroupLink;
2373 
2374  //__COUTV__(fieldNode.first);
2375  tableView_->getChildLink(
2376  tableView_->findCol(fieldNode.first), isGroupLink, linkPair);
2377 
2378  // add both link columns
2379 
2380  fieldCandidateList.push_back(ConfigurationTree::RecordField(
2381  table_->getTableName(),
2382  uid,
2383  tableView_->getColumnInfo(linkPair.first).getName(),
2384  relativePathBase, // relative path, not including columnName_
2385  &tableView_->getColumnInfo(linkPair.first)));
2386  fieldCount.push_back(1); // init count to 1
2387 
2388  fieldCandidateList.push_back(ConfigurationTree::RecordField(
2389  table_->getTableName(),
2390  uid,
2391  tableView_->getColumnInfo(linkPair.second).getName(),
2392  relativePathBase, // relative path, not including columnName_
2393  &tableView_->getColumnInfo(linkPair.second)));
2394  fieldCount.push_back(1); // init count to 1
2395  }
2396  }
2397  else // not first record
2398  {
2399  // if link fields (MUST BE 2) is in <field candidates list>, increment <field count>
2400  // else ignore
2401  for(j = 0; j < fieldCandidateList.size() - 1; ++j)
2402  {
2403  if((relativePathBase + fieldNode.first) ==
2404  (fieldCandidateList[j].relativePath_ +
2405  fieldCandidateList[j].columnName_))
2406  {
2407  //__COUT__ << "incrementing " << j <<
2408  // " " << fieldCandidateList[j].relativePath_ << __E__;
2409  // found, so increment <field count>
2410  ++fieldCount[j];
2411  ++fieldCount[j + 1]; // increment associated link index too!
2412  break;
2413  }
2414  }
2415  }
2416 
2417  // if depth remaining, then follow link, recursively!
2418  if(depth > 0 && !fieldNode.second.isDisconnected())
2419  fieldNode.second.recursiveGetCommonFields(
2420  fieldCandidateList,
2421  fieldCount,
2422  fieldAcceptList,
2423  fieldRejectList,
2424  depth,
2425  (relativePathBase + fieldNode.first) + "/", // relativePathBase
2426  inFirstRecord // continue inFirstRecord (or not) depth search
2427  );
2428  } // end handle unique link node
2429  } // end field node loop
2430 } // end recursiveGetCommonFields()
2431 
2432 //==============================================================================
2438 std::vector<std::vector<std::pair<std::string, ConfigurationTree>>>
2440  std::map<std::string /*relative-path*/, std::string /*value*/> filterMap,
2441  bool onlyStatusTrue) const
2442 {
2443  std::vector<std::vector<std::pair<std::string, ConfigurationTree>>> retVector;
2444 
2445  //__COUT__ << "Children of node: " << getValueAsString() << __E__;
2446 
2447  bool filtering = filterMap.size();
2448  std::string fieldValue;
2449 
2450  bool createContainer;
2451 
2452  std::vector<std::vector<std::string>> childrenNamesByPriority =
2453  getChildrenNamesByPriority(onlyStatusTrue);
2454 
2455  for(auto& childNamesAtPriority : childrenNamesByPriority)
2456  {
2457  createContainer = true;
2458 
2459  for(auto& childName : childNamesAtPriority)
2460  {
2461  //__COUT__ << "\tChild: " << childName << __E__;
2462 
2463  if(filtering) // if all criteria are not met, then skip
2464  if(!passFilterMap(childName, filterMap))
2465  continue;
2466 
2467  if(createContainer)
2468  {
2469  retVector.push_back(
2470  std::vector<std::pair<std::string, ConfigurationTree>>());
2471  createContainer = false;
2472  }
2473 
2474  retVector[retVector.size() - 1].push_back(
2475  std::pair<std::string, ConfigurationTree>(
2476  childName, this->getNode(childName, true)));
2477  } // end children within priority loop
2478  } // end children by priority loop
2479 
2480  //__COUT__ << "Done w/Children of node: " << getValueAsString() << __E__;
2481  return retVector;
2482 } // end getChildrenByPriority()
2483 
2484 //==============================================================================
2488  const std::string& childName,
2489  std::map<std::string /*relative-path*/, std::string /*value*/> filterMap) const
2490 {
2491  // if all criteria are not met, then skip
2492  bool skip = false;
2493 
2494  // for each filter, check value
2495  for(const auto& filterPair : filterMap)
2496  {
2497  std::string filterPath = childName + "/" + filterPair.first;
2498  __COUTV__(filterPath);
2499 
2500  ConfigurationTree childNode = this->getNode(filterPath);
2501  try
2502  {
2503  // extract field value list
2504  std::vector<std::string> fieldValues;
2506  filterPair.second, fieldValues, std::set<char>({','}) /*delimiters*/);
2507 
2508  __COUTV__(fieldValues.size());
2509 
2510  skip = true;
2511  // for each field check if any match
2512  for(const auto& fieldValue : fieldValues)
2513  {
2514  // Note: that ConfigurationTree maps both fields associated with a
2515  // link to the same node instance. The behavior is likely not
2516  // expected as response for this function.. so for links
2517  // return
2518  // actual value for field name specified i.e. if Table of link
2519  // is requested give that; if linkID is requested give that. use
2520  // TRUE in getValueAsString for proper behavior
2521 
2522  if(childNode.isGroupIDNode())
2523  {
2524  // handle groupID node special, check against set of groupIDs
2525 
2526  bool groupIdFound = false;
2527  std::set<std::string> setOfGroupIDs = childNode.getSetOfGroupIDs();
2528 
2529  for(auto& groupID : setOfGroupIDs)
2530  {
2531  __COUT__ << "\t\tGroupID Check: " << filterPair.first
2532  << " == " << fieldValue << " => "
2533  << StringMacros::decodeURIComponent(fieldValue)
2534  << " ??? " << groupID << __E__;
2535 
2537  StringMacros::decodeURIComponent(fieldValue), groupID))
2538  {
2539  // found a match for the field/groupId pair
2540  __COUT__ << "Found match" << __E__;
2541  groupIdFound = true;
2542  break;
2543  }
2544  } // end groupID search
2545 
2546  if(groupIdFound)
2547  {
2548  // found a match for the field/groupId-set pair
2549  __COUT__ << "Found break match" << __E__;
2550  skip = false;
2551  break;
2552  }
2553  }
2554  else // normal child node, check against value
2555  {
2556  __COUT__ << "\t\tCheck: " << filterPair.first << " == " << fieldValue
2557  << " => " << StringMacros::decodeURIComponent(fieldValue)
2558  << " ??? " << childNode.getValueAsString(true) << __E__;
2559 
2562  childNode.getValueAsString(true)))
2563  {
2564  // found a match for the field/value pair
2565  skip = false;
2566  break;
2567  }
2568  }
2569  }
2570  }
2571  catch(...)
2572  {
2573  __SS__ << "Failed to access filter path '" << filterPath << "' - aborting."
2574  << __E__;
2575 
2576  ss << nodeDump() << __E__;
2577  __SS_THROW__;
2578  }
2579 
2580  if(skip)
2581  break; // no match for this field, so stop checking and skip this
2582  // record
2583  }
2584  return !skip;
2585 } //end passFilterMap()
2586 
2587 //==============================================================================
2596 std::vector<std::pair<std::string, ConfigurationTree>> ConfigurationTree::getChildren(
2597  std::map<std::string /*relative-path*/, std::string /*value*/> filterMap,
2598  bool byPriority,
2599  bool onlyStatusTrue) const
2600 {
2601  std::vector<std::pair<std::string, ConfigurationTree>> retVector;
2602 
2603  //__COUT__ << "Children of node: " << getValueAsString() << __E__;
2604 
2605  bool filtering = filterMap.size();
2606  // bool skip;
2607  std::string fieldValue;
2608 
2609  std::vector<std::string> childrenNames = getChildrenNames(byPriority, onlyStatusTrue);
2610  for(auto& childName : childrenNames)
2611  {
2612  if(filtering && // if all criteria are not met, then skip
2613  !passFilterMap(childName, filterMap))
2614  continue;
2615 
2616  retVector.push_back(std::pair<std::string, ConfigurationTree>(
2617  childName, this->getNode(childName, true)));
2618  }
2619 
2620  //__COUT__ << "Done w/Children of node: " << getValueAsString() << __E__;
2621  return retVector;
2622 } // end getChildren()
2623 
2624 //==============================================================================
2628 std::map<std::string, ConfigurationTree> ConfigurationTree::getChildrenMap(
2629  std::map<std::string /*relative-path*/, std::string /*value*/> filterMap,
2630  bool onlyStatusTrue) const
2631 {
2632  std::map<std::string, ConfigurationTree> retMap;
2633 
2634  bool filtering = filterMap.size();
2635 
2636  //__COUT__ << "Children of node: " << getValueAsString() << __E__;
2637  std::vector<std::string> childrenNames =
2638  getChildrenNames(false /* byPriority */, onlyStatusTrue);
2639  for(auto& childName : childrenNames)
2640  {
2641  //__COUT__ << "\tChild: " << childName << __E__;
2642 
2643  // if all criteria are not met, then skip
2644  if(filtering && !passFilterMap(childName, filterMap))
2645  continue;
2646 
2647  retMap.insert(std::pair<std::string, ConfigurationTree>(
2648  childName, this->getNode(childName)));
2649  }
2650 
2651  //__COUT__ << "Done w/Children of node: " << getValueAsString() << __E__;
2652  return retMap;
2653 } // end getChildrenMap()
2654 
2655 //==============================================================================
2658 {
2659  if(!isUIDNode())
2660  {
2661  __SS__ << "Can not get status of '" << getValueAsString()
2662  << ".' Can only check the status of a UID/Record node!" << __E__;
2663  ss << nodeDump() << __E__;
2664  __SS_THROW__;
2665  }
2666 
2667  bool tmpStatus = true;
2668  try
2669  {
2670  tableView_->getValue(tmpStatus, row_, tableView_->getColStatus());
2671  }
2672  catch(const std::runtime_error& e)
2673  {
2674  //ignore error, assuming does not have a status column
2675  //default to enabled if no status
2676  }
2677  return tmpStatus;
2678 } // end isEnabled()
2679 
2680 //==============================================================================
2681 bool ConfigurationTree::isStatusNode(void) const
2682 {
2683  if(!isValueNode())
2684  return false;
2685 
2686  return col_ == tableView_->getColStatus();
2687 } // end isStatusNode()
2688 
2689 //==============================================================================
2692 std::vector<std::vector<std::string>> ConfigurationTree::getChildrenNamesByPriority(
2693  bool onlyStatusTrue) const
2694 {
2695  std::vector<std::vector<std::string /*child name*/>> retVector;
2696 
2697  if(!tableView_)
2698  {
2699  __SS__ << "Can not get children names of '" << getValueAsString()
2700  << "' with null configuration view pointer!" << __E__;
2701  if(isLinkNode() && isDisconnected())
2702  ss << " This node is a disconnected link to " << getDisconnectedTableName()
2703  << __E__;
2704 
2705  ss << nodeDump() << __E__;
2706  __SS_ONLY_THROW__;
2707  }
2708 
2709  if(row_ == TableView::INVALID && col_ == TableView::INVALID)
2710  {
2711  // this node is table node
2712  // so return all uid node strings that match groupId
2713 
2714  // bool tmpStatus;
2715 
2716  std::vector<std::vector<unsigned int /*group row*/>> groupRowsByPriority =
2717  tableView_->getGroupRowsByPriority(
2718  groupId_ == ""
2719  ? TableView::INVALID
2720  : // if no group ID, take all rows and ignore column, do not attempt link lookup
2721  tableView_->getLinkGroupIDColumn(childLinkIndex_),
2722  groupId_,
2723  onlyStatusTrue);
2724 
2725  // now build vector of vector names by priority
2726  for(const auto& priorityChildRowVector : groupRowsByPriority)
2727  {
2728  retVector.push_back(std::vector<std::string /*child name*/>());
2729  for(const auto& priorityChildRow : priorityChildRowVector)
2730  retVector[retVector.size() - 1].push_back(
2731  tableView_->getDataView()[priorityChildRow][tableView_->getColUID()]);
2732  }
2733  }
2734  else if(row_ == TableView::INVALID)
2735  {
2736  __SS__ << "Malformed ConfigurationTree" << __E__;
2737 
2738  ss << nodeDump() << __E__;
2739  __SS_THROW__;
2740  }
2741  else if(col_ == TableView::INVALID)
2742  {
2743  // this node is uid node
2744  // so return all link and value nodes
2745 
2746  for(unsigned int c = 0; c < tableView_->getNumberOfColumns(); ++c)
2747  if(c == tableView_->getColUID() || // skip UID and linkID columns (only show
2748  // link column, to avoid duplicates)
2749  tableView_->getColumnInfo(c).isChildLinkGroupID() ||
2750  tableView_->getColumnInfo(c).isChildLinkUID())
2751  continue;
2752  else
2753  {
2754  retVector.push_back(std::vector<std::string /*child name*/>());
2755  retVector[retVector.size() - 1].push_back(
2756  tableView_->getColumnInfo(c).getName());
2757  }
2758  }
2759  else // this node is value node, so has no node to choose from
2760  {
2761  // this node is value node, cant go any deeper!
2762  __SS__ << "\n\nError occurred looking for children of nodeName=" << getValueName()
2763  << "\n\n"
2764  << "Invalid depth! getChildrenValues() called from a value point in the "
2765  "Configuration Tree."
2766  << __E__;
2767 
2768  ss << nodeDump() << __E__;
2769  __SS_THROW__;
2770  }
2771 
2772  return retVector;
2773 } // end getChildrenNamesByPriority()
2774 
2775 //==============================================================================
2778 std::vector<std::string> ConfigurationTree::getChildrenNames(bool byPriority,
2779  bool onlyStatusTrue) const
2780 {
2781  std::vector<std::string /*child name*/> retVector;
2782 
2783  if(isRootNode())
2784  {
2785  for(auto& configPair : configMgr_->getActiveVersions())
2786  {
2787  //__GEN_COUT__ << configPair.first << " " << (int)(configPair.second?1:0) <<
2788  // __E__;
2789  retVector.push_back(configPair.first);
2790  }
2791  return retVector;
2792  }
2793 
2794  if(!tableView_)
2795  {
2796  __SS__ << "Can not get children names of '" << getFieldName() << ":"
2797  << getValueAsString() << "' with null configuration view pointer!"
2798  << __E__;
2799  if(isLinkNode() && isDisconnected())
2800  ss << " This node is a disconnected link to " << getDisconnectedTableName()
2801  << "(" << getDisconnectedLinkID() << ")" << __E__;
2802  __SS_ONLY_THROW__;
2803  }
2804 
2805  if(row_ == TableView::INVALID && col_ == TableView::INVALID)
2806  {
2807  // this node is table node
2808  // so return all uid node strings that match groupId
2809  std::vector<unsigned int /*group row*/> groupRows = tableView_->getGroupRows(
2810  (groupId_ == ""
2811  ? TableView::INVALID
2812  : // if no group ID, take all rows, do not attempt link lookup
2813  tableView_->getLinkGroupIDColumn(childLinkIndex_)),
2814  groupId_,
2815  onlyStatusTrue,
2816  byPriority);
2817 
2818  // now build vector of vector names by priority
2819  for(const auto& groupRow : groupRows)
2820  retVector.push_back(
2821  tableView_->getDataView()[groupRow][tableView_->getColUID()]);
2822 
2823  // bool tmpStatus;
2824  //
2825  // if(byPriority) // reshuffle by priority
2826  // {
2827  // try
2828  // {
2829  // std::map<uint64_t /*priority*/, std::vector<unsigned int /*child row*/>> orderedByPriority;
2830  // std::vector<std::string /*child name*/> retPrioritySet;
2831  //
2832  // unsigned int col = tableView_->getColPriority();
2833  //
2834  // uint64_t tmpPriority;
2835  //
2836  // for(unsigned int r = 0; r < tableView_->getNumberOfRows(); ++r)
2837  // if(groupId_ == "" || tableView_->isEntryInGroup(r, childLinkIndex_, groupId_))
2838  // {
2839  // // check status if needed
2840  // if(onlyStatusTrue)
2841  // {
2842  // tableView_->getValue(tmpStatus, r, tableView_->getColStatus());
2843  //
2844  // if(!tmpStatus)
2845  // continue; // skip those with status false
2846  // }
2847  //
2848  // tableView_->getValue(tmpPriority, r, col);
2849  // // do not accept DEFAULT value of 0.. convert to 100
2850  // orderedByPriority[tmpPriority ? tmpPriority : 100].push_back(r);
2851  // }
2852  //
2853  // // at this point have priority map
2854  // // now build return vector
2855  //
2856  // for(const auto& priorityChildRowVector : orderedByPriority)
2857  // for(const auto& priorityChildRow : priorityChildRowVector.second)
2858  // retVector.push_back(tableView_->getDataView()[priorityChildRow][tableView_->getColUID()]);
2859  //
2860  // __COUT__ << "Returning priority children list." << __E__;
2861  // return retVector;
2862  // }
2863  // catch(std::runtime_error& e)
2864  // {
2865  // __COUT_WARN__ << "Priority configuration not found. Assuming all "
2866  // "children have equal priority. "
2867  // << __E__;
2868  // retVector.clear();
2869  // }
2870  // }
2871  // // else not by priority
2872  //
2873  // for(unsigned int r = 0; r < tableView_->getNumberOfRows(); ++r)
2874  // if(groupId_ == "" || tableView_->isEntryInGroup(r, childLinkIndex_, groupId_))
2875  // {
2876  // // check status if needed
2877  // if(onlyStatusTrue)
2878  // {
2879  // tableView_->getValue(tmpStatus, r, tableView_->getColStatus());
2880  //
2881  // if(!tmpStatus)
2882  // continue; // skip those with status false
2883  // }
2884  //
2885  // retVector.push_back(tableView_->getDataView()[r][tableView_->getColUID()]);
2886  // }
2887  }
2888  else if(row_ == TableView::INVALID)
2889  {
2890  __SS__ << "Malformed ConfigurationTree" << __E__;
2891 
2892  ss << nodeDump() << __E__;
2893  __SS_THROW__;
2894  }
2895  else if(col_ == TableView::INVALID)
2896  {
2897  // this node is uid node
2898  // so return all link and value nodes
2899 
2900  for(unsigned int c = 0; c < tableView_->getNumberOfColumns(); ++c)
2901  if(c == tableView_->getColUID() || // skip UID and linkID columns (only show
2902  // link column, to avoid duplicates)
2903  tableView_->getColumnInfo(c).isChildLinkGroupID() ||
2904  tableView_->getColumnInfo(c).isChildLinkUID())
2905  continue;
2906  else
2907  retVector.push_back(tableView_->getColumnInfo(c).getName());
2908  }
2909  else // this node is value node, so has no node to choose from
2910  {
2911  // this node is value node, cant go any deeper!
2912  __SS__ << "\n\nError occurred looking for children of nodeName=" << getValueName()
2913  << "\n\n"
2914  << "Invalid depth! getChildrenValues() called from a value point in the "
2915  "Configuration Tree."
2916  << __E__;
2917 
2918  ss << nodeDump() << __E__;
2919  __SS_THROW__;
2920  }
2921 
2922  return retVector;
2923 } // end getChildrenNames()
2924 
2925 //==============================================================================
2929 ConfigurationTree ConfigurationTree::getValueAsTreeNode(void) const
2930 {
2931  // check if first character is a /, .. if so try to get value in tree
2932  // if exception, just take value
2933  // note: this call will throw an error, in effect, if not a "value" node
2934  if(!tableView_)
2935  {
2936  __SS__ << "Invalid node for get value." << __E__;
2937  __SS_THROW__;
2938  }
2939 
2940  std::string valueString =
2941  tableView_->getValueAsString(row_, col_, true /* convertEnvironmentVariables */);
2942  //__COUT__ << valueString << __E__;
2943  if(valueString.size() && valueString[0] == '/')
2944  {
2945  //__COUT__ << "Starts with '/' - check if valid tree path: " << valueString <<
2946  // __E__;
2947  try
2948  {
2949  ConfigurationTree retNode = configMgr_->getNode(valueString);
2950  __COUT__ << "Found a valid tree path in value!" << __E__;
2951  return retNode;
2952  }
2953  catch(...)
2954  {
2955  __SS__ << "Invalid tree path." << __E__;
2956  __SS_ONLY_THROW__;
2957  }
2958  }
2959 
2960  {
2961  __SS__ << "Invalid value string '" << valueString
2962  << "' - must start with a '/' character." << __E__;
2963  __SS_ONLY_THROW__;
2964  }
2965 } // end getValueAsTreeNode()
std::map< std::string, TableVersion > getActiveVersions(void) const
getActiveVersions
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
const TableBase * getTableByName(const std::string &configurationName) const
const unsigned int & getRow(void) const
getRow
const std::string & getValueDataType(void) const
std::map< std::string, ConfigurationTree > getNodes(const std::string &nodeString) const
getNodes
const TableVersion & getTableVersion(void) const
getTableVersion
bool isDisconnected(void) const
const std::string & getAuthor(void) const
getAuthor
const std::string & getComment(void) const
getComment
std::vector< std::string > getChildrenNames(bool byPriority=false, bool onlyStatusTrue=false) const
bool isEnabled(void) const
same as status()
static const std::string NODE_TYPE_GROUP_TABLE
bool isValueNumberDataType(void) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
const std::string & getTableName(void) const
getTableName
T getValueWithDefault(const T &defaultValue) const
const unsigned int & getFieldRow(void) const
std::map< std::string, ConfigurationTree > getChildrenMap(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool onlyStatusTrue=false) const
std::string nodeDump(bool forcePrintout=false) const
used for debugging (when throwing exception)
const std::string & getValueName(void) const
const std::string & getValueAsString(bool returnLinkTableValue=false) const
const ConfigurationManager * getConfigurationManager(void) const
extracting information from node
const std::string & getChildLinkIndex(void) const
getChildLinkIndex
void print(const unsigned int &depth=-1, std::ostream &out=std::cout) const
bool isGroupIDNode(void) const
const std::string & getDisconnectedTableName(void) const
getDisconnectedTableName
bool isValueBoolType(void) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
std::vector< std::string > getFixedChoices(void) const
bool hasComment(void) const
hasComment
const std::string & getDefaultValue(void) const
const time_t & getTableCreationTime(void) const
getTableCreationTime
std::string getParentLinkIndex(void) const
getParentLinkIndex
const std::string & getUIDAsString(void) const
std::vector< ConfigurationTree::RecordField > getCommonFields(const std::vector< std::string > &recordList, const std::vector< std::string > &fieldAcceptList, const std::vector< std::string > &fieldRejectList, unsigned int depth=-1, bool autoSelectFilterFields=false) const
const unsigned int & getNodeRow(void) const
getNodeRow
std::set< std::string > getSetOfGroupIDs(void) const
bool isValueNode(void) const
const std::string & getFieldName(void) const
alias for getValueName
std::vector< std::vector< std::string > > getChildrenNamesByPriority(bool onlyStatusTrue=false) const
std::set< std::string > getUniqueValuesForField(const std::vector< std::string > &recordList, const std::string &fieldName, std::string *fieldGroupIDChildLinkIndex=0) const
const std::string & getValueType(void) const
bool passFilterMap(const std::string &childName, std::map< std::string, std::string > filterMap) const
~ConfigurationTree(void)
destructor
bool isGroupLinkNode(void) const
std::string getParentLinkID(void) const
getParentLinkID
const std::string & getFieldTableName(void) const
const unsigned int & getColumn(void) const
getColumn
const std::string & getDisconnectedLinkID(void) const
getDisconnectedLinkID
const std::string & getParentTableName(void) const
getParentTableName
bool isUIDLinkNode(void) const
const std::string & getParentRecordName(void) const
getParentRecordName
std::string getEscapedValue(void) const
const TableViewColumnInfo & getColumnInfo(void) const
bool isDefaultValue(void) const
boolean info
std::vector< std::vector< std::pair< std::string, ConfigurationTree > > > getChildrenByPriority(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool onlyStatusTrue=false) const
const std::string & getParentLinkColumnName(void) const
getParentLinkColumnName
T getValue(void) const
defined in included .icc source
const unsigned int & getFieldColumn(void) const
const std::string & getTableName(void) const
Getters.
Definition: TableBase.cc:814
static const std::string DATATYPE_NUMBER
std::string getChildLinkIndex(void) const
getChildLinkIndex
static const std::string TYPE_UID
NOTE: Do NOT put '-' in static const TYPEs because it will mess up javascript handling in the web gui...
const BitMapInfo & getBitMapInfo(void) const
uses dataChoices CSV fields if type is TYPE_BITMAP_DATA
bool isBoolType(void) const
TODO check if min and max values need a function called getallminmaxforgui or something like that for...
bool isNumberDataType(void) const
isNumberDataType
bool isChildLinkGroupID(void) const
const std::string & getDefaultValue(void) const
returns the configued default value value for this particular column
unsigned int findRow(unsigned int col, const T &value, unsigned int offsetRow=0, bool doNotThrow=false) const
< in included .icc source
std::string getEscapedValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true, bool quotesToDoubleQuotes=false) const
Definition: TableView.cc:1024
std::vector< std::vector< unsigned int > > getGroupRowsByPriority(const unsigned int groupIdCol, const std::string &groupID, bool onlyStatusTrue=false) const
Definition: TableView.cc:1520
T validateValueForColumn(const std::string &value, unsigned int col, bool doConvertEnvironmentVariables=true) const
< in included .icc source
unsigned int getColStatus(void) const
Definition: TableView.cc:1407
unsigned int getLinkGroupIDColumn(const std::string &childLinkIndex) const
Definition: TableView.cc:1837
bool getChildLink(const unsigned int &col, bool &isGroup, std::pair< unsigned int, unsigned int > &linkPair) const
Definition: TableView.cc:3632
std::string getValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const
Definition: TableView.cc:975
std::vector< unsigned int > getGroupRows(const unsigned int groupIdCol, const std::string &groupID, bool onlyStatusTrue=false, bool orderedByPriority=false) const
Definition: TableView.cc:1497
std::set< std::string > getSetOfGroupIDs(const std::string &childLinkIndex, unsigned int row=-1) const
Definition: TableView.cc:1736
void getValue(T &value, unsigned int row, unsigned int col, bool doConvertEnvironmentVariables=true) const
< in included .icc source
unsigned int getColUID(void) const
Definition: TableView.cc:1322
unsigned int findCol(const std::string &name) const
Definition: TableView.cc:1952
unsigned int findRowInGroup(unsigned int col, const T &value, const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow=0) const
< in included .icc source
extracting information from a list of records
static void getVectorFromString(const std::string &inputString, std::vector< std::string > &listToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'}, std::vector< char > *listOfDelimiters=0, bool decodeURIComponents=false)
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
setToString ~
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
vectorToString ~
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static bool wildCardMatch(const std::string &needle, const std::string &haystack, unsigned int *priorityIndex=0)
Definition: StringMacros.cc:19
static std::string decodeURIComponent(const std::string &data)
static std::string stackTrace(void)