import ol_interaction_Interaction from 'ol/interaction/Interaction.js'
import ol_ext_element from '../util/element.js';

/** Interaction hover do to something when hovering a feature
 * @constructor
 * @extends {ol_interaction_Interaction}
 * @fires hover, enter, leave
 * @param {olx.interaction.HoverOptions} 
 *  @param { string | undefined } options.cursor css cursor propertie or a function that gets a feature, default: none
 *  @param {function | undefined} options.featureFilter filter a function with two arguments, the feature and the layer of the feature. Return true to select the feature 
 *  @param {function | undefined} options.layerFilter filter a function with one argument, the layer to test. Return true to test the layer
 *  @param {Array<ol.layer> | undefined} options.layers a set of layers to test
 *  @param {number | undefined} options.hitTolerance Hit-detection tolerance in pixels.
 *  @param { function | undefined } options.handleEvent Method called by the map to notify the interaction that a browser event was dispatched to the map. The function may return false to prevent the propagation of the event to other interactions in the map's interactions chain.
 */
var ol_interaction_Hover = class olinteractionHover extends ol_interaction_Interaction {
  constructor(options) {
    if (!options)
    options = options || {};

    var dragging = false;

    super({
      handleEvent: function (e) {
        if (!self.getActive())
          return true;
        switch (e.type) {
          case 'pointerdrag': {
            dragging = true;
            break;
          }
          case 'pointerup': {
            dragging = false;
            break;
          }
          case 'pointermove': {
            if (!dragging) {
              self.handleMove_(e);
            }
            break;
          }
        }
        if (options.handleEvent)
          return options.handleEvent(e);
        return true;
      }
    });
    var self = this;

    this.setLayerFilter(options.layerFilter);
    if (options.layers && options.layers.length) {
      this.setLayerFilter(function (l) {
        return (options.layers.indexOf(l) >= 0);
      });
    }
    this.setFeatureFilter(options.featureFilter);
    this.set('hitTolerance', options.hitTolerance);
    this.setCursor(options.cursor);
  }
  /**
   * Remove the interaction from its current map, if any,  and attach it to a new
   * map, if any. Pass `null` to just remove the interaction from the current map.
   * @param {ol.Map} map Map.
   * @api stable
   */
  setMap(map) {
    if (this.previousCursor_ !== undefined && this.getMap()) {
      ol_ext_element.setCursor(this.getMap(), this.previousCursor_);
      this.previousCursor_ = undefined;
    }
    super.setMap(map);
  }
  /** Activate / deactivate interaction
   * @param {boolean} b
   */
  setActive(b) {
    super.setActive(b);
    if (this.cursor_ && this.getMap() && this.getMap().getTargetElement()) {
      if (this.previousCursor_ !== undefined) {
        ol_ext_element.setCursor(this.getMap(), this.previousCursor_);
        this.previousCursor_ = undefined;
      }
    }
  }
  /**
   * Set cursor on hover
   * @param { string } cursor css cursor propertie or a function that gets a feature, default: none
   * @api stable
   */
  setCursor(cursor) {
    if (!cursor && this.previousCursor_ !== undefined && this.getMap()) {
      ol_ext_element.setCursor(this.getMap(), this.previousCursor_);
      this.previousCursor_ = undefined;
    }
    this.cursor_ = cursor;
  }
  /** Feature filter to get only one feature
  * @param {function} filter a function with two arguments, the feature and the layer of the feature. Return true to select the feature
  */
  setFeatureFilter(filter) {
    if (typeof (filter) == 'function')
      this.featureFilter_ = filter;
    else
      this.featureFilter_ = function () { return true; };
  }
  /** Feature filter to get only one feature
  * @param {function} filter a function with one argument, the layer to test. Return true to test the layer
  */
  setLayerFilter(filter) {
    if (typeof (filter) == 'function')
      this.layerFilter_ = filter;
    else
      this.layerFilter_ = function () { return true; };
  }
  /** Get features whenmove
  * @param {ol.event} e "move" event
  */
  handleMove_(e) {
    var map = this.getMap();
    if (map) {
      //var b = map.hasFeatureAtPixel(e.pixel);
      var feature, layer;
      var self = this;
      var b = map.forEachFeatureAtPixel(
        e.pixel,
        function (f, l) {
          if (self.featureFilter_.call(null, f, l)) {
            feature = f;
            layer = l;
            return true;
          } else {
            feature = layer = null;
            return false;
          }
        }, {
        hitTolerance: this.get('hitTolerance'),
        layerFilter: self.layerFilter_
      }
      );

      if (b)
        this.dispatchEvent({
          type: 'hover',
          feature: feature,
          layer: layer,
          coordinate: e.coordinate,
          pixel: e.pixel,
          map: e.map,
          originalEvent: e.originalEvent,
          dragging: e.dragging
        });

      if (this.feature_ === feature && this.layer_ === layer) {
        /* ok */
      } else {
        this.feature_ = feature;
        this.layer_ = layer;
        if (feature) {
          this.dispatchEvent({
            type: 'enter',
            feature: feature,
            layer: layer,
            coordinate: e.coordinate,
            pixel: e.pixel,
            map: e.map,
            originalEvent: e.originalEvent,
            dragging: e.dragging
          });
        } else {
          this.dispatchEvent({
            type: 'leave',
            coordinate: e.coordinate,
            pixel: e.pixel,
            map: e.map,
            originalEvent: e.originalEvent,
            dragging: e.dragging
          });
        }
      }

      if (this.cursor_) {
        var style = map.getTargetElement().style;
        if (b) {
          if (style.cursor != this.cursor_) {
            this.previousCursor_ = style.cursor;
            ol_ext_element.setCursor(map, this.cursor_);
          }
        } else if (this.previousCursor_ !== undefined) {
          ol_ext_element.setCursor(map, this.previousCursor_);
          this.previousCursor_ = undefined;
        }
      }
    }
  }
}

export default ol_interaction_Hover
