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