var juxtaposition = d3.select("#juxtaposition").append("svg")
                                    .attr("width", width-20)
                                    .attr("height", 120);
                                                                     
function drawJuxtaRect(group,thisElementWidth, start, end, startHeight, endHeight, width, col){

    var startQuad = xoffset + Math.ceil(start);
    var endQuad = startQuad + Math.ceil(end*thisElementWidth+1);

    var quadPoints = (startQuad) + " " + (startHeight + width/2) + ", "
                        + (startQuad) + " " + (startHeight - width/2) + ", "
                        + (endQuad) + " " + (endHeight - width/2) + ", "
                        + (endQuad) + " " + (endHeight + width/2);
    group.append("polygon")
        .attr("fill", col)
        .attr("points", quadPoints); 
}

function drawJuxtaArrow(group,n, i, thisElementWidth, start, gap, startHeight, endHeight, col){

    var arrowStart = start + xoffset;

    var length = Math.ceil(gap*thisElementWidth);
    var newLength = Math.ceil(Math.sqrt(Math.pow(length, 2) + Math.pow(endHeight-startHeight, 2)));
    var angleDeg = Math.atan2(endHeight - startHeight, gap*thisElementWidth) * 180 / Math.PI;
    var newColor = col;

    var height = startHeight;
    var size;
    var triangleLength;
    // if (loop){
    //   size = thisElementWidth;
    //   triangleLength = newLength;
    // }
    // else {
      size = (thisElementWidth+5 > 10) ? 10 : thisElementWidth+5;
      triangleLength = (newLength > size) ? size : newLength;
    // }

    var arrowGroup = group.append("g");

    arrowGroup.append("rect")
        .attr("height", size)
        .attr("width", newLength - triangleLength + 2)
        .attr("x", arrowStart)
        .attr("y", height-size/2)
        .style("fill", newColor);

    var trianglePoints = (arrowStart + newLength) + " " + (height) + ", " 
            + (arrowStart + newLength - triangleLength) + " " + (height + size) + ", " 
            + (arrowStart + newLength - triangleLength) + " " + (height - size) ; 

    arrowGroup.append("polygon")
              .attr("fill", newColor)
              .attr("points", trianglePoints);  

    var middle = (endHeight<startHeight) ? -((Math.abs(endHeight-startHeight))/2) : ((Math.abs(endHeight-startHeight))/2);

    arrowGroup.attr("transform", "rotate("+angleDeg+"," + (arrowStart+(length/2)) + "," + (startHeight+middle) + 
                    ") translate (0, " + (middle) + ")" );

    // arrowGroup.on("click", function(){
    //   highlighted[n] = (highlighted[n] === i) ? 9999 : i;
    //   redrawD3();
    //   (highlighted[n] === 9999) ? (resetViewerSelection(n)) : highlightPV(n, i);
    // });

}

function drawJuxtaHelix(group,n, j, thisElementWidth, start, gap, startHeight, endHeight, col){

  var startHelix = start + xoffset;
  var length = Math.ceil(gap*thisElementWidth);
  var height = startHeight;

  var newLength = length;
  // var angleDeg = Math.atan2(endHeight - startHeight, gap*thisElementWidth) * 180 / Math.PI;
  var newColor = col;

  var size = (thisElementWidth+9 > 20) ? 20 : thisElementWidth+9;

  var helixGroup = group.append("g");
  
  var firstShade = (startHelix) + " " + (height - size/2) + ", "
                        + ((i+size/2>startHelix+newLength) ? startHelix+newLength : startHelix+size/2) + " " + (height - size/2) + ", "
                        + (startHelix) + " " + (height+size/2) + ", "
                        + (startHelix - size/4) + " " + (height + size/2) + ", "
                        + (startHelix - size/4) + " " + (height);

  helixGroup.append("polygon")
        .attr("fill", newColor)
        .attr("opacity", 0.3)
        .attr("points", firstShade);


  for (var i = startHelix; i < startHelix+newLength; i+=size) {
      var quadPoints = (i) + " " + (height - size/2) + ", "
                        + (i+size/2) + " " + (height - size/2) + ", "
                        + (i+size) + " " + (height + size/2) + ", "
                        + (i+size/2) + " " + (height + size/2);

      if (i+10 > startHelix+newLength) quadPoints = (i) + " " + (height - size/2) + ", "
                                                + (i+size/2) + " " + (height - size/2) + ", "
                                                + (i+3*size/4) + " " + (height) + ", "
                                                + (i+3*size/4) + " " + (height + size/2) + ", "
                                                + (i+size/2) + " " + (height+size/2);

  helixGroup.append("polygon")
          .attr("fill", newColor)
          .attr("points", quadPoints);    

  }

  for (var i = startHelix+size/2; i < startHelix+newLength; i+=size) {
      var quadPoints = (i) + " " + (height + size/2) + ", "
                        + (i+size/2) + " " + (height + size/2) + ", "
                        + (i+size) + " " + (height - size/2) + ", "
                        + (i+size/2) + " " + (height - size/2);

      if (i+10 > startHelix+newLength) quadPoints = (i) + " " + (height + size/2) + ", "
                                                + (i+size/2) + " " + (height + size/2) + ", "
                                                + (i+3*size/4) + " " + (height) + ", "
                                                + (i+3*size/4) + " " + (height - size/2) + ", "
                                                + (i+size/2) + " " + (height-size/2);

  helixGroup.append("polygon")
          .attr("fill", newColor)
          .attr("opacity", 0.5)
          .attr("points", quadPoints);    

  }

  var middle = (endHeight<startHeight) ? -((Math.abs(endHeight-startHeight))/2) : ((Math.abs(endHeight-startHeight))/2);


  // helixGroup.on("click", function(){
  //     highlighted[n] = (highlighted[n] === j) ? 9999 : j;
  //     redrawD3();
  //     (highlighted[n] === 9999) ? (resetViewerSelection(n)) : highlightPV(n, j);
  //   });
}

