import Scroll from "./scroll";
import MouseMoveInteraction from "./mouse-move";
import MotionActions from "./actions";

export default class MotionFX extends elementorModules.ViewModule {
  getDefaultSettings() {
    return {
      type: 'element',
      $element: null,
      $dimensionsElement: null,
      addBackgroundLayerTo: null,
      interactions: {},
      refreshDimensions: false,
      range: 'viewport',
      classes: {
        element: 'motion-fx-element',
        parent: 'motion-fx-parent',
        backgroundType: 'motion-fx-element-type-background',
        container: 'motion-fx-container',
        layer: 'motion-fx-layer',
        perspective: 'motion-fx-perspective'
      }
    };
  }
  bindEvents() {
    this.defineDimensions = this.defineDimensions.bind(this);
    elementorFrontend.elements.$window.on('resize elementor-pro/motion-fx/recalc', this.defineDimensions);
  }
  unbindEvents() {
    elementorFrontend.elements.$window.off('resize elementor-pro/motion-fx/recalc', this.defineDimensions);
  }
  addBackgroundLayer() {
    const settings = this.getSettings();
    this.elements.$motionFXContainer = jQuery('<div>', {
      class: settings.classes.container
    });
    this.elements.$motionFXLayer = jQuery('<div>', {
      class: settings.classes.layer
    });
    this.updateBackgroundLayerSize();
    this.elements.$motionFXContainer.prepend(this.elements.$motionFXLayer);
    const $addBackgroundLayerTo = settings.addBackgroundLayerTo ? this.$element.find(settings.addBackgroundLayerTo) : this.$element;
    $addBackgroundLayerTo.prepend(this.elements.$motionFXContainer);
  }
  removeBackgroundLayer() {
    this.elements.$motionFXContainer.remove();
  }
  updateBackgroundLayerSize() {
    const settings = this.getSettings(),
      speed = {
        x: 0,
        y: 0
      },
      mouseInteraction = settings.interactions.mouseMove,
      scrollInteraction = settings.interactions.scroll;
    if (mouseInteraction && mouseInteraction.translateXY) {
      speed.x = mouseInteraction.translateXY.speed * 10;
      speed.y = mouseInteraction.translateXY.speed * 10;
    }
    if (scrollInteraction) {
      if (scrollInteraction.translateX) {
        speed.x = scrollInteraction.translateX.speed * 10;
      }
      if (scrollInteraction.translateY) {
        speed.y = scrollInteraction.translateY.speed * 10;
      }
    }
    this.elements.$motionFXLayer.css({
      width: 100 + speed.x + '%',
      height: 100 + speed.y + '%'
    });
  }
  defineDimensions() {
    const $dimensionsElement = this.getSettings('$dimensionsElement') || this.$element,
      elementOffset = $dimensionsElement.offset();
    const dimensions = {
      elementHeight: $dimensionsElement.outerHeight(),
      elementWidth: $dimensionsElement.outerWidth(),
      elementTop: elementOffset.top,
      elementLeft: elementOffset.left
    };
    dimensions.elementRange = dimensions.elementHeight + innerHeight;
    this.setSettings('dimensions', dimensions);
    if ('background' === this.getSettings('type')) {
      this.defineBackgroundLayerDimensions();
    }
  }
  defineBackgroundLayerDimensions() {
    const dimensions = this.getSettings('dimensions');
    dimensions.layerHeight = this.elements.$motionFXLayer.height();
    dimensions.layerWidth = this.elements.$motionFXLayer.width();
    dimensions.movableX = dimensions.layerWidth - dimensions.elementWidth;
    dimensions.movableY = dimensions.layerHeight - dimensions.elementHeight;
    this.setSettings('dimensions', dimensions);
  }
  initInteractionsTypes() {
    this.interactionsTypes = {
      scroll: Scroll,
      mouseMove: MouseMoveInteraction
    };
  }
  prepareSpecialActions() {
    const settings = this.getSettings(),
      hasTiltEffect = !!(settings.interactions.mouseMove && settings.interactions.mouseMove.tilt);
    this.elements.$parent.toggleClass(settings.classes.perspective, hasTiltEffect);
  }
  cleanSpecialActions() {
    const settings = this.getSettings();
    this.elements.$parent.removeClass(settings.classes.perspective);
  }
  runInteractions() {
    var _this = this;
    const settings = this.getSettings();
    this.actions.setCSSTransformVariables(settings.elementSettings);
    this.prepareSpecialActions();
    jQuery.each(settings.interactions, (interactionName, actions) => {
      this.interactions[interactionName] = new this.interactionsTypes[interactionName]({
        motionFX: this,
        callback: function () {
          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }
          jQuery.each(actions, (actionName, actionData) => _this.actions.runAction(actionName, actionData, ...args));
        }
      });
      this.interactions[interactionName].run();
    });
  }
  destroyInteractions() {
    this.cleanSpecialActions();
    jQuery.each(this.interactions, (interactionName, interaction) => interaction.destroy());
    this.interactions = {};
  }
  refresh() {
    this.actions.setSettings(this.getSettings());
    if ('background' === this.getSettings('type')) {
      this.updateBackgroundLayerSize();
      this.defineBackgroundLayerDimensions();
    }
    this.actions.refresh();
    this.destroyInteractions();
    this.runInteractions();
  }
  destroy() {
    this.destroyInteractions();
    this.actions.refresh();
    const settings = this.getSettings();
    this.$element.removeClass(settings.classes.element);
    this.elements.$parent.removeClass(settings.classes.parent);
    if ('background' === settings.type) {
      this.$element.removeClass(settings.classes.backgroundType);
      this.removeBackgroundLayer();
    }
  }
  onInit() {
    super.onInit();
    const settings = this.getSettings();
    this.$element = settings.$element;
    this.elements.$parent = this.$element.parent();
    this.$element.addClass(settings.classes.element);
    this.elements.$parent = this.$element.parent();
    this.elements.$parent.addClass(settings.classes.parent);
    if ('background' === settings.type) {
      this.$element.addClass(settings.classes.backgroundType);
      this.addBackgroundLayer();
    }
    this.defineDimensions();
    settings.$targetElement = 'element' === settings.type ? this.$element : this.elements.$motionFXLayer;
    this.interactions = {};
    this.actions = new MotionActions(settings);
    this.initInteractionsTypes();
    this.runInteractions();
  }
}
