<style>

.flex-container {
  display: -webkit-flex;
  display: flex;
  }

.ui-slider-range {
   background-image: none;
   background: lightgrey;
   }

th,td {
   font-size:12px;
   }

.patientDataFilterSliderReadout{
   font-size: 10px;
   height:16px;
   }

.ui-tabs .ui-tabs-nav li a{
   font-size:10pt !important;
   }

.ui-button .ui-button-text{
   font-size:10pt !important;
   }


</style>


<!DOCTYPE html> 
<html>

<head>
   <meta charset="UTF-8">
   <title> OncoDev 1.4</title>

   <script src="http://code.jquery.com/qunit/qunit-1.18.0.js"></script>
   <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.18.0.css">

   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/jquery-2.1.3.min.js"></script>
   <!-- script src="http://oncoscape.sttrcancer.org/oncoscape/js/jquery-1.11.2.min.js"></script-->
   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/jquery-ui-1.11.4.min.js"></script>
   <link   rel="stylesheet" type="text/css"
           href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/themes/smoothness/jquery-ui.css">

   <!-- script src="http://oncoscape.sttrcancer.org/oncoscape/js/cytoscape-2.3.10.min.js"></script -->
   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/cytoscape-2.4.4.min.js"></script>

   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/jquery.cytoscape.js-panzoom.js"></script>
   <link   href="http://oncoscape.sttrcancer.org/oncoscape/css/jquery.cytoscape.js-panzoom.css" 
           rel="stylesheet" 
           type="text/css">


   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/d3.min.js"></script>

   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/jquery.dataTables-1.10.5.min.js"></script>
   <link   rel="stylesheet" type="text/css"
           href="http://oncoscape.sttrcancer.org/oncoscape/css/jquery.dataTables-1.10.5.min.css">

   <script src="http://cdn.datatables.net/colvis/1.1.0/js/dataTable.colVis.js"></script>

   <link   rel="stylesheet" type="text/css"
           href="http://cdn.datatables.net/colvis/1.1.0/css/dataTables.colVis.css">

   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/jquery.multi-select.js" type="text/javascript"></script>
   <link href="http://oncoscape.sttrcancer.org/oncoscape/css/multi-select.css" media="screen" rel="stylesheet" type="text/css">
   <script src="http://oncoscape.sttrcancer.org/oncoscape/js/chosen.jquery.min.js" type="text/javascript"></script>
   <link href="http://oncoscape.sttrcancer.org/oncoscape/css/chosen.min.css" media="screen" rel="stylesheet" type="text/css">


<script> 
//--------------------------------------------------------------------------------------------------
// hooks for google analytics

  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
 
  ga('create', 'UA-528883-29', 'auto');
  ga('send', 'pageview');
//--------------------------------------------------------------------------------------------------
</script> 

</head>