function calculateCurve(loopEnd, loopBegin, elementWidth, xoffset, height){

  //Caluculate specific position in D3 canvas for start and length of curve
  var length = Math.ceil((loopEnd - loopBegin)*elementWidth);
  var startLoop = Math.ceil(loopBegin * elementWidth -2) + xoffset;

  var Cx = startLoop; // position loops start
  var Cy = height;  // height
  var Dx = Cx + length; // position of loops end
  var Dy = height; // height
  
  var Jx = Cx + (Dx - Cx) / 2;
  var Jy = Cy + (Dy - Cy) / 2;

  // console.log('Cx,Cy,Dx,Dy,Jx,Jy ',Cx,Cy,Dx,Dy,Jx,Jy);

  var curve = length > 180 ? 5 : 3;
  Jy = Jy-length/curve;
  //so the loops would not overlap the protein glyphs above
  if(Cy - Jy > 50) Jy = Cy - 50;
      
  var curveData = [[Cx, Cy], [Jx, Jy], [Dx, Dy]];
  var lineGenerator = d3.line().curve(d3.curveNatural);
  return lineGenerator(curveData);
}

function drawNewLoop(group, n,loopBegin,loopEnd,height,color,elementWidth,loopIndex){
  // console.log("LOOP: ",n,loopBegin,loopEnd,elementWidth);
  var loopCurve = group.append("g");

  var pathData = calculateCurve(loopEnd, loopBegin, elementWidth, xoffset, height);
    
  loopCurve.append("path")
            .attr("d", pathData)
            .attr("stroke", color)
            .attr("stroke-width", 3)
            .attr("fill", "none")
            .attr("pointer-events","visible") // handles click inside element which is not filled (fill:none)
            .on("click", function(){
              if(group !== superposition){
                highlightLoop(n, loopBegin, loopEnd, loopIndex);
                drawLoopOutline(n,loopBegin,loopEnd,elementWidth, height);
              }
  });
}

function drawLoopOutline(n,loopBegin,loopEnd,elementWidth, height){
  var outlineLoopCurve = juxtaposition.append("g")
                                      .attr("class", "loopOutLine");

  var pathData = calculateCurve(loopEnd, loopBegin, elementWidth, xoffset, height);
    
  outlineLoopCurve.append("path")
            .attr("d", pathData)
            .attr("stroke", "grey")
            .attr("stroke-width", 10)
            .attr("opacity", 0.3)
            .attr("fill", "none")
            .attr("pointer-events","visible") // handles click inside element which is not filled (fill:none)
            .on("click", function(){
              this.remove();
              var removeLoop = {start: loopBegin, end: loopEnd};
              highlighted[n].forEach(x => x.start === loopBegin && x.end === loopEnd ? highlighted[n].delete(x) : x);
              redrawD3();
              highlightPV(n);
              // loopInfo(event,loopBegin,loopEnd,n, elementWidth,loopIndex);
              // drawLoopOutline(loopBegin,loopEnd,height,elementWidth);
  });
}

