otsdaq  v2_00_00
ViewColumnInfo.cc
1 #include "otsdaq-core/ConfigurationDataFormats/ViewColumnInfo.h"
2 #include "otsdaq-core/Macros/CoutHeaderMacros.h"
3 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationView.h"
4 
5 #include <iostream>
6 #include <sstream>
7 #include <stdexcept>
8 
9 using namespace ots;
10 
11 //NOTE: Do NOT put '-' in static const TYPEs because it will mess up javascript handling in the web gui
12 const std::string ViewColumnInfo::TYPE_UID = "UID";
13 
14 const std::string ViewColumnInfo::TYPE_DATA = "Data";
15 const std::string ViewColumnInfo::TYPE_UNIQUE_DATA = "UniqueData";
16 const std::string ViewColumnInfo::TYPE_MULTILINE_DATA = "MultilineData";
17 const std::string ViewColumnInfo::TYPE_FIXED_CHOICE_DATA = "FixedChoiceData";
18 const std::string ViewColumnInfo::TYPE_BITMAP_DATA = "BitMap";
19 
20 const std::string ViewColumnInfo::TYPE_ON_OFF = "OnOff";
21 const std::string ViewColumnInfo::TYPE_TRUE_FALSE = "TrueFalse";
22 const std::string ViewColumnInfo::TYPE_YES_NO = "YesNo";
23 
24 const std::string ViewColumnInfo::TYPE_START_CHILD_LINK = "ChildLink";
25 const std::string ViewColumnInfo::TYPE_START_CHILD_LINK_UID = "ChildLinkUID";
26 const std::string ViewColumnInfo::TYPE_START_CHILD_LINK_GROUP_ID = "ChildLinkGroupID";
27 const std::string ViewColumnInfo::TYPE_START_GROUP_ID = "GroupID";
28 const std::string ViewColumnInfo::TYPE_COMMENT = "Comment";
29 const std::string ViewColumnInfo::TYPE_AUTHOR = "Author";
30 const std::string ViewColumnInfo::TYPE_TIMESTAMP = "Timestamp";
31 //NOTE: Do NOT put '-' in static const TYPEs because it will mess up javascript handling in the web gui
32 
33 const std::string ViewColumnInfo::DATATYPE_NUMBER = "NUMBER";
34 const std::string ViewColumnInfo::DATATYPE_STRING = "VARCHAR2";
35 const std::string ViewColumnInfo::DATATYPE_TIME = "TIMESTAMP WITH TIMEZONE";
36 
37 const std::string ViewColumnInfo::TYPE_VALUE_YES = "Yes";
38 const std::string ViewColumnInfo::TYPE_VALUE_NO = "No";
39 const std::string ViewColumnInfo::TYPE_VALUE_TRUE = "True";
40 const std::string ViewColumnInfo::TYPE_VALUE_FALSE = "False";
41 const std::string ViewColumnInfo::TYPE_VALUE_ON = "On";
42 const std::string ViewColumnInfo::TYPE_VALUE_OFF = "Off";
43 
44 const std::string ViewColumnInfo::DATATYPE_STRING_DEFAULT = "DEFAULT";
45 const std::string ViewColumnInfo::DATATYPE_COMMENT_DEFAULT = "No Comment";
46 const std::string ViewColumnInfo::DATATYPE_BOOL_DEFAULT = "0";
47 const std::string ViewColumnInfo::DATATYPE_NUMBER_DEFAULT = "0";
48 const std::string ViewColumnInfo::DATATYPE_TIME_DEFAULT = "0";
49 const std::string ViewColumnInfo::DATATYPE_LINK_DEFAULT = "NO_LINK";
50 
51 const std::string ViewColumnInfo::COL_NAME_STATUS = "Status";
52 
53 
54 //==============================================================================
55 //ViewColumnInfo
56 // if(capturedExceptionString) *capturedExceptionString = ""; //indicates no error found
57 // if(!capturedExceptionString) then exception is thrown on error
58 ViewColumnInfo::ViewColumnInfo(const std::string &type, const std::string &name,
59  const std::string &storageName, const std::string &dataType,
60  const std::string &dataChoicesCSV, std::string *capturedExceptionString)
61 : type_ (type)
62 , name_ (name)
63 , storageName_(storageName)
64 , dataType_ (dataType)
65 , bitMapInfoP_(0)
66 {
67  //verify type
68  if((type_ != TYPE_DATA) && (type_ != TYPE_UNIQUE_DATA) && (type_ != TYPE_UID) &&
69  (type_ != TYPE_MULTILINE_DATA) && (type_ != TYPE_FIXED_CHOICE_DATA) &&
70  (type_ != TYPE_BITMAP_DATA) &&
71  (type_ != TYPE_ON_OFF) && (type_ != TYPE_TRUE_FALSE) && (type_ != TYPE_YES_NO) &&
72  (type_ != TYPE_COMMENT) && (type_ != TYPE_AUTHOR) && (type_ != TYPE_TIMESTAMP) &&
73  !isChildLink() &&
74  !isChildLinkUID() &&
75  !isChildLinkGroupID() &&
76  !isGroupID() )
77  {
78  __SS__ << "The type for column " << name_ << " is " << type_ <<
79  ", while the only accepted types are: " <<
80  TYPE_DATA << " " <<
81  TYPE_UNIQUE_DATA << " " <<
82  TYPE_MULTILINE_DATA << " " <<
83  TYPE_FIXED_CHOICE_DATA << " " <<
84  TYPE_UID << " " <<
85  TYPE_ON_OFF << " " <<
86  TYPE_TRUE_FALSE << " " <<
87  TYPE_YES_NO << " " <<
88  TYPE_START_CHILD_LINK << "-* " <<
89  TYPE_START_CHILD_LINK_UID << "-* " <<
90  TYPE_START_CHILD_LINK_GROUP_ID << "-* " <<
91  TYPE_START_GROUP_ID << "-* " << std::endl;
92  if(capturedExceptionString) *capturedExceptionString = ss.str();
93  else throw std::runtime_error(ss.str());
94  }
95  else if(capturedExceptionString) *capturedExceptionString = ""; //indicates no error found
96 
97  //enforce that type only
98  //allows letters, numbers, dash, underscore
99  for(unsigned int i=0;i<type_.size();++i)
100  if(!(
101  (type_[i] >= 'A' && type_[i] <= 'Z') ||
102  (type_[i] >= 'a' && type_[i] <= 'z') ||
103  (type_[i] >= '0' && type_[i] <= '9') ||
104  (type_[i] == '-' || type_[i] <= '_' || type_[i] <= '.')
105  ))
106  {
107  __SS__ << "The data type for column " << name_ << " is '" << type_ <<
108  "'. Data types must contain only letters, numbers," <<
109  "dashes, underscores, and periods." << std::endl;
110  if(capturedExceptionString) *capturedExceptionString += ss.str();
111  else throw std::runtime_error(ss.str());
112  }
113 
114 
115  //verify data type
116  if((dataType_ != DATATYPE_NUMBER) &&
117  (dataType_ != DATATYPE_STRING) &&
118  (dataType_ != DATATYPE_TIME))
119  {
120  __SS__ << "The data type for column " << name_ << " is " << dataType_ <<
121  ", while the only accepted types are: " <<
122  DATATYPE_NUMBER << " " <<
123  DATATYPE_STRING << " " <<
124  DATATYPE_TIME << std::endl;
125  if(capturedExceptionString) *capturedExceptionString += ss.str();
126  else throw std::runtime_error(ss.str());
127  }
128 
129 
130  if(dataType_.size() == 0)
131  {
132  __SS__ << "The data type for column " << name_ << " is '" << dataType_ <<
133  "'. Data types must contain at least 1 character." << std::endl;
134  if(capturedExceptionString) *capturedExceptionString += ss.str();
135  else throw std::runtime_error(ss.str());
136  }
137 
138  //enforce that data type only
139  //allows letters, numbers, dash, underscore
140  for(unsigned int i=0;i<dataType_.size();++i)
141  if(!(
142  (dataType_[i] >= 'A' && dataType_[i] <= 'Z') ||
143  (dataType_[i] >= 'a' && dataType_[i] <= 'z') ||
144  (dataType_[i] >= '0' && dataType_[i] <= '9') ||
145  (dataType_[i] == '-' || dataType_[i] <= '_')
146  ))
147  {
148  __SS__ << "The data type for column " << name_ << " is '" << dataType_ <<
149  "'. Data types must contain only letters, numbers," <<
150  "dashes, and underscores." << std::endl;
151  if(capturedExceptionString) *capturedExceptionString += ss.str();
152  else throw std::runtime_error(ss.str());
153  }
154 
155  if(name_.size() == 0)
156  {
157  __SS__ << "There is a column named " << name_ <<
158  "'. Column names must contain at least 1 character." << std::endl;
159  if(capturedExceptionString) *capturedExceptionString += ss.str();
160  else throw std::runtime_error(ss.str());
161  }
162 
163  //enforce that col name only
164  //allows letters, numbers, dash, underscore
165  for(unsigned int i=0;i<name_.size();++i)
166  if(!(
167  (name_[i] >= 'A' && name_[i] <= 'Z') ||
168  (name_[i] >= 'a' && name_[i] <= 'z') ||
169  (name_[i] >= '0' && name_[i] <= '9') ||
170  (name_[i] == '-' || name_[i] <= '_')
171  ))
172  {
173  __SS__ << "There is a column named " << name_ <<
174  "'. Column names must contain only letters, numbers," <<
175  "dashes, and underscores." << std::endl;
176  if(capturedExceptionString) *capturedExceptionString += ss.str();
177  else throw std::runtime_error(ss.str());
178  }
179 
180 
181  if(storageName_.size() == 0)
182  {
183  __SS__ << "The storage name for column " << name_ << " is '" << storageName_ <<
184  "'. Storage names must contain at least 1 character." << std::endl;
185  if(capturedExceptionString) *capturedExceptionString += ss.str();
186  else throw std::runtime_error(ss.str());
187  }
188 
189  //enforce that col storage name only
190  //allows capital letters, numbers, dash, underscore
191  for(unsigned int i=0;i<storageName_.size();++i)
192  if(!(
193  (storageName_[i] >= 'A' && storageName_[i] <= 'Z') ||
194  (storageName_[i] >= '0' && storageName_[i] <= '9') ||
195  (storageName_[i] == '-' || storageName_[i] <= '_')
196  ))
197  {
198  __SS__ << "The storage name for column " << name_ << " is '" << storageName_ <<
199  "'. Storage names must contain only capital letters, numbers," <<
200  "dashes, and underscores." << std::endl;
201  if(capturedExceptionString) *capturedExceptionString += ss.str();
202  else throw std::runtime_error(ss.str());
203  }
204 
205  //build data choices vector from URI encoded data
206  //__COUT__ << "dataChoicesCSV " << dataChoicesCSV << std::endl;
207  {
208  std::istringstream f(dataChoicesCSV);
209  std::string s;
210  while (getline(f, s, ',')) dataChoices_.push_back(
211  ConfigurationView::decodeURIComponent(s));
212  //for(const auto &dc: dataChoices_)
213  // __COUT__ << dc << std::endl;
214  }
215 
216  try
217  {
218  extractBitMapInfo();
219  }
220  catch(std::runtime_error &e)
221  {
222  if(capturedExceptionString) *capturedExceptionString += e.what();
223  else throw;
224  }
225 
226  //__COUT__ << "dataChoicesCSV " << dataChoicesCSV << std::endl;
227 }
228 
229 //==============================================================================
230 void ViewColumnInfo::extractBitMapInfo()
231 {
232  //create BitMapInfo if this is a bitmap column
233  if(type_ == TYPE_BITMAP_DATA)
234  {
235  if(bitMapInfoP_) delete bitMapInfoP_;
236  bitMapInfoP_ = new BitMapInfo();
237 
238  //extract bitMapInfo parameters:
239  // must match TableEditor js handling:
240 
241 
242  // [ //types => 0:string, 1:bool (default no),
243  // //2:bool (default yes), 3:color
244  //
245  //0 0,//"Number of Rows",
246  //1 0,//"Number of Columns",
247  //2 0,//"Cell Bit-field Size",
248  //3 0,//"Min-value Allowed",
249  //4 0,//"Max-value Allowed",
250  //5 0,//"Value step-size Allowed",
251  //6 0,//"Display Aspect H:W",
252  //7 3,//"Min-value Cell Color",
253  //8 3,//"Mid-value Cell Color",
254  //9 3,//"Max-value Cell Color",
255  //10 3,//"Absolute Min-value Cell Color",
256  //11 3,//"Absolute Max-value Cell Color",
257  //12 1,//"Display Rows in Ascending Order",
258  //13 2,//"Display Columns in Ascending Order",
259  //14 1,//"Snake Double Rows",
260  //15 1];//"Snake Double Columns"];
261 
262  if(dataChoices_.size() < 16)
263  {
264  __SS__ << "The Bit-Map data parameters for column " << name_ <<
265  " should be size 16, but is size " << dataChoices_.size() <<
266  ". Bit-Map parameters should be rows, cols, cellBitSize, and min, mid, max color." <<
267  std::endl;
268  throw std::runtime_error(ss.str());
269  }
270 
271  sscanf(dataChoices_[0].c_str(),"%u",&(bitMapInfoP_->numOfRows_));
272  sscanf(dataChoices_[1].c_str(),"%u",&(bitMapInfoP_->numOfColumns_));
273  sscanf(dataChoices_[2].c_str(),"%u",&(bitMapInfoP_->cellBitSize_));
274 
275  sscanf(dataChoices_[3].c_str(),"%lu",&(bitMapInfoP_->minValue_));
276  sscanf(dataChoices_[4].c_str(),"%lu",&(bitMapInfoP_->maxValue_));
277  sscanf(dataChoices_[5].c_str(),"%lu",&(bitMapInfoP_->stepValue_));
278 
279  bitMapInfoP_->aspectRatio_ = dataChoices_[6];
280  bitMapInfoP_->minColor_ = dataChoices_[7];
281  bitMapInfoP_->midColor_ = dataChoices_[8];
282  bitMapInfoP_->maxColor_ = dataChoices_[9];
283  bitMapInfoP_->absMinColor_ = dataChoices_[10];
284  bitMapInfoP_->absMaxColor_ = dataChoices_[11];
285 
286  bitMapInfoP_->rowsAscending_ = dataChoices_[12] == "Yes"?1:0;
287  bitMapInfoP_->colsAscending_ = dataChoices_[13] == "Yes"?1:0;
288  bitMapInfoP_->snakeRows_ = dataChoices_[14] == "Yes"?1:0;
289  bitMapInfoP_->snakeCols_ = dataChoices_[15] == "Yes"?1:0;
290  }
291 }
292 
293 //==============================================================================
294 //private empty default constructor. Only used by assignment operator.
295 ViewColumnInfo::ViewColumnInfo(void){}
296 
297 //==============================================================================
298 ViewColumnInfo::ViewColumnInfo(const ViewColumnInfo& c) //copy constructor because of bitmap pointer
299 :type_(c.type_)
300 ,name_(c.name_)
301 ,storageName_(c.storageName_)
302 ,dataType_(c.dataType_)
303 ,dataChoices_(c.dataChoices_)
304 ,bitMapInfoP_(0)
305 {
306  //extract bitmap info if necessary
307  extractBitMapInfo();
308 }
309 
310 //==============================================================================
311 ViewColumnInfo& ViewColumnInfo::operator=(const ViewColumnInfo& c) //assignment operator because of bitmap pointer
312 {
313  ViewColumnInfo *retColInfo = new ViewColumnInfo();
314  retColInfo->type_ = c.type_;
315  retColInfo->name_ = c.name_;
316  retColInfo->storageName_ = c.storageName_;
317  retColInfo->dataType_ = c.dataType_;
318  retColInfo->dataChoices_ = c.dataChoices_;
319  retColInfo->bitMapInfoP_ = 0;
320 
321  //extract bitmap info if necessary
322  retColInfo->extractBitMapInfo();
323 
324  return *retColInfo;
325 }
326 
327 //==============================================================================
328 ViewColumnInfo::~ViewColumnInfo(void)
329 {
330  if(bitMapInfoP_) delete bitMapInfoP_;
331 }
332 
333 //==============================================================================
334 const std::string& ViewColumnInfo::getType(void) const
335 {
336  return type_;
337 }
338 
339 //==============================================================================
340 const std::string& ViewColumnInfo::getDefaultValue(void) const
341 {
342  if(getDataType() == ViewColumnInfo::DATATYPE_STRING)
343  {
344  if(getType() == ViewColumnInfo::TYPE_ON_OFF ||
345  getType() == ViewColumnInfo::TYPE_TRUE_FALSE ||
346  getType() == ViewColumnInfo::TYPE_YES_NO)
347  return (ViewColumnInfo::DATATYPE_BOOL_DEFAULT); //default to OFF, NO, FALSE
348  else if(isChildLink())
349  return (ViewColumnInfo::DATATYPE_LINK_DEFAULT);
350  else if(getType() == ViewColumnInfo::TYPE_COMMENT)
351  return (ViewColumnInfo::DATATYPE_COMMENT_DEFAULT);
352  else
353  return (ViewColumnInfo::DATATYPE_STRING_DEFAULT);
354  }
355  else if(getDataType() == ViewColumnInfo::DATATYPE_NUMBER)
356  return (ViewColumnInfo::DATATYPE_NUMBER_DEFAULT);
357  else if(getDataType() == ViewColumnInfo::DATATYPE_TIME)
358  return (ViewColumnInfo::DATATYPE_TIME_DEFAULT);
359  else
360  {
361  __SS__ << "\tUnrecognized View data type: " << getDataType() << std::endl;
362  __COUT_ERR__ << "\n" << ss.str();
363  throw std::runtime_error(ss.str());
364  }
365 }
366 
367 //==============================================================================
368 std::vector<std::string> ViewColumnInfo::getAllTypesForGUI(void)
369 {
370  std::vector<std::string> all;
371  all.push_back(TYPE_DATA);
372  all.push_back(TYPE_UNIQUE_DATA);
373  all.push_back(TYPE_FIXED_CHOICE_DATA);
374  all.push_back(TYPE_MULTILINE_DATA);
375  all.push_back(TYPE_BITMAP_DATA);
376  all.push_back(TYPE_ON_OFF);
377  all.push_back(TYPE_TRUE_FALSE);
378  all.push_back(TYPE_YES_NO);
379  all.push_back(TYPE_START_CHILD_LINK_UID);
380  all.push_back(TYPE_START_CHILD_LINK_GROUP_ID);
381  all.push_back(TYPE_START_CHILD_LINK);
382  all.push_back(TYPE_START_GROUP_ID);
383  return all;
384 }
385 
386 //==============================================================================
387 std::vector<std::string> ViewColumnInfo::getAllDataTypesForGUI(void)
388 {
389  std::vector<std::string> all;
390  all.push_back(DATATYPE_STRING);
391  all.push_back(DATATYPE_NUMBER);
392  all.push_back(DATATYPE_TIME);
393  return all;
394 }
395 
396 //==============================================================================
397 //map of datatype,type to default value
398 std::map<std::pair<std::string,std::string>,std::string> ViewColumnInfo::getAllDefaultsForGUI(void)
399 {
400  std::map<std::pair<std::string,std::string>,std::string> all;
401  all[std::pair<std::string,std::string>(DATATYPE_NUMBER,"*")] = DATATYPE_NUMBER_DEFAULT;
402  all[std::pair<std::string,std::string>(DATATYPE_TIME,"*")] = DATATYPE_TIME_DEFAULT;
403 
404  all[std::pair<std::string,std::string>(DATATYPE_STRING,TYPE_ON_OFF)] = DATATYPE_BOOL_DEFAULT;
405  all[std::pair<std::string,std::string>(DATATYPE_STRING,TYPE_TRUE_FALSE)] = DATATYPE_BOOL_DEFAULT;
406  all[std::pair<std::string,std::string>(DATATYPE_STRING,TYPE_YES_NO)] = DATATYPE_BOOL_DEFAULT;
407 
408  all[std::pair<std::string,std::string>(DATATYPE_STRING,TYPE_START_CHILD_LINK)] = DATATYPE_LINK_DEFAULT;
409  all[std::pair<std::string,std::string>(DATATYPE_STRING,"*")] = DATATYPE_STRING_DEFAULT;
410  return all;
411 }
412 
413 //==============================================================================
414 const std::string& ViewColumnInfo::getName(void) const
415 {
416  return name_;
417 }
418 
419 //==============================================================================
420 const std::string& ViewColumnInfo::getStorageName(void) const
421 {
422  return storageName_;
423 }
424 
425 //==============================================================================
426 const std::string& ViewColumnInfo::getDataType(void) const
427 {
428  return dataType_;
429 }
430 
431 //==============================================================================
432 const std::vector<std::string>& ViewColumnInfo::getDataChoices(void) const
433 {
434  return dataChoices_;
435 }
436 
437 //==============================================================================
438 //getBitMapInfo
439 // uses dataChoices CSV fields if type is TYPE_BITMAP_DATA
440 const ViewColumnInfo::BitMapInfo& ViewColumnInfo::getBitMapInfo(void) const
441 {
442  if(bitMapInfoP_) return *bitMapInfoP_;
443 
444  //throw error at this point!
445  {
446  __SS__ << "getBitMapInfo request for non-BitMap column of type: " << getType() << std::endl;
447  __COUT_ERR__ << "\n" << ss.str();
448  throw std::runtime_error(ss.str());
449  }
450 
451 }
452 
453 //==============================================================================
454 //isChildLink
455 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
456 // so don't allow alpha character immediately after
457 const bool ViewColumnInfo::isChildLink(void) const
458 {
459  return (type_.find(TYPE_START_CHILD_LINK) == 0 &&
460  type_.length() > TYPE_START_CHILD_LINK.length() &&
461  type_[TYPE_START_CHILD_LINK.length()] == '-');
462 }
463 
464 //==============================================================================
465 //isChildLinkUID
466 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
467 // so don't allow alpha character immediately after
468 const bool ViewColumnInfo::isChildLinkUID(void) const
469 {
470  return (type_.find(TYPE_START_CHILD_LINK_UID) == 0 &&
471  type_.length() > TYPE_START_CHILD_LINK_UID.length() &&
472  type_[TYPE_START_CHILD_LINK_UID.length()] == '-');
473 }
474 
475 //==============================================================================
476 //isChildLinkGroupID
477 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
478 // so don't allow alpha character immediately after
479 const bool ViewColumnInfo::isChildLinkGroupID(void) const
480 {
481  return (type_.find(TYPE_START_CHILD_LINK_GROUP_ID) == 0 &&
482  type_.length() > TYPE_START_CHILD_LINK_GROUP_ID.length() &&
483  type_[TYPE_START_CHILD_LINK_GROUP_ID.length()] == '-');
484 }
485 
486 //==============================================================================
487 //isGroupID
488 // note: TYPE_START_CHILD_LINK index may be a subset of UID and GROUP_ID
489 // so don't allow alpha character immediately after in group index
490 const bool ViewColumnInfo::isGroupID(void) const
491 {
492  return (type_.find(TYPE_START_GROUP_ID) == 0 &&
493  type_.length() > TYPE_START_GROUP_ID.length() &&
494  type_[TYPE_START_GROUP_ID.length()] == '-');
495 }
496 
497 //==============================================================================
498 //getChildLinkIndex
499 std::string ViewColumnInfo::getChildLinkIndex (void) const
500 {
501  //note: +1 to skip '-'
502  if(isChildLink())
503  return type_.substr(TYPE_START_CHILD_LINK.length()+1);
504  else if(isChildLinkUID())
505  return type_.substr(TYPE_START_CHILD_LINK_UID.length()+1);
506  else if(isChildLinkGroupID())
507  return type_.substr(TYPE_START_CHILD_LINK_GROUP_ID.length()+1);
508  else if(isGroupID())
509  return type_.substr(TYPE_START_GROUP_ID.length()+1);
510  else
511  {
512  __SS__ << ("Requesting a Link Index from a column that is not a child link member!") << std::endl;
513  __COUT_ERR__ << ss.str();
514  throw std::runtime_error(ss.str());
515  }
516 }
517 
518