/**
 * @hidden
 */
export class IgcDragService {
  constructor(element) {
    this.element = element;
    this.dragTolerance = 5;
    this.dragEdgeTolerance = 0;
    this.handleWheel = (event) => {
      event.preventDefault();
    };
    this.handleMouseDown = (event) => {
      // TODO Not sure if we need this
      // this.element.focus();
      // event.preventDefault();
      this.startX = event.clientX;
      this.startY = event.clientY;
      this.lastX = this.startX;
      this.lastY = this.startY;
      this.subscribeDragEvents();
    };
    this.handleMouseMove = (event) => {
      event.preventDefault();
      const maxHeight = document.documentElement.clientHeight;
      const maxWidth = document.documentElement.clientWidth;
      if (event.clientX < this.dragEdgeTolerance) {
        this.currentX = this.dragEdgeTolerance;
      }
      else if (event.clientX > maxWidth - this.dragEdgeTolerance) {
        this.currentX = maxWidth - this.dragEdgeTolerance;
      }
      else {
        this.currentX = event.clientX;
      }
      if (event.clientY < this.dragEdgeTolerance) {
        this.currentY = this.dragEdgeTolerance;
      }
      else if (event.clientY > maxHeight - this.dragEdgeTolerance) {
        this.currentY = maxHeight - this.dragEdgeTolerance;
      }
      else {
        this.currentY = event.clientY;
      }
      if (!this.dragStarted) {
        if (this.forcedDrag) {
          this.forcedDrag = false;
          this.startX = this.currentX;
          this.startY = this.currentY;
          this.lastX = this.startX;
          this.lastY = this.startY;
          this.triggerDragStart();
        }
        else {
          const offsetX = this.currentX - this.lastX;
          const offsetY = this.currentY - this.lastY;
          if (Math.abs(offsetX) > this.dragTolerance || Math.abs(offsetY) > this.dragTolerance) {
            this.triggerDragStart();
          }
        }
      }
      if (!this.dragStarted) {
        return;
      }
      if (this.dragMove) {
        const args = {
          offsetX: this.currentX - this.lastX,
          offsetY: this.currentY - this.lastY,
          totalOffsetX: this.currentX - this.startX,
          totalOffsetY: this.currentY - this.startY,
          clientX: this.currentX,
          clientY: this.currentY
        };
        this.dragMove(args);
        if (args.cancel) {
          this.unsubscribeDragEvents();
        }
      }
      this.lastX = this.currentX;
      this.lastY = this.currentY;
    };
    this.handleMouseUp = (event) => {
      this.unsubscribeDragEvents();
      if (this.dragStarted && this.dragEnd) {
        this.dragEnd({
          offsetX: this.currentX - this.startX,
          offsetY: this.currentY - this.startY,
          clientX: event.clientX,
          clientY: event.clientY
        });
      }
    };
    this.element.addEventListener('mousedown', this.handleMouseDown, false);
  }
  triggerDragStart() {
    if (this.dragStart) {
      const args = {
        clientX: this.startX,
        clientY: this.startY
      };
      this.dragStart(args);
      if (args.cancel) {
        this.unsubscribeDragEvents();
        return;
      }
    }
    this.dragStarted = true;
  }
  subscribeDragEvents() {
    this.dragStarted = false;
    document.documentElement.addEventListener('mousemove', this.handleMouseMove, false);
    document.documentElement.addEventListener('mouseup', this.handleMouseUp, false);
    document.documentElement.addEventListener('wheel', this.handleWheel, { passive: false });
  }
  unsubscribeDragEvents() {
    document.documentElement.removeEventListener('mousemove', this.handleMouseMove, false);
    document.documentElement.removeEventListener('mouseup', this.handleMouseUp, false);
    document.documentElement.removeEventListener('wheel', this.handleWheel);
  }
  destroy() {
    this.element.removeEventListener('mousedown', this.handleMouseDown, false);
    this.unsubscribeDragEvents();
    this.element = null;
    this.dragStart = null;
    this.dragEnd = null;
    this.dragMove = null;
  }
  forceDragging() {
    this.forcedDrag = true;
    this.subscribeDragEvents();
  }
}
