import Draw from 'ol/interaction/Draw';
import Overlay from 'ol/Overlay';
import {
  Circle as CircleStyle,
  Fill,
  Stroke,
  Style
} from 'ol/style';
import {
  LineString,
  Polygon
} from 'ol/geom';
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import {
  unByKey
} from 'ol/Observable';

class measureTool {
  constructor(map) {
    this.map = map;
    this.source = new VectorSource();
    this.vector = new VectorLayer({
      source: this.source,
      zIndex: 1000,
      style: new Style({
        fill: new Fill({
          color: 'rgba(255, 255, 255, 0.2)',
        }),
        stroke: new Stroke({
          color: '#ffcc33',
          width: 2,
        }),
        image: new CircleStyle({
          radius: 7,
          fill: new Fill({
            color: '#ffcc33',
          }),
        }),
      }),
    });
    this.map.addLayer(this.vector);

    /**
     * Currently drawn feature.
     * @type {import("../src/ol/Feature.js").default}
     */
    this.sketch;

    /**
     * The help tooltip element.
     * @type {HTMLElement}
     */
    this.helpTooltipElement;

    /**
     * Overlay to show the help messages.
     * @type {Overlay}
     */
    this.helpTooltip;

    /**
     * The measure tooltip element.
     * @type {HTMLElement}
     */
    this.measureTooltipElement;

    /**
     * Overlay to show the measurement.
     * @type {Overlay}
     */
    this.measureTooltip;

    this.overlayArr = [];

    /**
     * Message to show when the user is drawing a polygon.
     * @type {string}
     */
    this.continuePolygonMsg = '继续点击地图绘制测量区域';

    /**
     * Message to show when the user is drawing a line.
     * @type {string}
     */
    this.continueLineMsg = '继续点击地图绘制测量路线';

    this.draw; // global so we can remove it later

    this.createHelpTooltip();
  }

  start(measureType) {
    let that = this;
    const type = measureType == 'area' ? 'Polygon' : 'LineString';
    this.draw = new Draw({
      source: this.source,
      type: type,
      style: new Style({
        fill: new Fill({
          color: 'rgba(255, 255, 255, 0.2)',
        }),
        stroke: new Stroke({
          color: 'rgba(0, 0, 0, 0.5)',
          lineDash: [10, 10],
          width: 2,
        }),
        image: new CircleStyle({
          radius: 5,
          stroke: new Stroke({
            color: 'rgba(0, 0, 0, 0.7)',
          }),
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)',
          }),
        }),
      }),
    });
    this.map.addInteraction(this.draw);

    this.pointermove_event = this.map.on('pointermove', function (evt) {
      if (evt.dragging) {
        return;
      }
      /** @type {string} */
      let helpMsg = '点击地图进行测量';

      if (that.sketch) {
        const geom = that.sketch.getGeometry();
        if (geom instanceof Polygon) {
          helpMsg = that.continuePolygonMsg;
        } else if (geom instanceof LineString) {
          helpMsg = that.continueLineMsg;
        }
      }

      that.helpTooltipElement.innerHTML = helpMsg;
      that.helpTooltip.setPosition(evt.coordinate);

      that.helpTooltipElement.classList.remove('hidden');
    });

    this.map.getViewport().addEventListener('mouseout', d);

    function d(params) {
      if (that.helpTooltipElement == null || that.helpTooltipElement == undefined) {
        that.map.getViewport().removeEventListener('mouseout', d);
        return;
      }
      that.helpTooltipElement.classList.add('hidden');
    }

    let listener;
    this.draw.on('drawstart', function (evt) {

      that.createMeasureTooltip()

      // set sketch
      that.sketch = evt.feature;

      /** @type {import("../src/ol/coordinate.js").Coordinate|undefined} */
      let tooltipCoord = evt.coordinate;

      listener = that.sketch.getGeometry().on('change', function (evt) {
        const geom = evt.target;
        let output;
        if (geom instanceof Polygon) {
          output = that.formatArea(geom);
          tooltipCoord = geom.getInteriorPoint().getCoordinates();
        } else if (geom instanceof LineString) {
          output = that.formatLength(geom);
          tooltipCoord = geom.getLastCoordinate();
        }
        that.measureTooltipElement.innerHTML = output;
        that.measureTooltip.setPosition(tooltipCoord);
      });
    });

    this.draw.on('drawend', function () {
      that.measureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
      that.measureTooltip.setOffset([0, -7]);
      that.overlayArr.push(that.measureTooltip);
      // unset sketch
      that.sketch = null;
      // unset tooltip so that a new one can be created
      // that.measureTooltipElement.innerHTML = "";
      unByKey(listener);
    });
  }

  /**
   * Creates a new help tooltip
   */
  createHelpTooltip() {
    this.helpTooltipElement = document.createElement('div');
    this.helpTooltipElement.className = 'ol-tooltip hidden';
    this.helpTooltip = new Overlay({
      element: this.helpTooltipElement,
      offset: [15, 0],
      positioning: 'center-left',
    });
    this.map.addOverlay(this.helpTooltip);
  }

  /**
   * Creates a new measure tooltip
   */
  createMeasureTooltip() {
    this.measureTooltipElement = document.createElement('div');
    this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
    this.measureTooltip = new Overlay({
      element: this.measureTooltipElement,
      offset: [0, -15],
      positioning: 'bottom-center',
      stopEvent: false,
      insertFirst: false,
    });
    this.map.addOverlay(this.measureTooltip);
  }

  /**
   * Format length output.
   * @param {LineString} line The line.
   * @return {string} The formatted length.
   */
  formatLength(line) {
    const length = getLength(line);
    let output;
    if (length > 100) {
      output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km';
    } else {
      output = Math.round(length * 100) / 100 + ' ' + 'm';
    }
    return output;
  };

  /**
   * Format area output.
   * @param {Polygon} polygon The polygon.
   * @return {string} Formatted area.
   */
  formatArea(polygon) {
    const area = getArea(polygon);
    let output;
    if (area > 10000) {
      output = Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>';
    } else {
      output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>';
    }
    return output;
  };

  stop() {
    let that = this;
    if (this.draw) {
      this.map.removeInteraction(this.draw);
      this.draw = null;
      unByKey(this.pointermove_event);
      if (this.helpTooltip) {
        this.helpTooltip.setPosition(undefined)
      }
      if (this.measureTooltip) {
        this.measureTooltip.setPosition(undefined)
      }
      if (this.overlayArr.length > 0) {
        this.overlayArr.map(function (item) {
          that.map.removeOverlay(item);
        })
        this.overlayArr = [];
      }
      if (this.source.getFeatures().length != 0) {
        this.source.getFeatures().forEach(function (feature) {
          that.source.removeFeature(feature)
        })
      }
    }
  }
}

export default measureTool
