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