import { JSUtils } from '@sankhyalabs/core';
import { h, Host } from '@stencil/core';
import { EzScrollDirection } from './EzScrollDirection';
export class EzScroller {
  constructor() {
    this._shadowStart = "ez-scroller__wrapper--shadow-start";
    this._shadowEnd = "ez-scroller__wrapper--shadow-end";
    this.isActive = false;
    this.direction = undefined;
    this.locked = false;
    this.activeShadow = false;
  }
  //---------------------------------------------
  // Private methods
  //---------------------------------------------
  getContainerClass() {
    return `ez-scroller__container ez-scroller__container--${this.direction}
      ${this.locked || !this.isActive ? " ez-scroller__container--locked" : ""}
    `;
  }
  getWrapperClass() {
    return `ez-scroller__wrapper ez-scroller__wrapper--${this.direction}`;
  }
  finishDrag() {
    if (this._controller) {
      this._container.classList.remove("dragging");
    }
  }
  updateScroller() {
    const container = this._container;
    if (container == undefined) {
      return;
    }
    let remainingScroll;
    if (this.direction === EzScrollDirection.HORIZONTAL) {
      const { scrollWidth, clientWidth, scrollLeft } = container;
      remainingScroll = scrollWidth - clientWidth - Math.ceil(scrollLeft);
      this._startHidden = container.scrollLeft > 0;
    }
    else if (this.direction === EzScrollDirection.VERTICAL) {
      const { scrollHeight, clientHeight, scrollTop } = container;
      remainingScroll = scrollHeight - clientHeight - Math.ceil(scrollTop);
      this._startHidden = container.scrollTop > 0;
    }
    this._endHidden = remainingScroll > 0;
    this.isActive = this._startHidden || this._endHidden || this.isActiveScroller();
    this.updateShadow();
  }
  updateShadow() {
    const wrapper = this._wrapper;
    if (!this.activeShadow || wrapper == undefined) {
      return;
    }
    const shadowPositions = ["", "start", "end", "middle"];
    const currentPosition = shadowPositions[Number(this._startHidden) | Number(this._endHidden) << 1];
    if (currentPosition === "start") {
      wrapper.classList.add(this._shadowStart);
      wrapper.classList.remove(this._shadowEnd);
    }
    else if (currentPosition === "end") {
      wrapper.classList.remove(this._shadowStart);
      wrapper.classList.add(this._shadowEnd);
    }
    else if (currentPosition === "middle") {
      wrapper.classList.add(this._shadowStart);
      wrapper.classList.add(this._shadowEnd);
    }
    else {
      wrapper.classList.remove(this._shadowStart);
      wrapper.classList.remove(this._shadowEnd);
    }
  }
  configResize() {
    const container = this._container;
    if (container == undefined) {
      return;
    }
    if (this._resizeObserver != undefined) {
      this._resizeObserver.unobserve(container);
    }
    this._resizeObserver = new ResizeObserver(JSUtils.debounce(this.updateScroller.bind(this), 200));
    this._resizeObserver.observe(container);
  }
  getContainerElement() {
    return h("div", { ref: ref => this._container = ref, class: this.getContainerClass() }, h("slot", null));
  }
  isActiveScroller() {
    if (this._container == undefined) {
      return false;
    }
    return this._container.scrollWidth > this._container.clientWidth
      || this._container.scrollHeight > this._container.clientHeight;
  }
  //---------------------------------------------
  // Event handlers
  //---------------------------------------------
  clickListener(evt) {
    if (this._controller && this._controller.didScroll()) {
      evt.preventDefault();
      evt.stopPropagation();
      evt.stopImmediatePropagation();
    }
  }
  mouseDownHandler(evt) {
    if (this.locked) {
      this.finishDrag();
      return;
    }
    if (!this._controller) {
      this._controller = new ScrollCtrl(this._container);
    }
    this._controller.startDragg(evt);
    this._container.classList.add("dragging");
  }
  mouseUpHandler() {
    this.finishDrag();
  }
  mouseMoveHandler(evt) {
    if (this.locked) {
      this.finishDrag();
      return;
    }
    if (this._controller) {
      if (evt.buttons === 0) {
        this.finishDrag();
      }
      else {
        this._controller.doScroll(evt);
      }
    }
  }
  componentDidRender() {
    var _a, _b;
    if (this._container == undefined) {
      return;
    }
    if (this.direction === EzScrollDirection.BOTH) {
      (_a = this._wrapper) === null || _a === void 0 ? void 0 : _a.classList.remove(this._shadowStart);
      (_b = this._wrapper) === null || _b === void 0 ? void 0 : _b.classList.remove(this._shadowEnd);
      this.isActive = this.isActiveScroller();
      return;
    }
    this._container.onscroll = this.updateScroller.bind(this);
    this.configResize();
    this.updateScroller();
  }
  render() {
    return (h(Host, null, this.activeShadow
      ? h("div", { ref: ref => this._wrapper = ref, class: this.getWrapperClass() }, this.getContainerElement())
      : this.getContainerElement()));
  }
  static get is() { return "ez-scroller"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() {
    return {
      "$": ["ez-scroller.css"]
    };
  }
  static get styleUrls() {
    return {
      "$": ["ez-scroller.css"]
    };
  }
  static get properties() {
    return {
      "direction": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "EzScrollDirection",
          "resolved": "EzScrollDirection.BOTH | EzScrollDirection.HORIZONTAL | EzScrollDirection.VERTICAL",
          "references": {
            "EzScrollDirection": {
              "location": "import",
              "path": "./EzScrollDirection"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define a dire\u00E7\u00E3o em que haver\u00E1 scroll."
        },
        "attribute": "direction",
        "reflect": false
      },
      "locked": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define se o `scroll` estar\u00E1 bloqueado."
        },
        "attribute": "locked",
        "reflect": false,
        "defaultValue": "false"
      },
      "activeShadow": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define se haver\u00E1 efeito de sombreado."
        },
        "attribute": "active-shadow",
        "reflect": false,
        "defaultValue": "false"
      }
    };
  }
  static get states() {
    return {
      "isActive": {}
    };
  }
  static get listeners() {
    return [{
        "name": "click",
        "method": "clickListener",
        "target": undefined,
        "capture": true,
        "passive": false
      }, {
        "name": "mousedown",
        "method": "mouseDownHandler",
        "target": undefined,
        "capture": false,
        "passive": true
      }, {
        "name": "mouseup",
        "method": "mouseUpHandler",
        "target": undefined,
        "capture": false,
        "passive": true
      }, {
        "name": "mousemove",
        "method": "mouseMoveHandler",
        "target": undefined,
        "capture": false,
        "passive": true
      }];
  }
}
class ScrollCtrl {
  constructor(scrollablePanel) {
    this.scrollablePanel = scrollablePanel;
  }
  startDragg(evt) {
    this.startX = this.measureX(evt);
    this.startY = this.measureY(evt);
    this.scrollWidth = 0;
    this.scrollHeight = 0;
  }
  measureX(e) {
    return e.pageX - this.scrollablePanel.offsetLeft;
  }
  measureY(e) {
    return e.pageY - this.scrollablePanel.offsetTop;
  }
  doScroll(e) {
    const x = this.measureX(e);
    const y = this.measureY(e);
    if (x != this.startX || y != this.startY) {
      const scrollX = x - this.startX;
      const scrollY = y - this.startY;
      this.startX += scrollX;
      this.startY += scrollY;
      this.scrollWidth += Math.abs(scrollX);
      this.scrollHeight += Math.abs(scrollY);
      this.scrollablePanel.scrollLeft = Math.max(0, this.scrollablePanel.scrollLeft - scrollX);
      this.scrollablePanel.scrollTop = Math.max(0, this.scrollablePanel.scrollTop - scrollY);
    }
  }
  didScroll() {
    const tollerance = 5;
    return this.scrollHeight > tollerance || this.scrollWidth > tollerance;
  }
}