function highlightLoop(n, start, end, loop_index){

  //This shouldn't happen
  if(highlighted[n] == null){
    highlighted[n] = new Set();
  }

  var newLoop = {start: start, end: end, index: loop_index};
  highlighted[n].add(newLoop);

  // console.log("Start: " + start + "  End: " + end);
  redrawD3();
  highlightPV(n);
}

function drawFluctation(n, height, start, length){
    // var fluctationValues = [];
    var bfactElementWidth = length / atomsFromPdb[n].length;
    var bfactPoins = [start + " " + height + ", "];
    var svgHeight = 30;

    let lastAminoAcid = 0;
    let numOfAtomsInAA = 1;
    let totalAAfluctation = 0;

    for (var i = 0; i < atomsFromPdb[n].length; i++) {

      //case of new amino acid
      if(atomsFromPdb[n][i][5] != lastAminoAcid) {
        lastAminoAcid = atomsFromPdb[n][i][5];

        totalAAfluctation += (atomsFromPdb[n][i][10] - lowestBfact)/(highestBfact-lowestBfact);
        thisBfactNorm = totalAAfluctation / numOfAtomsInAA;
        var calcHeight = height - svgHeight * thisBfactNorm - 5;
        if(isNaN(calcHeight)) calcHeight = height;
        bfactPoins += [start + i*bfactElementWidth*1.03 + " " + calcHeight + ", "];

        numOfAtomsInAA = 1;
        totalAAfluctation = 0;
      } else {
        numOfAtomsInAA++;
        totalAAfluctation += (atomsFromPdb[n][i][10] - lowestBfact)/(highestBfact-lowestBfact);
      }

    }

    var calcHeight = height - (svgHeight * totalAAfluctation / numOfAtomsInAA) - 5;
    if(isNaN(calcHeight)) calcHeight = height;
    bfactPoins += [start + (atomsFromPdb[n].length-1)*bfactElementWidth*1.03 + " " + calcHeight + ", "];    

    bfactPoins += [start + atomsFromPdb[n].length*bfactElementWidth*1.03 + " " + height];
    // console.log(fluctationValues)

    juxtaposition.append("polygon")
        .attr("fill", "#b6b6b6")
        .attr("opacity", 0.5)
        .attr("points", bfactPoins);
}

