//import * as d3 from 'd3';

function polygonToPath(polygon) {
  return ("M" + (polygon.map(function (d) { return d.join(','); }).join('L')));
}

function distance(pt1, pt2) {
  return Math.sqrt(Math.pow( (pt2[0] - pt1[0]), 2 ) + Math.pow( (pt2[1] - pt1[1]), 2 ));
}

function lasso(camera) {
  var dispatch = d3.dispatch('start', 'end');

  // distance last point has to be to first point before it auto closes when mouse is released
  var closeDistance = 75;

  function lasso(root) {
    // append a <g> with a rect
    var g = root.append('g').attr('class', 'lasso-group');
    var bbox = root.node().getBoundingClientRect();

    var area = g
      .append('rect')
      .attr('width', bbox.width)
      .attr('height', bbox.height)
      .attr('fill', 'tomato')
      .attr('opacity', 0);

    var drag = d3
      .drag()
      .on('start', handleDragStart)
      .on('drag', handleDrag)
      .on('end', handleDragEnd);

    area.call(drag);

    var lassoPolygon;
    var lassoPath;
    var closePath;

    function handleDragStart() {
      var newMouseEvent = []
      newMouseEvent.push(d3.mouse(this)[0])
      newMouseEvent.push(d3.mouse(this)[1])
      lassoPolygon = [newMouseEvent];
      if (lassoPath) {
        lassoPath.remove();
      }

      lassoPath = g
        .append('path')
        .attr('fill', '#0bb')
        .attr('fill-opacity', 0.1)
        .attr('stroke', '#0bb')
        .attr('stroke-dasharray', '3, 3');

      closePath = g
        .append('line')
        .attr('x2', lassoPolygon[0][0])
        .attr('y2', lassoPolygon[0][1])
        .attr('stroke', '#0bb')
        .attr('stroke-dasharray', '3, 3')
        .attr('opacity', 0);
      dispatch.call('start', lasso, lassoPolygon);
    }

    function handleDrag() {
      var point = d3.mouse(this);
      lassoPolygon.push(point);
      lassoPath.attr('d', polygonToPath(lassoPolygon));

      // indicate if we are within closing distance
      if (
        distance(lassoPolygon[0], lassoPolygon[lassoPolygon.length - 1]) <
        closeDistance
      ) {
        closePath
          .attr('x1', point[0])
          .attr('y1', point[1])
          .attr('opacity', 1);
      } else {
        closePath.attr('opacity', 0);
      }
    }

    function handleDragEnd() {
      // remove the close path
      closePath.remove();
      closePath = null;

      // succesfully closed
      if (
        distance(lassoPolygon[0], lassoPolygon[lassoPolygon.length - 1]) <
        closeDistance
      ) {
        lassoPath.attr('d', polygonToPath(lassoPolygon) + 'Z');
        dispatch.call('end', lasso, lassoPolygon);

        // otherwise cancel
      } else {
        lassoPath.remove();
        lassoPath = null;
        lassoPolygon = null;
      }
    }

    lasso.reset = function () {
      if (lassoPath) {
        lassoPath.remove();
        lassoPath = null;
      }

      lassoPolygon = null;
      if (closePath) {
        closePath.remove();
        closePath = null;
      }
    };
  }

  lasso.on = function (type, callback) {
    dispatch.on(type, callback);
    return lasso;
  };

  return lasso;
}

