// a function to build a sigmoid curve
function get_curve (drug, cellLine, x) {
  var max = curves[drug][cellLine].max,
    min = curves[drug][cellLine].min,
    IC50 = curves[drug][cellLine].IC50,
    slope = curves[drug][cellLine].Slope,
    minConc = curves[drug][cellLine].minConc;

  return min + (max - min)/ 
    (1 + Math.pow(10, -(x - Math.log10(IC50/minConc)) * slope));
}

var selDrugs = [drugs[0], drugs[1]],
   selCellLine = cellLines[0];

lc.heatmap()
   .nrows(drugs.length)
   .ncols(drugs.length)
   .rowLabel(i => drugs[i])
   .colLabel(i => drugs[i])
   .set_paddings({left: 40, top: 40, right: 50})
   .showLegend(false)
   .clusterRows(true)
   .clusterCols(true)
   .value((row, col) => corMat[row][col])
   .on_click((row, col) => {
      selDrugs = [drugs[row], drugs[col]];
      dssplot.update();
      viability.update();
      plateHms[0].update();
      plateHms[1].update();
   })
  .place("#A1");

  var dssplot = lc.scatter()
   .width(300)
   .height(250)
   .title("DSS value")
   .x(i => scoreMat[i][drugs.indexOf(selDrugs[0])])
   .y(i => scoreMat[i][drugs.indexOf(selDrugs[1])])
   .domainX([0, 45])
   .domainY([0, 45])
   .set_paddings({bottom: 20})
   .colour(i => i == cellLines.indexOf(selCellLine) ? "black" : "grey")
   .axisTitleX(() => selDrugs[0])
   .axisTitleY(() => selDrugs[1])
   .label(i => cellLines[i])
   .on_click(d => {
      selCellLine = cellLines[d];
      dssplot.get_layer("layer0").updateElementStyle();
      viability.update();
      plateHms[0].update();
      plateHms[1].update();
   });       

//add another layer to the 'dssplot'
lc.xLine("line", dssplot)
   .lineFun(x => x)
   .place("#A2");

//here, data are transformed from an array in a nested format
//which easier and faster by the linked-charts.js to access
curves = lc.separateBy(curves, ["Drug", "CellLine"]);

var viability = lc.xLine()
   .width(300)
   .height(150)
   .title(() => selCellLine)
   .axisTitleX("Concentration order")
   .axisTitleY("Cell viability, %")
   .set_paddings({bottom: 20})
   .nelements(2)
   .addColourScaleToLegend(false)
   .lineFun((x, i) => get_curve(selDrugs[i], selCellLine, x))
   .colourValue(i => selDrugs[i]);

lc.scatter("points", viability)
   .nelements(10)
   .x(i => i % 5)
   .y(i => curves[selDrugs[+(i < 5)]][selCellLine]["D" + (i % 5 + 1)])
   .domainY([-10, 105])
   .on_mouseover(i => {
      let well = curves[selDrugs[+(i < 5)]][selCellLine]["W" + (i % 5 + 1)];
      plateHms[+(i < 5)].mark([well[0], well.slice(1)]);
   })
   .on_mouseout(() => {
      plateHms.forEach(el => el.mark("__clear__"));
   })    
   .colourValue(i => selDrugs[+(i < 5)])
   .legend.container("#A2")
   .legend.width(300)
   .place("#A2");

plates = lc.separateBy(plates, ["Barcode", "DWell"]);


//since heatmaps for readouts are so similar to each other
//it is easier to make them both within a "for" loop
//however, since we need the index variable inside the callback
//functions, we are using a "placeHeatmap" function that produces
//and returns a heatmap
var plateHms = [];
for(let i = 0; i < 2; i++)
   plateHms[i] = placeHeatmap(i);

function placeHeatmap(i) {
   return lc.heatmap()
      .width(300)
      .height(225)
      .showPanel(false)
      .title(() => "Plate " + curves[selDrugs[i]][selCellLine].Barcode)
      .titleSize(15)
      .paddings({top: 40, left: 15, bottom: 5, right: 5})
      .rowIds("ABCDEFGHIJKLMNOP".split(""))
      .colIds(d3.range(24).map(el => el + 1))
      .value((row, col) => 
         plates[curves[selDrugs[i]][selCellLine].Barcode][row+col].rawIntensity)
      .informText((row, col) => {
         let well = plates[curves[selDrugs[i]][selCellLine].Barcode][row + col];

         return "<b>" + well.ProductName + "</b><br>" + 
            "Concentration:" + well.Concentration + "<br>" +
            "Value: " + well.rawIntensity;
      })
      .showLegend(false)
      .place("#A3");   
}