otsdaq_utilities  v2_05_02_indev
SmartLaunch.js
1 
2 
3 
4  // Description of Smart Launch Functionality/Behavior:
5  //
6  // Checkboxes on left to select detector systems to include
7  // Giant button on right to launch
8  //
9  // Launch means:
10  // - enable associated contexts
11  // - save new context group, activate (do not alias)
12  // - save user active sessions
13  // - relaunch otsdaq normal mode
14  // - load active sessions
15  // - detect in GUI that system is back alive
16 
17 //User note:
18 // Users can define special launch context groupings by defining
19 // global variables: SmartLaunch.subsystems and SmartLaunch.systemToContextMap.
20 // This is demonstrated in otsdaq_demo/UserWebGUI/html/SmartLaunch.html
21 //
22 // In short, subsystems make up your configuration, and subsystems consist
23 // of one or many context records.
24 
25 
26 //Smart Launch desktop icon from:
27 // http://icons.iconarchive.com/icons/bokehlicia/captiva/256/rocket-icon.png
28 
29 
30 var SmartLaunch = SmartLaunch || {}; //define SmartLaunch namespace
31 
32 if (typeof Debug == 'undefined')
33  throw('ERROR: Debug is undefined! Must include Debug.js before SmartLaunch.js');
34 else if (typeof Globals == 'undefined')
35  throw('ERROR: Globals is undefined! Must include Globals.js before SmartLaunch.js');
36 
37 SmartLaunch.MENU_PRIMARY_COLOR = "rgb(220, 187, 165)";
38 SmartLaunch.MENU_SECONDARY_COLOR = "rgb(130, 51, 51)";
39 
40 
41 SmartLaunch.launcher; //this is THE SmartLaunch variable
42 SmartLaunch.doShowContexts = false; //default value for showing contexts or not
43 SmartLaunch.subsystems = [];
44 // _NAME_STRIPS,
45 // _NAME_MWPC,
46 // _NAME_NIMPLUS
47 // ];
48 SmartLaunch.systemToContextMap = {};
49 // SmartLaunch.systemToContextMap[_NAME_STRIPS] = [
50 // "StripTelescopeContext"
51 // ];
52 // SmartLaunch.systemToContextMap[_NAME_MWPC] = [
53 // "WireChamberContext",
54 // "ARTDAQBoardReader0",
55 // "ARTDAQEventBuilder0",
56 // "ARTDAQEventBuilder1",
57 // "ARTDAQAggregator0"
58 // ];
59 // SmartLaunch.systemToContextMap[_NAME_NIMPLUS] = [
60 // "NimPlusContext"
61 // ];
62 
65 //call create to create instance of a SmartLaunch
68 SmartLaunch.create = function() {
69 
70 
71  //functions:
72  //
73  // init()
74  // createElements()
75  // redrawWindow()
76  // readEnabledSubsystems()
77  // getCurrentState()
78  // - localGetStateHandler()
79  // displayState()
80  //
81  // this.launch()
82  // - localLaunch()
83  // - localSetSequenceOfRecords()
84  // this.gatewayLaunchOts()
85  // - localDelayedLaunch()
86  // -- localCountDown()
87  // this.run()
88  // - localStop()
89  // - localRun()
90  //
91  // this.toggleCheckboxDiv(i)
92  // this.handleCheckbox(c)
93 
94 
95 
96 
97  //for display
98  var _CHECKBOX_H = 40;
99  var _CHECKBOX_MIN_W = 240;
100  var _CHECKBOX_MAX_W = 540;
101  var _LAUNCH_MIN_W = 525;
102  var _MARGIN = 40;
103 
104 
105  var _needEventListeners = true;
106 
107  var _subsetBasePath = "XDAQContextTable";
108 
109  var _systemStatusArray = [];
110  var _contextRecords = [];
111 
112 
113 
114  //for run state
115  var _state = "";
116  var _inTransition = false;
117  var _wasInTransition = false;
118  var _timeInState = 0;
119  var _transitionPercentComplete = 0;
120  var _runNumber;
121  var _transitionName = "";
122 
123  var _fsmName, _fsmWindowName;
124  var _getStateTimer = 0;
125  var _runFSMTimer = 0;
126 
127  var _running = false;
128  var _runStatusDiv;
129 
132  // end variable declaration
133  SmartLaunch.launcher = this;
134  Debug.log("SmartLaunch.launcher constructed");
135 
136  init();
137  Debug.log("SmartLaunch.launcher initialized");
138 
139 
140  //=====================================================================================
141  //init ~~
142  function init()
143  {
144  var windowTooltip = "Welcome to the Smart Launch user interface. " +
145  "Select which pieces of the configuration you want to enable, and then press the launch button!" +
146  "\n\n" +
147  "Once the pieces you want are enabled, press the run button!";
148  Debug.log("Smart Launch init ");
149  DesktopContent.tooltip("Smart Launch", windowTooltip);
150  DesktopContent.setWindowTooltip(windowTooltip);
151 
152  //get all existing contexts
153  ConfigurationAPI.getSubsetRecords(
154  _subsetBasePath,
155  "",//filterList,
156  localGetContextRecordsHandler
157  );
158 
159  //get run state always
160  window.clearTimeout(_getStateTimer);
161  _getStateTimer = window.setTimeout(getCurrentState,1000); //in 1 sec
162 
163  return;
164 
166  function localGetContextRecordsHandler(records)
167  {
168  //extract context records
169  console.log(records);
170  _contextRecords = records;
171 
172  //proceed with rest of init
173  createElements();
174 
175  if(_needEventListeners)
176  {
177  window.addEventListener("resize",redrawWindow);
178  _needEventListeners = false;
179  }
180 
181  //redrawWindow();
182  readEnabledSubsystems();
183  }
184 
185 
186  } //end init()
187 
188  //=====================================================================================
189  //createElements ~~
190  // called initially to create checkbox and button elements
191  function createElements()
192  {
193  Debug.log("createElements");
194 
195 
196  // <!-- body content populated by javascript -->
197  // <div id='content'>
198  // <div id='refreshLink'><a onclick='init()'>Refresh</a></div>
199  //
200  // <div id='subsystemDiv'><div id='subsystemDivContainer'></div></div>
201  //
202  // <a id='launchLink' onclick='SmartLaunch.launcher.launch()'>
203  // <div id='launchDiv'>Launch</div>
204  // </a>
205  //
206  // <a id='runLink' onclick='SmartLaunch.launcher.run()'>
207  // <div id='runDiv'>Run</div>
208  // </a>
209  //
210  // <div id='runStatusDiv' style='top:10px;/*default to 10px for case when someone else has lock*/'></div>
211  //
212  // </div>
213 
214  var cel,el,al,sl;
215 
216  cel = document.getElementById("content");
217  if(!cel)
218  {
219  cel = document.createElement("div");
220  cel.setAttribute("id","content");
221  }
222 
223  //clear all elements
224  cel.innerHTML = "";
225 
226 
227  { //content div
228 
229 
230  //subsystem div
231  sl = document.createElement("div");
232  sl.setAttribute("id","subsystemDiv");
233  el = document.createElement("div");
234  el.setAttribute("id","subsystemDivContainer");
235  sl.appendChild(el);
236  cel.appendChild(sl);
237 
238 
239 
240  //launch link
241  al = document.createElement("a");
242  al.setAttribute("id","launchLink");
243  al.onclick = function()
244  {
245  Debug.log("clicked launch");
246  SmartLaunch.launcher.launch();
247  };
248 
249  el = document.createElement("div");
250  el.setAttribute("id","launchDiv");
251  el.innerHTML = "Launch";
252  al.appendChild(el);
253  cel.appendChild(al);
254 
255  //run link
256  al = document.createElement("a");
257  al.setAttribute("id","runLink");
258  al.onclick = function()
259  {
260  Debug.log("clicked run");
261  SmartLaunch.launcher.run();
262  };
263 
264  el = document.createElement("div");
265  el.setAttribute("id","runDiv");
266  el.innerHTML = "Run";
267  al.appendChild(el);
268  cel.appendChild(al);
269 
270  //run status
271  sl = document.createElement("div");
272  sl.setAttribute("id","runStatusDiv");
273  sl.style.top = "10px"; //default to 10px for case when someone else has lock
274  cel.appendChild(sl);
275 
276  }
277 
278 
279 
280 
281 
282 
283  document.body.appendChild(cel);
284 
285 
286  } //end createElements()
287 
288  //=====================================================================================
289  //readEnabledSubsystems ~~
290  // call redrawWindow when complete
291  function readEnabledSubsystems()
292  {
293  try
294  {
295  Debug.log("readEnabledSubsystems");
296 
297  var recordsArray = [];
298 
299  for(var i=0; i<SmartLaunch.subsystems.length; ++i)
300  {
301  for(var j=0; j<SmartLaunch.systemToContextMap[SmartLaunch.subsystems[i]].length; ++j)
302  recordsArray.push(SmartLaunch.systemToContextMap[SmartLaunch.subsystems[i]][j]);
303  }
304  if(SmartLaunch.doShowContexts)
305  for(var i=0; i<_contextRecords.length; ++i)
306  recordsArray.push(_contextRecords[i]);
307 
308  console.log("recordsArray",recordsArray);
309 
310  ConfigurationAPI.getFieldValuesForRecords(
311  _subsetBasePath,
312  recordsArray,
313  ["Status"],
314  localStatusForRecordsHandler
315  );
316  return;
317  }
318  catch(e)
319  {
320  Debug.log("There was error reading the status of the configuration subsystems (" +
321  "were the subsystem variables setup properly?):[" + DesktopContent.getExceptionLineNumber(e) + "]: " +
322  e, Debug.HIGH_PRIORITY);
323  return;
324  }
325 
327  function localStatusForRecordsHandler(recFieldValues)
328  {
329  Debug.log("localStatusForRecordsHandler value-length=" + recFieldValues.length)
330  var statusArray = []; //clear
331  for(var i in recFieldValues)
332  statusArray.push(
333  recFieldValues[i].fieldValue == "On"?true:false);//recFieldValues[i].fieldUID .. recFieldValues[i].fieldPath + ": " +
334 
335  console.log("statusArray",statusArray);
336 
337  _systemStatusArray = []; //clear
338  var k=0;
339  for(var i=0; i<SmartLaunch.subsystems.length; ++i)
340  {
341  _systemStatusArray.push(true);
342  for(var j=0; j<SmartLaunch.systemToContextMap[SmartLaunch.subsystems[i]].length; ++j,++k)
343  if(!statusArray[k]) //found one off exception
344  _systemStatusArray[i] = false; //so consider entire subsystem off
345  }
346  if(SmartLaunch.doShowContexts)
347  for(var i=0; i<_contextRecords.length; ++i, ++k)
348  _systemStatusArray.push(statusArray[k]);
349 
350  console.log("_systemStatusArray",_systemStatusArray);
351 
352  redrawWindow();
353 
354  } //end localStatusForRecordsHandler()
355 
356 
357  } //end readEnabledSubsystems()
358 
359 
360  //=====================================================================================
361  //redrawWindow ~~
362  // called when page is resized
363  function redrawWindow()
364  {
365  //adjust link divs to proper size
366  // use ratio of new-size/original-size to determine proper size
367 
368  var w = window.innerWidth | 0;
369  var h = window.innerHeight | 0;
370 
371  if(w < _LAUNCH_MIN_W)
372  w = _LAUNCH_MIN_W;
373  if(h < _LAUNCH_MIN_W)
374  h = _LAUNCH_MIN_W;
375 
376  Debug.log("redrawWindow to " + w + " - " + h);
377 
378  var sdiv = document.getElementById("subsystemDiv");
379  var ldiv = document.getElementById("launchDiv");
380  var rdiv = document.getElementById("runDiv");
381  _runStatusDiv = runStatusDiv = document.getElementById("runStatusDiv");
382 
383  var chkH = _CHECKBOX_H;
384  var chkW = (w/3)|0;
385  if(chkW < _CHECKBOX_MIN_W) chkW = _CHECKBOX_MIN_W;
386  if(chkW > _CHECKBOX_MAX_W) chkW = _CHECKBOX_MAX_W;
387 
388  var sdivH = 66 + chkH*SmartLaunch.subsystems.length; //header + chkboxes
389 
390  if(SmartLaunch.doShowContexts)
391  {
392  sdivH += 66 + chkH*_contextRecords.length; //header + chkboxes
393  }
394  if(sdivH > 2/3*h)
395  sdivH = 2/3*h; //clip height
396  if(sdivH < 100)
397  sdivH = 100; //clip min
398 
399  var sdivW = chkW;
400 
401  var sdivX = _MARGIN;
402  var sdivY = (h-sdivH)/2;
403  if(sdivY < _MARGIN)
404  sdivY = _MARGIN;
405 
406 // var ldivX = _MARGIN + chkW;
407 // var ldivSz = h;
408 // if(ldivSz > w - ldivX - _MARGIN*3) //pick min of w/h
409 // ldivSz = w - ldivX - _MARGIN*3;
410 // if(ldivSz < 120) //clip min
411 // ldivSz = 120;
412 // var ldivY = (h-ldivSz)/2;
413 //
414 // var rdivX = _MARGIN + chkW;
415 // var rdivSz = ldivSz;
416 // var rdivY = ldivY + ldivSz;
417 // var rratio = 180/300;
418 
419  var ldivX = _MARGIN + chkW;
420  var ldivSz = h/2;
421  if(ldivSz > w - ldivX - _MARGIN*3) //pick min of w/h
422  ldivSz = w - ldivX - _MARGIN*3;
423  ldivSz *= 0.9;
424  var ldivY = (h-ldivSz)/2 - ldivSz/2;
425  var lratio = 180/300;
426 
427  var rdivX = _MARGIN + chkW;
428  var rdivSz = ldivSz;
429  var rdivY = ldivY + ldivSz;
430  var rratio = 180/300;
431 
432 
433  //draw checkboxes
434  {
435  var str = "";
436  var statusIndex = 0;
437 
438  var hideableSubsystems = SmartLaunch.subsystems.length && SmartLaunch.doShowContexts;
439  var hideableContexts = SmartLaunch.subsystems.length;
440 
441  if(SmartLaunch.subsystems.length)
442  {
443  if(hideableSubsystems)
444  str += "<a onclick='SmartLaunch.launcher.toggleCheckboxDiv(0);' title='Hide/Show Subsystems'>";
445  str += "<h3>Subsystems</h3>";
446  if(hideableSubsystems)
447  str += "</a>";
448 
449  str += "<div id='ssCheckboxDiv'>";
450  for(var i=0;i<SmartLaunch.subsystems.length;++i,++statusIndex)
451  {
452  str += "<div class='ssCheckbox' style='height:" + chkH + "px;" +
453  "' >";
454  str += "<div class='pretty p-icon p-round p-smooth' onclick='SmartLaunch.launcher.handleCheckbox(" +
455  statusIndex + ");' >"; //p-smooth for slow transition
456  str += " <input type='checkbox' class='subsystemCheckboxes' " +
457  (_systemStatusArray[statusIndex]?"checked":"") +
458  "/>";
459  str += "<div class='state p-success'>";
460  str += "<i class='icon mdi mdi-check'></i>";
461  str += "<label>" + SmartLaunch.subsystems[i] + "</label>";
462  str += "</div>";
463  str += "</div>";
464  str += "</div>";
465  str += "<div id='clearDiv'></div>";
466  }
467  str += "</div>";
468  }
469  else if(!SmartLaunch.doShowContexts)
470  {
471  str += "No subsystem configuration definition found.";
472  }
473 
474 
475  if(SmartLaunch.doShowContexts)
476  {
477  if(hideableContexts)
478  str += "<a onclick='SmartLaunch.launcher.toggleCheckboxDiv(1);' title='Hide/Show Contexts'>";
479  str += "<h3>Individual Contexts</h3>";
480  if(hideableContexts)
481  str += "</a>";
482 
483  if(!_contextRecords.length)
484  str += "No contexts found.";
485 
486 
487  str += "<div id='ctxCheckboxDiv'>";
488  for(var i=0; i<_contextRecords.length; ++i,++statusIndex)
489  {
490  str += "<div class='ssCheckbox' style='height:" + chkH + "px;" +
491  "' >";
492  str += "<div class='pretty p-icon p-round p-smooth' onclick='SmartLaunch.launcher.handleCheckbox(" +
493  statusIndex + ");' >"; //p-smooth for slow transition
494  str += " <input type='checkbox' class='subsystemCheckboxes' " +
495  (_systemStatusArray[statusIndex]?"checked":"") +
496  "/>";
497  str += "<div class='state p-success'>";
498  str += "<i class='icon mdi mdi-check'></i>";
499  str += "<label>" + _contextRecords[i] + "</label>";
500  str += "</div>";
501  str += "</div>";
502  str += "</div>";
503  str += "<div id='clearDiv'></div>";
504  }
505  str += "</div>"
506  }
507 
508 
509  sdiv.style.left = (sdivX-20) + "px";
510  sdiv.style.top = sdivY + "px";
511  sdiv.style.height = sdivH + "px";
512  sdiv.style.width = sdivW + "px";
513  sdiv.style.display = "block";
514 
515 
516  sdiv = document.getElementById("subsystemDivContainer");
517  sdiv.style.left = (sdivX-20) + "px";
518  sdiv.style.top = sdivY + "px";
519  sdiv.style.height = sdivH + "px";
520  sdiv.style.width = sdivW + "px";
521  sdiv.innerHTML = "";
522  sdiv.innerHTML = str;
523  sdiv.style.display = "block";
524  }
525 
526  //draw launch button
527  {
528 
529 // ldiv.style.left = (ldivX + (w - ldivX - _MARGIN*2 - ldivSz)/2) + "px";
530 // ldiv.style.top = (ldivY+((ldivSz-ldivSz*200/300)/2)) + "px";
531 //
532 // ldiv.style.width = ldivSz + "px";
533 // var fontSize = ldivSz/10;
534 // if(fontSize < 30) fontSize = 30;
535 // ldiv.style.fontSize = (fontSize) + "px";
536 // ldiv.style.paddingTop = (ldivSz*200/300/2 - (fontSize+6)/2) + "px"; //ratio of size minus font size
537 // ldiv.style.paddingBottom = (ldivSz*200/300/2- (fontSize+6)/2) + "px";
538 // ldiv.style.borderRadius = (ldivSz*300/100) + "px/" + (ldivSz*200/100) + "px";
539 //
540 // ldiv.style.display = "block";
541  ldiv.style.left = (ldivX + (w - ldivX - _MARGIN*2 - ldivSz)/2) + "px";
542  ldiv.style.top = (ldivY+((ldivSz-ldivSz*lratio)/2)) + "px";
543  //ldiv.style.height = (ldivSz*200/300) + "px";
544  ldiv.style.width = ldivSz + "px";
545  ldiv.style.paddingTop = (ldivSz*lratio/2 - 36/2) + "px"; //ratio of size minus font size
546  ldiv.style.paddingBottom = (ldivSz*lratio/2- 36/2) + "px";
547  //ldiv.style.paddingLeft = (ldivSz/2) + "px";
548  //ldiv.style.paddingRight = (ldivSz/2) + "px";
549 
550  ldiv.style.borderRadius = ldivSz + "px/" + (ldivSz*200/300) + "px";
551  ldiv.style.fontSize = ldivSz/10 + "px";
552 
553  ldiv.style.display = "block";
554  }
555 
556 
557  //draw run button
558  {
559 
560  rdiv.style.left = (rdivX + (w - rdivX - _MARGIN*2 - rdivSz)/2) + "px";
561  rdiv.style.top = (rdivY+((rdivSz-rdivSz*rratio)/2)) + "px";
562  //rdiv.style.height = (rdivSz*200/300) + "px";
563  rdiv.style.width = rdivSz + "px";
564  rdiv.style.paddingTop = (rdivSz*rratio/2 - 36/2) + "px"; //ratio of size minus font size
565  rdiv.style.paddingBottom = (rdivSz*rratio/2- 36/2) + "px";
566  //rdiv.style.paddingLeft = (rdivSz/2) + "px";
567  //rdiv.style.paddingRight = (rdivSz/2) + "px";
568 
569  rdiv.style.borderRadius = rdivSz + "px/" + (rdivSz*200/300) + "px";
570  rdiv.style.fontSize = rdivSz/10 + "px";
571 
572  rdiv.style.display = "block";
573  //ldiv.innerHTML = str;
574 
575  runStatusDiv.style.left = (rdivX + _MARGIN + (w - rdivX - _MARGIN*2 - rdivSz)/2) + "px";
576  runStatusDiv.style.top = (h/2 - 50) + "px";
577  runStatusDiv.style.width = (rdivSz + _MARGIN) + "px";
578  runStatusDiv.style.fontSize = rdivSz/15 + "px";
579  }
580 
581  } //end redrawWindow()
582 
583 
584  //=====================================================================================
585  //getCurrentState ~~
586  function getCurrentState()
587  {
588  window.clearTimeout(_getStateTimer);
589 
590  DesktopContent.XMLHttpRequest("Request?RequestType=getCurrentState" +
591  "&fsmName=" + _fsmName,
592  "",
593  localGetStateHandler,/*returnHandler*/
594  0 /*reqParam*/,
595  0 /*progressHandler*/,
596  0 /*callHandlerOnErr*/,
597  true /*doNotShowLoadingOverlay*/,
598  true /*targetSupervisor*/,
599  true /*ignoreSystemBlock*/);
600 
601  //===========
602  function localGetStateHandler(req,id,err)
603  {
604  if(!req) //error! stop handler
605  {
606  Debug.log("Error: " + err, Debug.HIGH_PRIORITY);
607  return;
608  }
609 
610 
611  _state = DesktopContent.getXMLValue(req,"current_state");
612  _inTransition = DesktopContent.getXMLValue(req,"in_transition") == "1";
613  _timeInState = DesktopContent.getXMLValue(req,"time_in_state") | 0;
614  _runNumber = DesktopContent.getXMLValue(req,"run_number");
615  _transitionPercentComplete = DesktopContent.getXMLValue(req,"transition_progress") | 0;
616 
617  if(_transitionPercentComplete > 100)
618  {
619  //Debug.log("???" + _transitionPercentComplete);
620  _transitionPercentComplete = 100;
621  }
622 
623 
624  //Debug.log("localGetStateHandler: " + _state + " -- " + _inTransition +
625  // " -- t" + _timeInState + " " + _transitionPercentComplete + "%");
626 
627 
628 
629  displayState();
630 
631 
632  //on success, get state again
633  window.clearTimeout(_getStateTimer);
634  _getStateTimer = window.setTimeout(getCurrentState,1000); //in 1 sec
635  }
636  } //getCurrentState
637 
638 
639  //=====================================================================================
640  //displayState ~~
641  function displayState()
642  {
643  //Debug.log("displayState");
644 
645  //update display
646 
647  //indicate running if detected
648  if(_state == "Running")
649  {
650  if(!_running)
651  {
652  _running = true;
653  document.getElementById("runDiv").innerHTML = "Stop";
654  }
655  }
656  else //not running
657  {
658  if(_running)
659  {
660  _running = false;
661  document.getElementById("runDiv").innerHTML = "Run";
662  }
663  }
664 
665 
666  let str = "";
667  str += "<table cellspacing='0' cellpadding='0'>";
668 
669  //current state display
670  if(_inTransition)
671  str += "<tr><td style='font-weight: bold; padding-right:20px;'>Transition:</td><td>" +
672  _transitionName + "</td></tr>";
673  else
674  str += "<tr><td style='font-weight: bold; padding-right:20px;'>Current State:</td><td>" +
675  _state + "</td></tr>";
676 
677 
678 
679  //current run number display
680  if(//_state == "Running" &&
681  _runNumber)
682  {
683  //extract run number components
684  let i = _runNumber.lastIndexOf(' ');
685  if(i >= 0)
686  {
687  let hdr = _runNumber.substr(0,i);
688  let num = _runNumber.substr(i+1);
689  stateStr = "Running <br>&nbsp;&nbsp;&nbsp;&nbsp;" + _runNumber;
690  str += "<tr><td style='font-weight: bold; padding-right:20px;'>" +
691  hdr + "</td><td>" +
692  num + "</td></tr>";
693  }
694  }
695 
696 
697 
698  //transitioning display
699  let progressStr = "";
700  if(_inTransition)
701  {
702  progressStr = _transitionPercentComplete + " %";
703 
704  str += "<tr><td style='font-weight: bold; padding-right:20px;'>Progress:</td><td>" +
705  progressStr + "</td></tr>";
706 
707  if(!_wasInTransition)
708  _wasInTransition = true;
709  }
710  else if(_wasInTransition)
711  {
712  //show 100% once to show some display
713  _wasInTransition = false;
714  progressStr = 100 + " %";
715 
716  str += "<tr><td style='font-weight: bold; padding-right:20px;'>Transitioning:</td><td>" +
717  progressStr + "</td></tr>";
718  }
719  else
720  {
721  //time in state display
722  let tstr = "";
723  var hours = (_timeInState/60.0/60.0)|0;
724  var mins = ((_timeInState%(60*60))/60.0)|0;
725  var secs = _timeInState%60;
726 
727  tstr += hours + ":";
728  if(mins < 10) tstr += "0"; //keep to 2 digits
729  tstr += mins + ":";
730  if(secs < 10) tstr += "0"; //keep to 2 digits
731  tstr += secs ;
732 
733  str += "<tr><td style='font-weight: bold; padding-right:20px;'>Time-in-State:</td><td>" + tstr + "</td></tr>";
734  }
735 
736  try //in case no display
737  {
738  _runStatusDiv.innerHTML = str;
739 
740  _runStatusDiv.style.display = "block";
741  }
742  catch(e) {console.log(":[" + DesktopContent.getExceptionLineNumber(e) + "]: " + e);}
743  } //end displayState()
744 
745  //=====================================================================================
746  //launch ~~
747  this.launch = function()
748  {
749  Debug.log("launch");
750  DesktopContent.popUpVerification(
751  "Are you sure you want to relaunch otsdaq?",
752  localLaunch,
753  0,"#efeaea",0,"#770000");
754 
755  //============
756  function localLaunch()
757  {
758  Debug.log("localLaunch");
759 
760  var checkboxes = document.getElementsByClassName('subsystemCheckboxes');
761  console.log("checkboxes",checkboxes);
762  var checkedArray = [];
763  for(var i=0;i<checkboxes.length;++i)
764  checkedArray.push(checkboxes[i].checked);
765  console.log("checkedArray",checkedArray);
766 
767  var recordsArray = [];
768  var valuesArray = [];
769 
770  //assemble records array
771 
772  if(SmartLaunch.doShowContexts)
773  {
774  //just use context checkbox settings
775  for(var i=0; i<_contextRecords.length; ++i)
776  {
777  recordsArray.push(_contextRecords[i]);
778  valuesArray.push(checkedArray[SmartLaunch.subsystems.length+i]?
779  "1":"0");
780  }
781  }
782  else
783  {
784  //extract context settings from system to context map
785  for(var i=0; i<SmartLaunch.subsystems.length; ++i)
786  {
787  for(var j=0; j<SmartLaunch.systemToContextMap[SmartLaunch.subsystems[i]].length; ++j)
788  {
789  recordsArray.push(SmartLaunch.systemToContextMap[SmartLaunch.subsystems[i]][j]);
790  valuesArray.push(checkedArray[i]?"1":"0");
791 
792  }
793  }
794  }
795  console.log("recordsArray",recordsArray);
796  console.log("valuesArray",valuesArray);
797 
798  var recordIndex = 0;
799  var localModifiedTables = undefined;
800  //sequentially send request for each record until done
801  localSetSequenceOfRecords();
802 
803  //===========================
804  function localSetSequenceOfRecords()
805  {
806  ConfigurationAPI.setFieldValuesForRecords(
807  _subsetBasePath,
808  recordsArray[recordIndex],
809  "Status", //fieldArr
810  valuesArray[recordIndex], //valueArr
811  function(modifiedTables)
812  {
813  Debug.log("recordIndex = " + recordIndex);
814 
815  if(modifiedTables.length == 0)
816  {
817  Debug.log("Something went very wrong. Notify administrators.",
818  Debug.HIGH_PRIORITY);
819  return;
820  }
821 
822  ++recordIndex;
823  if(recordIndex == recordsArray.length)
824  {
825  Debug.log("Done with sequence.");
826 
827  //proceed to save (quietly) tables, groups, aliases
828  ConfigurationAPI.saveModifiedTables(modifiedTables,
830  function(savedTables, savedGroups, savedAliases)
831  {
832  if(!savedTables.length)
833  {
834  Debug.log("Something went very wrong. Notify administrators.",
835  Debug.HIGH_PRIORITY);
836  return;
837  }
838 
839  Debug.log("Successfully applied subsystem selections!", Debug.INFO_PRIORITY);
840 
841 
842  //relaunch
843  Debug.log("Relaunching ots...");
844  SmartLaunch.launcher.gatewayLaunchOts();
845 
846 
847  }); //end saveModifiedTables handler
848  return;
849  }
850 
851  console.log("setFieldValuesForRecords modifiedTables",modifiedTables);
852  localModifiedTables = modifiedTables;
853  localSetSequenceOfRecords();
854 
855  } //end setFieldValuesForRecords handler
856  ,localModifiedTables);
857  } //end localSetSequenceOfRecords()
858  }
859  } // end launch()
860 
861  //=====================================================================================
862  //gatewayLaunchOts ~~
863  this.gatewayLaunchOts = function()
864  {
865  Debug.log("Relaunching otsdaq!",Debug.INFO_PRIORITY);
866 
867  //block checks
868  window.clearTimeout(_getStateTimer);
869 
870  //start blackout
871  DesktopContent.systemBlackout(true);
872  //DesktopContent._blockSystemCheckMailbox.innerHTML = "1";
873  window.setTimeout(localDelayedLaunch,1000); //gaurantee blackout starts
874  //now in all future requests must ignoreSystemBlock
875 
876  //===========
877  function localDelayedLaunch()
878  {
879  DesktopContent.XMLHttpRequest("Request?" +
880  "RequestType=gatewayLaunchOTS", //end get data
881  "", //end post data
882  function(req) //start handler
883  {
884  Debug.log("gatewayLaunchOts handler ");
885 
886 
887  var countDown = 10;
888  localCountDown();
889  //=================
890  function localCountDown()
891  {
892  Debug.log("Waiting " + countDown + " seconds for startup sequence...",
893  Debug.INFO_PRIORITY);
894 
895  window.setTimeout(function() {
896  Debug.log("localCountDown handler ");
897  --countDown;
898  if(countDown == 0)
899  {
900  //end blackout
901  DesktopContent.systemBlackout(false);
902  //DesktopContent._blockSystemCheckMailbox.innerHTML = "";
903  init();
904  Debug.log("And we are back!",Debug.INFO_PRIORITY);
905  return;
906  }
907  localCountDown();
908  }, //end blackout-end handler
909  1000/*ms*/);
910  }// end localCountDown
911 
912  }, //end gatewayLaunchOTS req handler
913  0, //handler param
914  0,0,false, //progressHandler, callHandlerOnErr, doNotShowLoadingOverlay
915  true /*targetSupervisor*/, true /*ignoreSystemBlock*/);
916  } // end localDelayedLaunch()
917 
918  } //end gatewayLaunchOts()
919 
920 
921  //=====================================================================================
922  //run ~~
923  this.run = function()
924  {
925  Debug.log("run");
926 
927  var timeoutCount = 0; //used to detect taking too long
928  var operativeWord = "starting";
929  var lastState = "";
930 
931  if(_running)
932  {
933  DesktopContent.popUpVerification(
934  "Are you sure you want to stop the run?",
935  localStop,
936  0,"#efeaea",0,"#770000");
937 
938  //===========
939  function localStop()
940  {
941  Debug.log("localStop");
942  //just change operative word and run (to stop)
943  operativeWord = "stopping";
944  localRun();
945  }
946  return;
947  }
948 
949  DesktopContent.popUpVerification(
950  "Are you sure you want to start a run?",
951  localRun,
952  0,"#efeaea",0,"#770000");
953 
954  //===========
955  function localRun()
956  {
957  Debug.log("localRun");
958 
959  window.clearTimeout(_runFSMTimer);
960 
961  ++timeoutCount;
962  if(timeoutCount > 60) //if it has been one minute, too long
963  {
964  Debug.log("Timeout reached! Giving up on " + operativeWord + " the run.", Debug.HIGH_PRIORITY);
965  return;
966  }
967 
968  if(_inTransition) //wait
969  {
970  window.clearTimeout(_getStateTimer);
971  _getStateTimer = window.setTimeout(getCurrentState,1000); //in 1 sec
972 
973  window.clearTimeout(_runFSMTimer);
974  _runFSMTimer = window.setTimeout(localRun,1000); //wait a sec
975  return;
976  }
977 
978  if(lastState == _state)
979  {
980  Debug.log("State machine is not progressing! Stuck in '" +
981  _state + ".' Giving up on " + operativeWord + " the run.", Debug.HIGH_PRIORITY);
982  return;
983  }
984 
985  lastState = _state;
986 
987  let transitionPostData = "";
988  //keep transitioning to Run state
989  if(_state == "Initial")
990  {
991  _transitionName = "Initialize";
992  }
993  else if(_state == "Failed")
994  {
995  if(timeoutCount > 1)
996  {
997  //if localRun activity caused failure, give up
998  Debug.log("Fault encountered! Giving up on " + operativeWord + " the run.", Debug.HIGH_PRIORITY);
999  return;
1000  }
1001  _transitionName = "Halt";
1002  }
1003  else if(_state == "Halted")
1004  {
1005  _transitionName = "Configure";
1006  //FIXME -- could get system alias from somewhere (e.g. first alias in list, or icon parameter)
1007  transitionPostData = "ConfigurationAlias=" + "defaultSystemAlias";
1008  }
1009  else if(_state == "Configured")
1010  {
1011  if(operativeWord == "stopping")
1012  {
1013  //done!
1014  Debug.log("<i>otsdaq</i> has now Stopped! " +
1015  _runNumber + ".", Debug.INFO_PRIORITY);
1016  return;
1017  }
1018 
1019  _transitionName = "Start";
1020  }
1021  else if(_state == "Paused")
1022  {
1023  _transitionName = "Start";
1024  }
1025  else if(_state == "Running")
1026  {
1027  if(operativeWord == "stopping")
1028  {
1029  _transitionName = "Stop";
1030  }
1031  else //starting
1032  {
1033  //done!
1034  Debug.log("<i>otsdaq</i> is now Running! " +
1035  _runNumber + ".", Debug.INFO_PRIORITY);
1036  return;
1037  }
1038  }
1039  else
1040  {
1041  Debug.log("Unknown action for current state '" + _state + "'..." +
1042  "Giving up on " + operativeWord + " the run.", Debug.HIGH_PRIORITY);
1043  return;
1044  }
1045 
1046  _inTransition = true;
1047  _transitionPercentComplete = 0;
1048 
1049  displayState();
1050 
1051  Debug.log("_transitionName = " + _transitionName +
1052  " transitionPostData = " + transitionPostData);
1053 
1054  DesktopContent.XMLHttpRequest("StateMachineXgiHandler?StateMachine=" +
1055  _transitionName +
1056  "&fsmName=" + _fsmName +
1057  "&fsmWindowName=" + _fsmWindowName,
1058  transitionPostData,
1059  //===========
1060  function(req)
1061  {
1062 
1063  var success = DesktopContent.getXMLValue(req,"state_tranisition_attempted") == "1";
1064  if(!success)
1065  {
1066  var err = DesktopContent.getXMLValue(req,"state_tranisition_attempted_err");
1067  if(err)
1068  Debug.log(err,Debug.HIGH_PRIORITY);
1069  Debug.log("Server indicated failure to attempt state transition. " +
1070  "Giving up on " + operativeWord + " the run.",Debug.HIGH_PRIORITY);
1071  return;
1072  }
1073 
1074  //on success continue..
1075  window.clearTimeout(_runFSMTimer);
1076  _runFSMTimer = window.setTimeout(localRun,3000); //wait 3 seconds before doing anything
1077  }, // end handler
1078  0, //handler param
1079  0,0,true, //progressHandler, callHandlerOnErr, doNotShowLoadingOverlay
1080  true /*targetSupervisor*/);
1081 
1082  }
1083 
1084  } //end run()
1085 
1086  //=====================================================================================
1087  //toggleCheckboxDiv(i) ~~
1088  this.toggleCheckboxDiv = function(i)
1089  {
1090  Debug.log("toggleCheckboxDiv(i) " + i);
1091 
1092  var el;
1093  if(i == 0) //toggle subsystems
1094  {
1095  el = document.getElementById("ssCheckboxDiv");
1096  el.style.display = (el.style.display == "none")?"block":"none";
1097  }
1098  else if(i == 1) //toggle contextx
1099  {
1100  el = document.getElementById("ctxCheckboxDiv");
1101  el.style.display = (el.style.display == "none")?"block":"none";
1102  }
1103  else throw("Invalid index checkbox div " + i);
1104  } //end toggleCheckboxDiv()
1105 
1106  //=====================================================================================
1107  //handleCheckbox(i) ~~
1108  this.handleCheckbox = function(c)
1109  {
1110  Debug.log("handleCheckbox(c) " + c);
1111 
1112  var checkboxes = document.getElementsByClassName('subsystemCheckboxes');
1113  console.log("checkboxes",checkboxes);
1114  var checkedArray = [];
1115  for(var i=0;i<checkboxes.length;++i)
1116  checkedArray.push(checkboxes[i].checked);
1117  console.log("checkedArray",checkedArray);
1118 
1119  Debug.log("set to " + checkedArray[c]);
1120 
1121  //create a context map
1122  var contextEnabledMap = {}; //map to [enabled, index]
1123  for(var i=0; i<_contextRecords.length; ++i)
1124  contextEnabledMap[_contextRecords[i]] = [checkedArray[SmartLaunch.subsystems.length+i],
1125  SmartLaunch.subsystems.length+i];
1126 
1127  //update for each context that was just affected
1128  if(c < SmartLaunch.subsystems.length)
1129  {
1130  //dealing with a subsystem
1131  for(var j=0; j<SmartLaunch.systemToContextMap[SmartLaunch.subsystems[c]].length; ++j)
1132  {
1133  //update map
1134  contextEnabledMap[ //context name
1135  SmartLaunch.systemToContextMap[SmartLaunch.subsystems[c]][j]
1136  ][0] = checkedArray[c]; //set to checked value
1137  //and set checkbox
1138  checkboxes[contextEnabledMap[ //context name
1139  SmartLaunch.systemToContextMap[SmartLaunch.subsystems[c]][j]
1140  ][1]].checked = checkedArray[c];
1141  }
1142  }
1143  else
1144  {
1145  //dealing with a context
1146 
1147  //update map
1148  contextEnabledMap[_contextRecords[c - SmartLaunch.subsystems.length]][0] = checkedArray[c]; //set to checked value
1149 
1150  }
1151  console.log("contextEnabledMap",contextEnabledMap);
1152 
1153 
1154  //update all subsystems based on this change
1155  for(var i=0;i<SmartLaunch.subsystems.length;++i)
1156  {
1157  if(i==c) continue; //skip box that was changed
1158 
1159  var enabled = true;
1160  //if any member contexts are disabled then disable subsystem
1161  for(var j=0; j<SmartLaunch.systemToContextMap[SmartLaunch.subsystems[i]].length; ++j)
1162  {
1163  if(!contextEnabledMap[
1164  SmartLaunch.systemToContextMap[SmartLaunch.subsystems[i]][j]][0])
1165  {
1166  enabled = false;
1167  break;
1168  }
1169  }
1170 
1171  //set checkbox
1172  checkboxes[i].checked = enabled;
1173  }
1174 
1175 
1176  } //end handleCheckbox()
1177 
1178 
1179 } //end create() SmartLaunch instance
1180 
1181 
1182 
1183 
1184 
1185 
1186 
1187 
1188 
1189 
1190