<script>
//----------------------------------------------------------------------------------------------------
// These javascript functions and variables are arranged into a simple module so that
// implementation details are kept private from the public API other oncoscape 
// browser modules will use.  common services and utility functions are provided here
//----------------------------------------------------------------------------------------------------
var HubModule = (function () {

  var name = "HubModule";
     // keys are module names, their outermost divs are the values.
     // providing these outermost divs allows was inspired by 
     // the need to allow raising of tabs by the sending tab.
     // TODO: not sure that's still needed

  var selectionDestinations = {};
  var dispatchOptions = {};
  var socketIsConnected = false;
  var socketConnectedFunctions = [];
  var onDocumentReadyFunctions = [];
  var socketURI = window.location.href.replace("http://", "ws://");
  var socket;

  var  messagingRestrictedToLogin = false;

  var modules = {};
//----------------------------------------------------------------------------------------------------
function registerModule(name, moduleObject)
{
   modules[name] = moduleObject;

} // registerModule
//----------------------------------------------------------------------------------------------------
function getModules()
{
   return modules;

} // getModules
//----------------------------------------------------------------------------------------------------
// TODO: add 3rd argument: acceptsIncomingMessages
//       datasets, for instance, seems to have no need for incoming json/websocket messages
function registerSelectionDestination(names, outermostDivID)
{
  if(typeof(names) == "string")
    names = [names];

  for(var i=0; i < names.length; i++)
     selectionDestinations[names[i]] = outermostDivID;

} // registerSelectionDestination
//----------------------------------------------------------------------------------------------------
function getRegisteredSelectionDestinations()
{
  return(selectionDestinations);

} // getRegisteredSelectionDestinations
//----------------------------------------------------------------------------------------------------
function setupSocket(socket)
{
  console.log("=== Module.hub setupSocket");

  try {
     socket.onopen = function() {
        console.log("websocket connection now open");
        socketIsConnected = true;
        for(var f=0; f < socketConnectedFunctions.length; f++){
           console.log("calling the next sockectConnectedFunction");
           socketConnectedFunctions[f]();
           } // for f
        } // socked.onopen

     socket.onmessage = function got_packet(msg) {
        //console.log("=== Hub, socket.onmessage");
        var msg = JSON.parse(msg.data)
        dispatchMessage(msg)
        } // socket.onmessage, got_packet

     socket.onclose = function(){
        console.log("socket closing");
        } // socket.onclose
     } // try
  catch(exception) {
    console.log("Error: " + exception);
    }
 
  return(socket);

} // setupSocket
//----------------------------------------------------------------------------------------------------
function socketConnected()
{
   return(socketIsConnected);

} // socketConnected
//----------------------------------------------------------------------------------------------------
function addSocketConnectedFunction(func)
{
   socketConnectedFunctions.push(func)

} // addSocketConnectedFunction
//----------------------------------------------------------------------------------------------------
function getSocketConnectedFunctions()
{
   return(socketConnectedFunctions)

} // getSocketConnectedFunction
//----------------------------------------------------------------------------------------------------
function addOnDocumentReadyFunction(func)
{
   onDocumentReadyFunctions.push(func)

} // addOnDocumentReadyFunction
//----------------------------------------------------------------------------------------------------
function getOnDocumentReadyFunctions()
{
   return(onDocumentReadyFunctions)

} // getOnDocumentReadyFunctions
//----------------------------------------------------------------------------------------------------
// the nginx proxy server, used by fhcrc IT for the publicly-visible version of Oncoscape
// times out web sockets at 90 seconds.
// this function, when called more often that that, will keep the websocket open.
keepAlive = function()
{   
    //console.log("keep alive"); 
    msg = {cmd: "keepAlive", callback: "", status:"request", payload:""}
    socket.send(JSON.stringify(msg));

} // keepAlive
//--------------------------------------------------------------------------------------------------
function runOnDocumentReadyFunctions()
{
  setInterval(keepAlive, 30000);
  var funcs = getOnDocumentReadyFunctions()
  console.log("==== Module.hub: " + funcs.length + " onDocumentReadyFunctions");

  for (var f = 0; f < funcs.length; f++) {
     console.log("calling on ready function");
     funcs[f]();
     }

} // runOnDocumentReadyFunctions
//----------------------------------------------------------------------------------------------------
function runningInNode()
{
    // a not very sophisticated test, but adequate for our purposes thus far
  return(typeof(window) == "undefined")

} // functionRunningInNode
//----------------------------------------------------------------------------------------------------
function initializeWebSocket()
{
   if(runningInNode()){
     console.log("--- web socket not currently available when runing in Node");
     process.exit(code=1)
     }

   socket = new WebSocket(socketURI);
   socket = setupSocket(socket);

} // initializeWebSocket
//----------------------------------------------------------------------------------------------------
function getSocket()
{
  return(socket);

} // getSocket
//----------------------------------------------------------------------------------------------------
function addMessageHandler(cmd, func)
{
  if(cmd in dispatchOptions){
     dispatchOptions[cmd].push(func)
     }
  else{
     dispatchOptions[cmd] = [func]
     }
  
} // addMessageHandler
//----------------------------------------------------------------------------------------------------
function getRegisteredMessageNames()
{
   return(Object.keys(dispatchOptions));
  
} // getRegisteredMessageNames
//----------------------------------------------------------------------------------------------------
function getDispatchOptions()
{
   return(dispatchOptions);
  
} // getDispatchOptions
//----------------------------------------------------------------------------------------------------
function dispatchMessage(msg)
{
   var cmd = msg.cmd;
   var status = msg.status;
   //console.log("=============== dispatching '" + cmd + "'");

   var dispatchKeys = Object.keys(dispatchOptions);
   var cmdIndex = dispatchKeys.indexOf(cmd);
   console.log("hub.dispatchMessage(" + cmd + "): " + cmdIndex);

   if(cmdIndex === -1){
      console.log("unrecognized socket request: " + msg.cmd);
      console.log(" --- msg:");
      console.log(msg);
      console.log(" --- dispatchOptions");
      console.log(dispatchOptions);
      }
   else{
     var funcs = dispatchOptions[cmd];
     //console.log(" func count for msg cmd " + cmd + ": " + funcs.length);
      for(var i=0; i < funcs.length; i++){
         //console.log("--- Module.hub executing func # " + i + " for cmd " + msg.cmd);
         funcs[i](msg); // dispatchOptions[msg.cmd](msg)
         } // for i
      }

}  // dispatchMessage
//----------------------------------------------------------------------------------------------------
function restrictMessagingToLogin(newState)
{
   messagingRestrictedToLogin = newState;

} // restrictMessagingToLogin
//----------------------------------------------------------------------------------------------------
function send(msg)
{
   var cmd = JSON.parse(msg).cmd;
   if(messagingRestrictedToLogin && cmd === "checkPassword"){
      console.log("hub.send drops non-login msg");
      return;
      }

   var browserLocalCommand = Object.keys(dispatchOptions).indexOf(cmd) >= 0;
   var mode = "server";
   if(browserLocalCommand)
      mode = "browser local";

   console.log("--- hub.send: '" + cmd + "' (" + mode + ")");

   if(browserLocalCommand)
      dispatchMessage(JSON.parse(msg));
   else{
      socket.send(msg);
      }

}  // send
//----------------------------------------------------------------------------------------------------
function setTitle (newTitle)
{
  window.document.title = newTitle;

}  // setTitle
//----------------------------------------------------------------------------------------------------
// add a pulldown menu to the specified menuSelector, which has been provided by the caller, which
// is assumed to be an Oncoscape module.  append the names of all previously-registered divs, 
// except for those explicitly excluded in the incoming argument "excludedModules".
// This supports the usual (but not universal) case: a module does not want to send selections
// to itself.
// this argument will often be an array of one element, the name of the calling module.
// some modules may have multiple send destinations (eg, "PCA" & "PCA (highlight)".
function configureSendSelectionMenu(menuSelector, excludedModules, changeFunction, menuTitle)
{
  var menu = $(menuSelector);
  menu.append("<option>" + menuTitle + "</option>");
  menu.change(changeFunction);
  var otherModules = Object.keys(hub.getRegisteredSelectionDestinations());

  for(var i=0; i < otherModules.length; i++){
     var moduleName = otherModules[i];
     var excluded = excludedModules.indexOf(moduleName) >= 0;
     if(!excluded){
        menu.append("<option>" + moduleName + "</option>");
        }
     } // for i

  return(menu);

} // createSendSelectionMenu
//--------------------------------------------------------------------------------------------
function disableButton(button)
{
   button.prop("disabled", true);
   button.css({"background-color": "lightgray", "color": "gray"});

} // disableButton
//--------------------------------------------------------------------------------------------
function enableButton(button)
{
   button.prop("disabled", false);
   //button.css({ 'color': 'black'})
   button.css({"background-color": "white", "color": "black"});

} // enableButton
//--------------------------------------------------------------------------------------------
// if jQuery-style tabs are in use with Oncoscape, this function raised the named tab to the
// the front (visible) position in the tabset
// the argument, "tabIDString" is the tab id used in the module's widget.html, reproduced exactly
// in tabsApp/widget.html, with some current examples being
//  pcaDiv, patientTimeLinesDiv, gbmPathwaysDiv
//
function raiseTab(tabIDString)
{
  var tabsWidget = $("#oncoscapeTabs");

  if(tabsWidget.length > 0){
     var selectionString = '#oncoscapeTabs a[href="#' + tabIDString + '"]';
     var tabIndex = $(selectionString).parent().index ();
     if(tabIndex < 0) throw "Module.hub does not recognize tabIDString '" + tabIDString + "'";
     tabsWidget.tabs( "option", "active", tabIndex);
     } // if tabs exist

} // raiseTab
//----------------------------------------------------------------------------------------------------
// each of our tabs is a div, nested directly within $("oncoscapeTabs").  
// this function returns an array of each of the div ids
function getTabDivIDs()
{
   return ($("#oncoscapeTabs").children("div").map(function(index,dom){return dom.id}));

} // getTabDivIDs
//----------------------------------------------------------------------------------------------------
// e.g., hub.hideTab("Login", "#loginDiv");
function hideTab(tabTitle, tabDivIDstring)
{
  $(".ui-tabs-nav li:contains('" + tabTitle + "')").hide()
  $(tabDivIDstring).hide();

} // hideTab
//----------------------------------------------------------------------------------------------------
function hideAllTabsButOne(tabTitle, tabDivIDstring)
{
  var divIDs = getTabDivIDs();
  
  $(".ui-tabs-nav li:contains('" + tabTitle + "')").hide()
  $(tabDivIDstring).hide();

} // hideAllTabsButOne
//----------------------------------------------------------------------------------------------------
function showTab(tabTitle, tabDivIDstring)
{
  $(".ui-tabs-nav li:contains('" + tabTitle + "')").show()
  $(tabDivIDstring).show();

} // showTab
//----------------------------------------------------------------------------------------------------
function getRandomFloat (min, max)
{
    return Math.random() * (max - min) + min;
}
//----------------------------------------------------------------------------------------------------
function getRandomInt (min, max) 
{
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
//----------------------------------------------------------------------------------------------------
String.prototype.beginsWith = function (string) 
{
    return(this.toLowerCase().indexOf(string.toLowerCase()) === 0);
};
//----------------------------------------------------------------------------------------------------
uniqueElementsOfArray = function(vector)
{
  var u = {}, a = [];

  for(var i = 0, l = vector.length; i < l; ++i){
     if(u.hasOwnProperty(vector[i])){
       continue;
       }
     a.push(vector[i]);
     u[vector[i]] = 1;
     } // for i

   return a;

} // uniqueElementsOfArray
//----------------------------------------------------------------------------------------------------
// return the targets matched by the candidates, where match is tolerant of differences by suffix
// thus incoming id "TCGA.06.0649.01" matches existing id "TCGA.06.0649" and
//      incoming id "TCGA.06.0649"    matches existing id "TCGA.06.0649.01" 
// this may cause problems with gene names, eg, MYC would mach MYCL and MYCA
// todo: make this suffix-tolerant match suffix-specific 
function intersectionOfArrays(candidates, targets) {

  hits=[]; 

  for(var i=0; i < candidates.length; i++){
    for (var j=0; j < targets.length; j++){
       candidate = candidates[i];
       target = targets[j];
       index1 = candidate.indexOf(target);   // "abc".indexOf("ab") -> 0
       index2 = target.indexOf(candidate); 
       //console.log("c(t): " + candidate + " contains " + target + ": " + index1);
       //console.log("t(c): " + target + " contains " + candidate + ": " + index2);
       if (index1 == 0)
          hits.push(target)
       else if (index2 == 0)
          hits.push(target)
         } // for j
     } // for i

  return(hits)

} // intersectionOfArays
//----------------------------------------------------------------------------------------------------
function setupGlobalExceptionHandler()
{
   window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {

      var title = "Oncoscape Error";
      var options = {buttons: { "Ok": function () { $(this).dialog("close"); } },
                     title: title};
      var text = "<i>" + errorMsg + "</i><br>" +
                 "<br><b>Script</b>: " + url + 
                 "<br><b>Line:</b> " + lineNumber + 
                 "<br><b>Column:</b> " + column + 
                 "<br><b>StackTrace:</b> " +  errorObj;
      $("<div></div>").dialog(options).html(text);
      };
 
} // setupGlobalExceptionHandler
//----------------------------------------------------------------------------------------------------
function start()
{
  setupGlobalExceptionHandler();
  initializeWebSocket();
  $(document).ready(runOnDocumentReadyFunctions);

}  // start
//----------------------------------------------------------------------------------------------------
function test_intersectionOfArrays()
{
   console.log("---  test_intersectionOfArrays");
   var targets = ["TCGA.02.0006"];
   var candidates = ["TCGA.02.0006"];

   QUnit.test("test_intersectionOfArrays 1", function(assert) {
      assert.equal(hub.intersectionOfArrays(candidates, targets), candidates);
      });

   targets = ["TCGA.02.0006"];
   candidates = ["bogus"];
   QUnit.test("test_intersectionOfArrays 2", function(assert) {
      assert.equal(hub.intersectionOfArrays(candidates, targets), []);
      });

   targets = ["bogus"];
   candidates = ["TCGA.02.0006"];
   QUnit.test("test_intersectionOfArrays 3", function(assert) {
      assert.equal(hub.intersectionOfArrays(candidates, targets), []);
      });


   targets = ["TCGA.02.0006.01"];
   candidates = ["TCGA.02.0006"];
   QUnit.test("test_intersectionOfArrays 4", function(assert) {
      assert.equal(hub.intersectionOfArrays(candidates, targets), candidates);
      });

   //targets = ["MAP2"];   this test will fail because sometimes we want incomplete matches:
   //  see test4 just above
   //candidates = ["MAP2K4", "abc"];
   //QUnit.test("test_intersectionOfArrays 5", function(assert) {
   //   assert.equal(hub.intersectionOfArrays(candidates, targets), []);
   //   });


} //  test_intersectionOfArrays
//----------------------------------------------------------------------------------------------------
function standAloneTest()
{
   test_intersectionOfArrays();

}  // standaloneTest
//----------------------------------------------------------------------------------------------------

  return({
     getName: function() {return(name)},
     restrictMessagingToLogin: restrictMessagingToLogin,
     registerModule: registerModule,
     getModules: getModules,
     registerSelectionDestination: registerSelectionDestination,
     getRegisteredSelectionDestinations: getRegisteredSelectionDestinations,
     socketConnected: socketConnected,
     addSocketConnectedFunction: addSocketConnectedFunction,
     getSocketConnectedFunctions: getSocketConnectedFunctions,
     addOnDocumentReadyFunction: addOnDocumentReadyFunction,
     getOnDocumentReadyFunctions: getOnDocumentReadyFunctions,
     runningInNode: runningInNode,
     initializeWebSocket: initializeWebSocket,
     getSocket: getSocket,
     addMessageHandler: addMessageHandler,
     getRegisteredMessageNames: getRegisteredMessageNames,
     getDispatchOptions: getDispatchOptions,
     dispatchMessage: dispatchMessage,
     configureSendSelectionMenu: configureSendSelectionMenu,
     enableButton: enableButton,
     disableButton: disableButton,
     getRandomInt: getRandomInt,
     getRandomFloat: getRandomFloat,
     intersectionOfArrays: intersectionOfArrays,
     uniqueElementsOfArray: uniqueElementsOfArray,
     send: send,
     setTitle: setTitle,
     getTabDivIDs: getTabDivIDs,
     raiseTab: raiseTab,
     hideTab: hideTab,
     showTab: showTab,
     sat: standAloneTest,
     start: start
     });

}); // HubModule
//----------------------------------------------------------------------------------------------------


var hub = HubModule();
hub.start();

hub.addOnDocumentReadyFunction(function() {
    console.log("====== tabapps document ready");
    window.tabsAppRunning = true
    $("#oncoscapeTabs").tabs({
         // todo: distinguish between tabs, only do needed resets
       activate: function(event, ui) {
            console.log(" tabsApp/code.js:activate");
            var tableRef = $("#historyTable").dataTable();
            var tableRef2 = $("#userDataStoreTable").dataTable();
            if (tableRef.length > 0) {
               console.log("   adjusting patient history table");
               tableRef.fnAdjustColumnSizing();
               } // if
            if (tableRef2.length > 0) {
               console.log("   skipping! - adjusting user data store table");
               tableRef2.fnAdjustColumnSizing();
               } // if
            //console.log(" ==== tab.activate, possible cyjs resize and fit");
            if(typeof(cwMarkers) != "undefined") {
               //console.log("adjusting cwMarkers");
               cwMarkers.resize(); 
               cwMarkers.fit(50);
               //console.log("done adjusting cwMarkers");
               }
            if(typeof(cwGbm) != "undefined") {
               //console.log("adjusting cwGbm");
               cwGbm.resize();
               cwGbm.fit(50);
               //console.log("done adjusting cwGbm");
               }
            if(typeof(cwAngio) != "undefined") {
               //console.log("adjusting cwAngio");
               cwAngio.resize();
               cwAngio.fit(50);
               //console.log("done adjusting cwGbm");
               }
            } // activate
        }); // tabs
    });  // ready



</script>
<style>
.ui-tabs .ui-tabs-nav li a {font-size:10pt !important;}
.ui-button .ui-button-text {font-size:10pt !important;}
</style>

<script>
//----------------------------------------------------------------------------------------------------
var DataSummaryModule = (function () {

  var dataSummaryDiv;

  var outputDiv;
  var dataSetNamesOutputDiv;
  var thisModulesName = "datasets";
  var thisModulesOutermostDiv = "datasetsDiv";

  var tableElement;
  var tableRef;
  var datasetMenu;
  var selectedDataSet;
  var useThisDatasetButton;

  var sendSelectionsMenu;
  var sendSelectionsMenuTitle = "Send selection...";
  var passwordProtected = false;

//----------------------------------------------------------------------------------------------------
function initializeUI()
{
  sendSelectionsMenu = hub.configureSendSelectionMenu("#datasetsSendSelectionsMenu", 
                                                      [thisModulesName], sendSelections,
                                                       sendSelectionsMenuTitle);

  hub.disableButton(sendSelectionsMenu);

  $(window).resize(handleWindowResize);
  datasetMenu = $("#datasetMenu");
  datasetMenu.change(selectManifest);
  //hub.disableButton($("#datasetMenu"))

  dataSetNamesOutputDiv = $("#dataSetNamesOutputDiv");
  dataSummaryDiv = $("#dataSummaryOutputDiv");

  useThisDatasetButton = $("#selectDatasetButton");
  useThisDatasetButton.button();
  hub.disableButton(useThisDatasetButton);
  useThisDatasetButton.click(specifyCurrentDataset);

  outputDiv = $("#dataSummaryOutputDiv");
  tableElement = $("#datasetsManifestTable");
      
  //console.log("===== Module.datasets, about to hide my div");

  //$("#datasetsDiv").hide();

} // initializeUI
//----------------------------------------------------------------------------------------------------
function handleWindowResize()
{
  console.log("==== Module.datasets handleWindowResize");

  console.log("  window: " + $(window).width());

  $("#"+thisModulesOutermostDiv).width($(window).width() * 0.95);
  $("#"+thisModulesOutermostDiv).height($(window).height() * 0.95);
//  console.log("  div: " + outputDiv.width());

//  console.log("  tbl before: " + tableElement.width());
//  tableElement.width($(window).width() * 0.50);
//  console.log("  tbl after: " + tableElement.width());

} // handleWindowResize
//----------------------------------------------------------------------------------------------------
function sendSelections(event)
{
   var destination = sendSelectionsMenu.val();
   console.log("send selections to " + destination);
   sendSelectionsMenu.val(sendSelectionsMenuTitle);

   var cmd = "sendSelectionTo_" + destination;
   payload = "dummy payload";
   var newMsg = {cmd: cmd,  callback: "", status: "request", payload: payload};

   sendSelectionsMenu.val(sendSelectionsMenuTitle);

   hub.send(JSON.stringify(newMsg));

} // sendSelections
//----------------------------------------------------------------------------------------------------
function selectManifest(event)
{
   selectedDataSet = datasetMenu.val();
   console.log("dataset '" + selectedDataSet + "'");

   if(selectedDataSet === ""){
     // outputDiv.empty();
      $("#datasetInstructions").css("display", "block")
      $("#datasetsManifestTable").css("display", "none")
      hub.disableButton(useThisDatasetButton);
      }
    else{
      $("#datasetInstructions").css("display", "none")
      $("#datasetsManifestTable").css("display", "block")      
      requestDataSetSummary(selectedDataSet);
    }

} // selectManifest
//----------------------------------------------------------------------------------------------------
function populateDataSetMenu()
{
   $(datasetMenu).ready(function() {
      console.log("=== datasetMenu ready, now issuing populateDataSetMenu request to server");
      var msg = {cmd: "getDataSetNames",  callback: "handleDataSetNames", status: "request", 
                 payload: ""};
      hub.send(JSON.stringify(msg));
      });

} // populateDataSetMenu
//----------------------------------------------------------------------------------------------------
function handleDataSetNames(msg)
{
   console.log("=== handleDataSetNames");
   
   var dataSetNames = msg.payload.datasets;
   var passwordProtected = msg.payload.passwordProtected;

   if(!Array.isArray(dataSetNames))
      dataSetNames = [dataSetNames];

   for(var i=0; i < dataSetNames.length; i++){
      var s = dataSetNames[i];
      datasetMenu.append("<option value='" + s + "'>" + s + "</option>");
      }

  if(passwordProtected)
     hub.disableButton($("#datasetMenu"));


} // handleDataSetNames
//----------------------------------------------------------------------------------------------------
function requestDataSetSummary(dataSetName)
{
   console.log("=== requestDataSetSummary");

   var msg = {cmd: "getDataManifest",  callback: "displayDataManifest", status: "request", 
              payload: dataSetName};

   hub.send(JSON.stringify(msg));

} // requestDataSetSummary
//----------------------------------------------------------------------------------------------------
function displayDataManifest(msg)
{
   var payload = msg.payload;
   var tblColumnNames = payload.colnames;

   var columnTitles = [];
     // convert simple strings to array of objects, each an sTitle
   for(var i=0; i < tblColumnNames.length; i++){
      columnTitles.push({sTitle: tblColumnNames[i]});
      }
     
   if(typeof(tableRef) != "undefined"){
      tableRef.destroy();
      tableElement.empty();
      }


   $(tableElement).ready(function() {
      tableRef = tableElement.DataTable({
        //sDom: 't',
        aoColumns: columnTitles,
        //scrollX: true,
        bPaginate: false,
        bFilter: false, 
        bAutoWidth: true,
        bSort: false,
        bInfo: false
        }); // dataTable

     tableRef = $("#datasetsManifestTable").DataTable();

     tableRef.rows.add(payload.mtx).draw();
     // tableRef.fnAddData(payload.mtx);

     $('#datasetsManifestTable tbody').on( 'click', 'tr', function (){ 
         console.log("=== click");
         var category = $('td', this).eq(0).text();
         var subcategory = $('td', this).eq(1).text();
         if($(this).hasClass("selected")){
            $(this).removeClass('selected');
            hub.disableButton(sendSelectionsMenu);
            }
         else{
            tableRef.$('tr.selected').removeClass('selected');
            $(this).addClass('selected');
            hub.enableButton(sendSelectionsMenu);
            console.log("selected " + category + ", " + subcategory);
            }
         });

     handleWindowResize();
     hub.enableButton(useThisDatasetButton);
     }); // tableElement.ready

} // displayDataManifest
//----------------------------------------------------------------------------------------------------
function specifyCurrentDataset()
{
   console.log("specifyCurrentDataset: " + selectedDataSet);

   var msg = {cmd: "specifyCurrentDataset",  callback: "datasetSpecified", 
              status: "request", payload: selectedDataSet};

   hub.send(JSON.stringify(msg));

} // specifyCurrentDataset
//----------------------------------------------------------------------------------------------------
function datasetSpecified(msg)
{
   console.log("--- Module.datasets:  datasetSpecified");

} // datasetSpecified
//----------------------------------------------------------------------------------------------------
function test(dataSetName)
{
   console.log("Module.datasets test, on datasetName: '" + dataSetName + "'");

   QUnit.test("choose dataset '" + dataSetName + "'", function(assert) {
      hub.raiseTab("datasetsDiv");
      var desiredDataset = dataSetName;
      var dzNames = $("#datasetMenu option").map(function(opt){return this.value})

      if($.inArray(desiredDataset, dzNames) < 0){
         alert("cannot run tests:  " + desiredDataset + " dataset not loaded");
         return;
         }

      $("#datasetMenu").val(desiredDataset)
      $("#datasetMenu").trigger("change");

      var done1 = assert.async();
      var done2 = assert.async();
      var done3 = assert.async();
      assert.expect(3);

      setTimeout(function(){
         assert.equal($("#datasetMenu").val(), desiredDataset);  done1();
         assert.ok($("#datasetsManifestTable tr").length >= 10); done2();
         assert.equal($("#datasetsManifestTable tbody tr").eq(0).find("td").eq(0).text(), 
                      "mRNA expression"); done3();
         //testLoadPatientHistoryTable();
         }, 5000);
      });


} // test
//----------------------------------------------------------------------------------------------------
function moduleInit()
{

  hub.addOnDocumentReadyFunction(initializeUI);
  // hub.addOnDocumentReadyFunction(function() {$("#datasetsDiv").hide();});
  // hub.registerSelectionDestination(thisModulesName, thisModulesOutermostDiv);
  hub.addSocketConnectedFunction(populateDataSetMenu);
  hub.addMessageHandler("handleDataSetNames", handleDataSetNames);
  hub.addMessageHandler("displayDataManifest", displayDataManifest);
  hub.addMessageHandler("datasetSpecified", datasetSpecified);
  hub.setTitle("Datasets");

} // moduleInit
//----------------------------------------------------------------------------------------------------
return{
   init: moduleInit,
   test: test
   }; // DataSummaryModule return value

//----------------------------------------------------------------------------------------------------
}); // DataSummaryModule

var dataSummaryModule = DataSummaryModule();
dataSummaryModule.init();
hub.registerModule("Datasets", dataSummaryModule);

//----------------------------------------------------------------------------------------------------
var patientHistoryTableRef;

var ageAtDxMinReadout;
var ageAtDxMaxReadout;
var survivalMinReadout, survivalMaxReadout;

var ageAtDxMin, ageAtDxMax;
var ageAtDxSlider, survivalSlider;
var survivalMin, survivalMax;


var PatientHistoryModule = (function () {

  var patientHistoryDiv;
  var controlsDiv;
  var tableDiv;
  var tableElement;
  var sendSelectionsMenu;

  var thisModulesName = "patientHistory";
  var thisModulesOutermostDiv = "patientHistoryDiv";
  var selectionDestinations = [thisModulesName];

  var sendSelectionsMenuTitle = "Send selection...";
  var showAllRowsButton;
  
//--------------------------------------------------------------------------------------------
function initializeUI()
{
  console.log("=== Module.patientHistory, initializeUID");

  $(window).resize(handleWindowResize);

  patientHistoryDiv = $("#patientHistoryDiv");
  controlsDiv = $("#patientHistoryControlsDiv");
  tableDiv = $("#patientHistoryTableDiv");
  tableElement = $("#patientHistoryTable");

  showAllRowsButton = $("#patientHistoryShowAllRowsButton");
  showAllRowsButton.click(showAllRows);

  sendSelectionsMenu = hub.configureSendSelectionMenu("#patientHistorySendSelectionsMenu", 
                                                      selectionDestinations, sendSelections,
                                                      sendSelectionsMenuTitle);

  handleWindowResize();

} // initializeUI
//----------------------------------------------------------------------------------------------------
function createDataTable(colnames, data)
{
      // DataTable likes some structure for column titles

   var columnTitles = [];
   for(var i=0; i < colnames.length; i++){
     columnTitles.push({sTitle: colnames[i]});
     }

   if(typeof(patientHistoryTableRef) != "undefined"){
      patientHistoryTableRef.destroy();
      tableElement.empty();
      }

   patientHistoryTableRef = tableElement.DataTable({
                             data: data,
                             columns: columnTitles,
                             //dom: "C<fi<t>>",
                             dom: 'C<"clear">lfrtip',
                             paging: false,
                             jQueryUI: false
                             });

   if(colnames.indexOf("AgeDx") >= 0){
      var minMax = learnSliderMinAndMax(data, colnames.indexOf("AgeDx"));
      console.log("minMax for AgeDx: ");
      console.log(minMax);
      ageAtDxMin = minMax[0];
      ageAtDxMax = minMax[1];
         // slider, title & readouts for specifying age range for table display
      createAgeAtDiagnosisWidget(ageAtDxMin, ageAtDxMax);  
      } // ageAtDx slider

   if(colnames.indexOf("Survival") >= 0){
      minMax = learnSliderMinAndMax(data, colnames.indexOf("Survival"));
      console.log("minMax for Survival: ");
      console.log(minMax);
      survivalMin = minMax[0];
      survivalMax = minMax[1];
         // slider, title & readouts for specifying age range for table display
      createSurvivalWidget(survivalMin, survivalMax);  
      } // survival slider

   showAllRows();
   setupSliderDrivenFilterBehavior(colnames);
 

} // createDataTable
//----------------------------------------------------------------------------------------------------
function setupSliderDrivenFilterBehavior(colnames)
{
  var ageDxColumn = colnames.indexOf("AgeDx");
  var survivalColumn = colnames.indexOf("Survival");

  if(ageDxColumn >= 0) {
    jQuery.fn.dataTable.ext.search.push(
       function(settings, data, dataIndex) {
         var ageAtDxMin      = parseFloat(ageAtDxMinReadout.val());
         var ageAtDxMax      = parseFloat(ageAtDxMaxReadout.val());

         var patientAgeAtDx  = parseFloat(data[ageDxColumn]) || 0;
 
         var ageAtDxInRange  = (patientAgeAtDx >= ageAtDxMin) && (patientAgeAtDx <= ageAtDxMax);
         if(ageAtDxInRange)
            return true;
         return false;
        }); // anonymous function
      } // push

  if(survivalColumn >= 0) {
    jQuery.fn.dataTable.ext.search.push(
       function(settings, data, dataIndex) {
         var survivalMin      = parseFloat(survivalMinReadout.val());
         var survivalMax      = parseFloat(survivalMaxReadout.val());

         var patientSurvival  = parseFloat(data[survivalColumn]) || 0;
         var survivalInRange  = (patientSurvival >= survivalMin) && (patientSurvival <= survivalMax);
         if(survivalInRange)
            return true;
         return false;
        }); // anonymous function
      } // push


} // setupSliderDrivenFilterBehavior
//----------------------------------------------------------------------------------------------------
function createAgeAtDiagnosisWidget(minValue, maxValue)
{
  ageAtDxSlider = $("#ageAtDxSlider");
  ageAtDxMinReadout = $("#ageAtDxMinSliderReadout");
  ageAtDxMaxReadout = $("#ageAtDxMaxSliderReadout");

  ageAtDxSlider.slider({
     range: true,
     slide: function(event, ui) {
        //console.log("AgeDx: " + ui.values[0] + ", " + ui.values[1]);
        if(ui.values[0] > ui.values[1]){
           return false;
           }          
       ageAtDxMinReadout.text (ui.values[0]);
       ageAtDxMaxReadout.text (ui.values[1]);
       patientHistoryTableRef.draw();
       handleWindowResize();
       //updateRowCountReadout();
       },
    min: minValue,
    max: maxValue,
    values: [minValue, maxValue]
    });

  ageAtDxMinReadout.text(minValue);
  ageAtDxMaxReadout.text(maxValue);

} // createAgeAtDiagnosisWidget
//----------------------------------------------------------------------------------------------------
function createSurvivalWidget(minValue, maxValue)
{
  survivalSlider = $("#survivalSlider");
  survivalMinReadout = $("#survivalMinSliderReadout");
  survivalMaxReadout = $("#survivalMaxSliderReadout");
  console.log("createSurvivalWidget");

  survivalSlider.slider({
     range: true,
     slide: function(event, ui) {
        //console.log("survival: " + ui.values[0] + ", " + ui.values[1]);
        if(ui.values[0] > ui.values[1]){
           return false;
           }          
       survivalMinReadout.text (ui.values[0]);
       survivalMaxReadout.text (ui.values[1]);
       patientHistoryTableRef.draw();
       handleWindowResize();
       },
    min: minValue,
    max: maxValue,
    values: [minValue, maxValue]
    });

  survivalMinReadout.text(minValue);
  survivalMaxReadout.text(maxValue);

} // createSurvivalWidget
//----------------------------------------------------------------------------------------------------
// when the patient history table arrives, the filtering sliders can be setup, using the 
// min and max values of selected columns.  our sliders are currently ageAtDx and survival.
// the column numbers for these are specified by the caller.  missing values are not
// troublesome to Javascript's min and max functions.  note the use of floor and ceil,
// to nudge min and max values out a bit.
function learnSliderMinAndMax(tbl, columnNumber)
{
  var rowCount = tbl.length;
  var min = Number.MAX_VALUE;
  var max = -Number.MAX_VALUE;

  for(var r=0; r < rowCount; r++){
    var value = Number.parseFloat(tbl[r][columnNumber]);
    //console.log(value)
    if(value < min)
      min = value;
    if(value > max)
      max = value;
    } // for r

  return[Math.floor(min), Math.ceil(max)];

} // learnSliderMinAndMax
//----------------------------------------------------------------------------------------------------
function showAllRows()
{
   if(typeof(ageAtDxMin)  != "undefined" &&
      typeof(ageAtDxMax)  != "undefined" &&
      typeof(survivalMin) != "undefined" &&
      typeof(survivalMax) != "undefined") {

        ageAtDxSlider.slider("values", [ageAtDxMin, ageAtDxMax]);
        survivalSlider.slider("values", [survivalMin, survivalMax]);
        ageAtDxMinReadout.text(ageAtDxMin);
        ageAtDxMaxReadout.text(ageAtDxMax);
        survivalMinReadout.text(survivalMin);
        survivalMaxReadout.text(survivalMax);
        } // all 4 min/max slider values defined

    // chained calls: clear the DataTable search box, then iterate through the columns, then render

   if(typeof(patientHistoryTableRef) != "undefined")
       patientHistoryTableRef.search('').columns().search('').draw();

   handleWindowResize();

} // showAllRows
//----------------------------------------------------------------------------------------------------
function handleWindowResize()
{

  patientHistoryDiv.width($(window).width() * 0.95);
  patientHistoryDiv.height($(window).height() * 0.90);  // leave room for tabs above

  //controlsDiv.width($(window).width() * 0.90);
  controlsDiv.width(patientHistoryDiv.width()); //  * 0.95);
  controlsDiv.height("100px");

  tableDiv.width(patientHistoryDiv.width()); //  * 0.95);
  tableDiv.height(patientHistoryDiv.height() - 130);

} // handleWindowResize
//--------------------------------------------------------------------------------------------
function sendSelections(event)
{
   var destination = sendSelectionsMenu.val();

   var visibleRows = patientHistoryTableRef.rows({'filter': 'applied'})[0];
   if(visibleRows.length === 0)
      return;

   var selectedIDs = [];

   var data = patientHistoryTableRef.data();

   for(var i=0; i < visibleRows.length; i++){
      var id = data[visibleRows[i]][0];
      selectedIDs.push(id);
      } // for i

   var cmd = "sendSelectionTo_" + destination;

   payload = {value: selectedIDs, count: selectedIDs.length, source: "patient history module"};
   var newMsg = {cmd: cmd,  callback: "", status: "request", payload: payload};

   sendSelectionsMenu.val(sendSelectionsMenuTitle);

   hub.send(JSON.stringify(newMsg));

} // sendSelections
//--------------------------------------------------------------------------------------------
function handleSelections(msg)
{
   showAllRows();
   var ids = msg.payload.value;
   if(typeof(ids) == "string")
      ids = [ids];

      // incoming ids may have trailing version number, e.g., "TCGA.02.0114.01"
      // strip all such 2-digit suffixes:

   ids = ids.map(function(id) {return(id.replace(/\.0[0-9]$/, ""))})
   filterByString(ids);
   hub.raiseTab(thisModulesOutermostDiv);

} // handleSelections
//----------------------------------------------------------------------------------------------------
filterByString = function(strings)
{
   var filterString = strings[0];
   for(var i=1; i < strings.length; i++){
     filterString += "|" + strings[i];
     }

   showAllRows();
   console.log(filterString);

   if(typeof(patientHistoryTableRef) != "undefined")
      patientHistoryTableRef.search(filterString, true, false).draw();   // string, regex, smart

}; // filterByString
//----------------------------------------------------------------------------------------------------
function displayPatientHistoryTable(msg)
{
   var payload = msg.payload;
   var colnames = payload.colnames;
   var data = payload.tbl; // an array of arrays

   console.log("incoming table, rows: " + data.length);
   console.log("incoming table, cols: " + data[0].length);
   createDataTable(colnames, data);
   // hub.raiseTab(thisModulesOutermostDiv);

}  // displayPatientHistoryTable
//----------------------------------------------------------------------------------------------------
// called when the a dataset has been specified, typically via the Datasets tab, which presents
// the user with a list of the datasets they are able to use, from which they choose one at a time
// as their current working dataset.
// this module uses the dataset name to request the patient history table from the server
function datasetSpecified (msg)
{
   var datasetName = msg.payload;

     // request patient data table
   var payload = {datasetName: datasetName, durationFormat: "byYear"};
   var newMsg = {cmd: "getPatientHistoryTable",  callback: "displayPatientHistoryTable", 
                 status: "request", payload: payload};

   hub.send(JSON.stringify(newMsg));

} // datasetSpecified
//----------------------------------------------------------------------------------------------------
// for standalone exploration, development, and testing.   assumes a hub has been
// created and initialized.  set the dataset, and in the callback load the table
// thus 
//   specifyCurrentDataSet -> getPatientHistoryTable -> displayPatientHistoryTable
//
function testLoad()
{
   var msg = {cmd: "specifyCurrentDataset",  callback: "datasetSpecified", 
              status: "request", payload: "TCGAgbm"};

   hub.send(JSON.stringify(msg));

} // test
//----------------------------------------------------------------------------------------------------
function testSelect()
{
   var msg={cmd: "sendSelectionTo_patientHistory", status: "request", callback: "", 
            payload:["TCGA.02.0011", "TCGA.06.0238"]};

   hub.send(JSON.stringify(msg));

} // testSelect
//----------------------------------------------------------------------------------------------------
return{
   init: function(){
      hub.registerSelectionDestination(selectionDestinations, thisModulesOutermostDiv);
      hub.addOnDocumentReadyFunction(initializeUI);
      hub.addMessageHandler("sendSelectionTo_patientHistory", handleSelections);
      hub.addMessageHandler("datasetSpecified", datasetSpecified);
      hub.addMessageHandler("displayPatientHistoryTable", displayPatientHistoryTable);
      //hub.addSocketConnectedFunction(testLoad);
      hub.setTitle("patientHistory");
      },
   testSelect: testSelect,
   testLoad:   testLoad
   }; // PatientHistoryModule return value

//----------------------------------------------------------------------------------------------------
}); // PatientHistoryModule
pts = PatientHistoryModule();
pts.init();


</script>

<body>

<div id="oncoscapeTabs">
   <ul>
     <li><a href="#datasetsDiv">Datasets</a></li>
     <li><a href="#patientHistoryDiv">Patient History</a></li>
   </ul>


<style>
 
</style>

<div id="datasetsDiv">

  <div id="dataSummaryControlsDiv">
     <span id="selectDataSetMenuLabel" style="margin-left: 20px;">Available Datasets</span>
     <select type="button" id="datasetMenu" style="margin: 5px;"><option> </option></select>
     <button id="selectDatasetButton">Use Dataset</button>
     <select type="button" id="datasetsSendSelectionsMenu" style="float:right; margin:15px; display: none"></select>
  </div>

   <div id="dataSetNamesOutputDiv" style="margin: 20px;"></div>

   <div id="dataSummaryOutputDiv" style="margin: 20px;overflow-x:auto">
      <div id="datasetInstructions">Please select a dataset from the above menu.</div>
      <table id="datasetsManifestTable" class="display" cellpadding="0" cellspacing="0" border="1" style="margin:0px; width:auto; display:none"></table>
   </div>
</div>

<style>


#patientHistoryDiv{
   width: 600px;
   height: 400px;
   background-color: #ffffff;
   margin: auto;
   padding: 5px;
   }


