import { DirHelper } from './vaadin-dir-helper.js';
/**
 * Array of Vaadin custom element classes that have been subscribed to the dir changes.
 */

const directionSubscribers = [];

const directionUpdater = function () {
  const documentDir = getDocumentDir();
  directionSubscribers.forEach(element => {
    alignDirs(element, documentDir);
  });
};

let scrollType;
const directionObserver = new MutationObserver(directionUpdater);
directionObserver.observe(document.documentElement, {
  attributes: true,
  attributeFilter: ['dir']
});

const alignDirs = function (element, documentDir) {
  if (documentDir) {
    element.setAttribute('dir', documentDir);
  } else {
    element.removeAttribute('dir');
  }
};

const getDocumentDir = function () {
  return document.documentElement.getAttribute('dir');
};
/**
 * @polymerMixin
 */


export const DirMixin = superClass => class VaadinDirMixin extends superClass {
  static get properties() {
    return {
      /**
       * @protected
       */
      dir: {
        type: String,
        readOnly: true
      }
    };
  }
  /** @protected */


  static finalize() {
    super.finalize();

    if (!scrollType) {
      scrollType = DirHelper.detectScrollType();
    }
  }
  /** @protected */


  connectedCallback() {
    super.connectedCallback();

    if (!this.hasAttribute('dir')) {
      this.__subscribe();

      alignDirs(this, getDocumentDir());
    }
  }
  /** @protected */


  attributeChangedCallback(name, oldValue, newValue) {
    super.attributeChangedCallback(name, oldValue, newValue);

    if (name !== 'dir') {
      return;
    } // New value equals to the document direction and the element is not subscribed to the changes


    const newValueEqlDocDir = newValue === getDocumentDir() && directionSubscribers.indexOf(this) === -1; // Value was emptied and the element is not subscribed to the changes

    const newValueEmptied = !newValue && oldValue && directionSubscribers.indexOf(this) === -1; // New value is different and the old equals to document direction and the element is not subscribed to the changes

    const newDiffValue = newValue !== getDocumentDir() && oldValue === getDocumentDir();

    if (newValueEqlDocDir || newValueEmptied) {
      this.__subscribe();

      alignDirs(this, getDocumentDir());
    } else if (newDiffValue) {
      this.__subscribe(false);
    }
  }
  /** @protected */


  disconnectedCallback() {
    super.disconnectedCallback();

    this.__subscribe(false);

    this.removeAttribute('dir');
  }
  /** @private */


  __subscribe(push = true) {
    if (push) {
      directionSubscribers.indexOf(this) === -1 && directionSubscribers.push(this);
    } else {
      directionSubscribers.indexOf(this) > -1 && directionSubscribers.splice(directionSubscribers.indexOf(this), 1);
    }
  }
  /**
   * @param {Element} element
   * @return {number}
   * @protected
   */


  __getNormalizedScrollLeft(element) {
    return DirHelper.getNormalizedScrollLeft(scrollType, this.getAttribute('dir') || 'ltr', element);
  }
  /**
   * @param {Element} element
   * @param {number} scrollLeft
   * @protected
   */


  __setNormalizedScrollLeft(element, scrollLeft) {
    return DirHelper.setNormalizedScrollLeft(scrollType, this.getAttribute('dir') || 'ltr', element, scrollLeft);
  }

};