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