#patientHistoryControlsDiv {
  background-color: #FFFFFF;
  position: relative;
  height: 400px;
  width: 600px;
  border: 1px solid #aaa;
  border-radius: 5px;
  margin-right: auto;
  margin-left: auto;
  margin-top: 10px;
  margin-bottom: 5px;
  padding: 0px;
  }

#patientHistoryTableDiv {
  background-color: #FFFFFF;
  position: relative;
  height: 400px;
  width: 600px;
  overflow-x:auto;
  margin-right: auto;
  margin-left: auto;
  margin-top: 5px;
  margin-bottom: 5px;
  padding: 0px;
  }

.patientDataFilterSliderReadout {
  font-family:"Courier";
  color: #0000FF;
  background-color: #FFF;
  font-size: 12px;
  border: 2px solid #DDD;
  width: 50px;
  height: 25px;
  resize: none;
  margin-top: 5px;
  margin-left: 1px;
  }

.patientDataFilterSliderTitleDiv {
  font-family:"Arial";
  color: #000000;
  font-size: 12px;
  padding-top: 0px;
  padding-right:0px;
  }


</style>


<div id="patientHistoryDiv">

  <div id="patientHistoryControlsDiv">  


        <div id="ageSliderDiv" class="nav navbar-nav navbar-form navbar-left"  style="display: inline-block">
           <div id="ageAtDxSliderTitleDiv" class="patientDataFilterSliderTitleDiv" style="text-align: center; width=100%">Age at Dx</div>
           <div style="width: 280px; overflow: hidden;">
               <div id="ageAtDxMsgBox1" style="float: left; margin-left: 5px; margin-right: 15<px; width: 40px" >
  
                  <textarea id="ageAtDxMinSliderReadout" style="font-size: 12px; height:16px"
                            readonly class="patientDataFilterSliderReadout"></textarea> 
                  </div>
               <div style="width: 120px; height: 6px; float: left; margin-top: 10px; 
                           margin-left: 30px; margin-right: 15px;" 
                   id="ageAtDxSlider" class="slider patientDataFilterSlider">
                   </div>
               <div id="ageAtDxMsgBox2" style="float: left">  
                  <textarea id="ageAtDxMaxSliderReadout" style="font-size: 12px; height:16px"
                            readonly class="patientDataFilterSliderReadout"></textarea> 
                  </div>
              </div>
           </div>


        <div id="survivalSliderDiv" class="nav navbar-nav navbar-form navbar-left" style="display: inline-block">
           <div id="survivalSliderTitleDiv" class="patientDataFilterSliderTitleDiv" style="text-align: center; width=100%">Survival</div>
           <div style="width: 280px; overflow: hidden;">
               <div id="survivalMsgBox1" style="float: left" >  
                  <textarea id="survivalMinSliderReadout" style="font-size: 12px; height:16px"
                             readonly class="patientDataFilterSliderReadout"></textarea> 
                  </div>
               <div style="width: 120px; height: 6px; float: left; margin-top: 10px; margin-left: 15px;
                            margin-right: 15px;" 
                   id="survivalSlider" class="slider patientDataFilterSlider">
                   </div>
               <div id="survivalMsgBox2" style="float: left">  
                  <textarea id="survivalMaxSliderReadout"  style="font-size: 12px; height:16px"
                            readonly class="patientDataFilterSliderReadout"></textarea> 
                  </div>
              </div>
           </div>

     <button id="patientHistoryShowAllRowsButton" type="button">Reset</button>
     <select type="button" id="patientHistorySendSelectionsMenu" style="float:right; margin:15px"></select>


  </div>

  <div id="patientHistoryTableDiv">  
    <table id="patientHistoryTable" cellpadding="0" cellspacing="0" border="0" class="display">
    </table>
 </div>

</div>


</div>



</body>
</html>

