import * as d3 from 'd3';

export default class BarChartNegativeValues {

  private svg;
  private targetElementId: string;
  private data: Map<string, number> = new Map();
  private paramColors: Map<string, string> = new Map();
  private parent;

  constructor(targetElementId: string, parent) {
    this.targetElementId = targetElementId;
    this.parent = parent;
  }

  public setChart(data: Map<string, number>, paramColors: Map<string, string>) {
    this.paramColors = paramColors;
    this.data = data;
    this.build();
  }

  //render chart
  private build() {

    let self = this;

    this.svg = d3
      .select('#' + this.targetElementId)
      .selectAll("*")
      .remove();

    let keys = Array.from(this.data.keys());
    let values = Array.from(this.data.values());

    // init the container
    let d3Container: HTMLElement | null =
      document.getElementById(this.targetElementId);


    if (!d3Container) {
      throw new Error("no container with id '" + this.targetElementId + "' found.");
    } 

    const margin = 30;
    const width = 500 - 2 * margin;
    const height = 500 - 2 * margin;

    // init the svg canvas
    this.svg = d3
      .select('#' + this.targetElementId)
      .append('svg')
      .attr(
        'viewBox',
        -margin + ' ' + -margin + ' ' + 550 + ' ' + 600
      )
      .classed('svg-content-responsive', true);

    const chart = this.svg.append('g')
      .attr('transform', `translate(${margin}, ${margin})`)

      //xScale
      const x = d3.scaleBand()
        .range([0, width])
        .domain(keys)
        .padding(0.1)

      chart.append('g')
          .attr('transform', `translate(0, ${height})`)
          .call(d3.axisBottom(x));

      //yScale
      var y0 = Math.abs(d3.min(values));
      var y1 = Math.abs(d3.max(values));
      var y2;
      if(y0 > y1){
        y2 = y0;
      } else {
        y2 = y1;
      }

      var y = d3.scaleLinear()
          .domain([-y2, y2])
          .range([height,0])
          .nice();
      
      var yAxis = d3.axisLeft()
          .scale(y)

      chart.append("g")
          .attr("class", "x axis")
          .call(yAxis);

          //arrow
      chart.append("svg:defs").append("svg:marker")
      .attr("id", "triangle")
      .attr("refX", 6)
      .attr("refY", 6)
      .attr("markerWidth", 30)
      .attr("markerHeight", 30)
      .attr("markerUnits","userSpaceOnUse")
      .attr("orient", "auto")
      .append("path")
      .attr("d", "M 0 0 12 6 0 12 3 6")
      .style("fill", "white");

      //Y-label
      chart.append('text')
      .attr('x', -(height / 4))
      .attr('y', -(margin * 1.3))
      .attr('transform', 'rotate(-90)')
      .attr('text-anchor', 'start')
      .attr("font-family", "sans-serif")
      .attr("font-size", "13px")
      .attr("fill", "white")
      .text('ROI')
      chart.append("line")
          .attr("x1",-(margin * 1.5))  
          .attr("y1",(height / 2) - (margin/3))  
          .attr("x2",-(margin * 1.5))  
          .attr("y2",(height / 3) - (margin/3))  
          .attr("fill","white")  
          .attr("stroke", "white")
          .attr("stroke-width",2)  
          .attr("marker-end","url(#triangle)");  

      chart.append('text')
      .attr('x', -(height  - (height / 4)))
      .attr('y', -(margin * 1.3))
      .attr('transform', 'rotate(-90)')
      .attr('text-anchor', 'end')
      .attr("font-family", "sans-serif")
      .attr("font-size", "13px")
      .attr("fill", "white")
      .text('non-ROI')
      chart.append("line")
          .attr("x1",-(margin * 1.5))  
          .attr("y1",(height / 2) + (margin/3))  
          .attr("x2",-(margin * 1.5))  
          .attr("y2",(height / 1.5) + (margin/3))  
          .attr("fill","white")  
          .attr("stroke", "white")
          .attr("stroke-width",2)  
          .attr("marker-end","url(#triangle)");  


      //grid lines
      chart.append('g')
      .attr('class', 'grid')
      .call(d3.axisLeft()
          .scale(y)
          .tickSize(-width, 0, 0)
          .tickFormat(''))

      
      //bars    
      chart.selectAll()
      .data(values)
      .enter()
      .append('rect')
      .attr("class", function(d) { return d < 0 ? "bar negative" : "bar positive"; })
      .attr("x", function(d) { return x(keys[values.indexOf(d)])})
      .attr("y", function(d) { return y(Math.max(0, d)); })
      .attr("height", function(d) { return Math.abs(y(d) - y(0)); })
      .attr('width', x.bandwidth())
      .attr('name', function(d) { return keys[values.indexOf(d)] })
      .attr('stroke', 'white')
      .attr('stroke-width', '0')
     .style('fill', function(d) {
       var param = keys[values.indexOf(d)];
        return self.getColor(param);
      }); 

    // bar labels
    chart.selectAll()
    .data(values)
    .enter()
    .append("text")
    .text(function(d) {
      var num = d;
      var n = num.toFixed(2);
      return n;
    })
    .attr("x", function(d) { 
      var a = x(keys[values.indexOf(d)]);
      return a + 10;
    })
    .attr("y", function(d) {
      var b = y(0);
      if( d < 0){
        return b - 5;
      } else {
        return b + 15;
      }
     
    })
    .attr("id", function(d) { return keys[values.indexOf(d)] })
    .attr("font-family", "sans-serif")
    .attr("font-size", "13px")
    .attr("fill", "white")
    .attr('opacity', 0);
 



      //interactivity
      chart.selectAll('rect')
      .on('mouseenter', handleMouseEnter)
      .on('mouseleave', handleMouseLeave)
      .on('click', handleMouseClick)     
    
       // Create Event Handlers for mouseEnter
      function handleMouseEnter(this) {  // Add interactivity

        //select rect, change opacity
        d3.select(this)
        .attr('opacity', 0.4)
        .attr('stroke-width', '2')
        //select text
        var name = d3.select(this).attr("name");
        d3.select("#" + name)
        .attr('opacity', 1);

        }

      // Create Event Handlers for mouseLeave
      function handleMouseLeave(this) {  // Add interactivity

        //select rect, change opacity
        d3.select(this)
        .attr('opacity', 1)
        .attr('stroke-width', '0')
        //select text
        var name = d3.select(this).attr("name");
        d3.select("#" + name)
        .attr('opacity', 0);

        }

        function handleMouseClick(this) {
          var name = d3.select(this).attr("name");
          self.parent.showTable(name);

        }
  }

  private getColor(param: string) : string{
    var s = this.paramColors.get(param);
    if(s != undefined){
      return s;
    } else {
      return 'white';
    }
  }
}