function drawJuxtaposition(n){

  juxtaposition.append("text")
          .attr("y", n*65+60)
          .attr("x", 0)
          .attr('text-anchor', 'left')
          .attr("class", "myLabel")
          .text(proteins[n]);

  var radialGradient = juxtaposition.append("defs")
    .append("radialGradient")
      .attr("id", "radial-gradient");

  radialGradient.append("stop")
      .attr("offset", "0%")
      .attr("stop-color", BallColors[n][0]);

  radialGradient.append("stop")
      .attr("offset", "100%")
      .attr("stop-color", "#fff");

  juxtaposition.append("circle")
          .attr("cx", xoffset/2)
          .attr("cy", n*65 + 70)
          .attr("r", 5)
          .attr("fill", "url(#radial-gradient)")//BallColors[n][0])
          .on("click", function(d) {
            var chain = Math.round((this.cy.animVal.value - 70)/65);
            var index = 0;
            viewer.forEach(function(object) {
              if(index === chain) object.setOpacity((BallColors[chain][0]==="green")? 0 : 1);
              index++;
            });
            // viewer.get(proteins[chain])
            viewer.requestRedraw();
            BallColors[chain] = [BallColors[chain][1], BallColors[chain][0]]
            radialGradient.select("stop").transition().attr("offset", "0%").attr("stop-color", BallColors[n][0]);
            d3.select(this).style("fill", "url(#radial-gradient)");
          });

  var startAA = juxtaZoom[n][0]; //od kt po kt (pole poli) pre kazdu sekvenciu kt tam mam ze od kt po kt poziciu sa to zobrazuje
  var endAA = juxtaZoom[n][1];
  if(juxtaElementSet) {
    juxtaElementWidth = thisElementWidth;
    juxtaElementSet = false;
  }

  var globalI = 0;
  

  if(n !== reference) {
    juxtaposition.append("line")
            .attr('x1', xoffset)
            .attr('y1', 70 + n*65)
            .attr('x2', thisElementWidth*(endAA-startAA))
            .attr('y2', 70 + n*65)
            .style('stroke', 'lightgray')
            .style('stroke-width', 1)
  }

  var lastHeight = 0;
  var lastSS = 0;
  var initHeight = 70 + n*65;
  var endHeight = 70 + n*65;

  drawFluctation(n, initHeight, xoffset, thisElementWidth*ss[n].length*0.975);
  
  // for (let index = 0; index < loops.length; index++) {
  //   drawNewLoop(n,loops[index].start,loops[index].end,initHeight,colorMolecule[n],thisElementWidth,index,5);
  // }
  let loopIndex = 0;
  let loopShift = null;
  var lastLoopIndex = [];
  
  for (var i = 0; i < ss[n].length - 1; i++) {      
      var thisSS = ss[n][i]; // ss[n] - retazec (HHHHEEEECCC..) sheetov coilov a helixov ss[n][i] - jeden item (pr. H)
      var start = i;
      // console.log('start i',start)
      while (ss[n][i+1] === thisSS){i++;  }
      
      if (loopIndex < loops[n].length && i >= loops[n][loopIndex].start){  
        if (loopShift == null){
          loopShift = loops[n][loopIndex].start - start;
          // loopShift = atomsFromPdb[n][0][1];
        }
        
        let strt = parseInt(loops[n][loopIndex].start) - parseInt(loopShift);
        let ennd = parseInt(loops[n][loopIndex].end) - parseInt(loopShift);

        //check if there is any nearby starting value
        var isThereCloseVal = false;
        for (var iii = 0; iii < lastLoopIndex.length; iii++) {
          if(Math.abs(lastLoopIndex[iii] - strt) < ss[n].length/20) {
            isThereCloseVal = true;
            break;
          }
        }
        if(!isThereCloseVal) {
          lastLoopIndex.push(strt);
          juxtaposition.append("text")
                      .attr("y", n*65+90)
                      .attr("x", strt*thisElementWidth+xoffset/2)
                      .attr('text-anchor', 'left')
                      // .attr("class", "myLabel")
                      .attr("fill", colorMolecule[n])
                      .style("font-size", "12px")
                      // .style("stroke-width", 0.5)
                      .text(strt);
        }

        //check if there is any nearby ending value
        isThereCloseVal = false;
        for (var jjj = 0; jjj < lastLoopIndex.length; jjj++) {
          if(Math.abs(lastLoopIndex[jjj] - ennd) < ss[n].length/20) {
            isThereCloseVal = true;
            break;
          }
        }
        if(!isThereCloseVal) {
          lastLoopIndex.push(ennd);
          juxtaposition.append("text")
                      .attr("y", n*65+90)
                      .attr("x", ennd*thisElementWidth+xoffset/2)
                      .attr('text-anchor', 'left')
                      // .attr("class", "myLabel")
                      .attr("fill", colorMolecule[n])
                      .style("font-size", "12px")
                      // .style("stroke-width", 0.5)
                      .text(ennd);
        }

        drawNewLoop(juxtaposition,n,strt,ennd,initHeight,colorMolecule[n],thisElementWidth,loopIndex);
        loopIndex++;
      }
      var gap = i - start + 1;
      // n - index of sequence
      // i - position in the sequence
      // globalI - position in the D3.js canvas
      // gap - number of residues in the ss

      var thisColor = colorMolecule[n]; //"#66FF00"
      if(highlighted[n] != null) {
        highlighted[n].forEach( function callback(loopI){
          //change colour if it is part of highlighted loop
          if((start >= loopI.start-1 && start < loopI.end) || (i >= loopI.start-1 && start < i.end)) thisColor = "#66FF00";
        });
      }

      if (thisSS === 'E') drawJuxtaArrow(juxtaposition,n, i, thisElementWidth, globalI, gap, initHeight, endHeight, thisColor);
      if (thisSS === 'H') drawJuxtaHelix(juxtaposition,n, i, thisElementWidth, globalI, gap, initHeight, endHeight, thisColor);
      if (thisSS === '-') drawJuxtaRect(juxtaposition,thisElementWidth, globalI,  gap, initHeight, endHeight, 3, "lightgray");
      if (thisSS === 'C') drawJuxtaRect(juxtaposition,thisElementWidth, globalI,  gap, initHeight, endHeight, 3, thisColor);

      globalI += Math.round( gap * thisElementWidth);
  }

  if(highlighted[n] != null) {
    highlighted[n].forEach( function callback(i){
      drawLoopOutline(n, i.start, i.end, thisElementWidth, initHeight);
    });

    // console.log(highlighted[n].length);
    // console.log(highlighted[n].get(0)[0] + "   " + highlighted[n].get(0)[1])
    // for (var i = 0; i < highlighted[n].length; i++){
    //   drawLoopOutline(n, highlighted[n].get(i)[0], highlighted[n].get(i)[1], thisElementWidth);
    // }
  }

}