import _extends from "@babel/runtime/helpers/extends";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
// Copyright 1999-2020. Plesk International GmbH. All rights reserved.
import { isRtl } from '../../utils';
import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Measure from 'react-measure';
import { CLS_PREFIX } from '../../constants';
import Icon from '../Icon';

const calcWidths = node => {
  const slideWidths = [].map.call(node.childNodes, el => el.clientWidth);
  const totalWidth = slideWidths.reduce((prev, curr) => prev + curr, 0);
  return {
    slideWidths,
    totalWidth
  };
};
/**
 * Carousel component is used for optimizing page space by displaying only some parts
 * of entire content in a cyclic view.
 * @since 0.0.42
 */


class Carousel extends Component {
  constructor(props) {
    super(props);

    _defineProperty(this, "state", {
      showControls: false,
      current: 0,
      next: 0,
      moving: false,
      slideWidths: [],
      totalWidth: 0
    });

    this.speed = 500;
    this.movingCallback = null;
    this.playSpeed = 5000;
    this.playTimer = null;
    this.handlePrevClick = this.handlePrevClick.bind(this);
    this.handleNextClick = this.handleNextClick.bind(this);
    this.stop = this.stop.bind(this);
    this.play = this.play.bind(this);
    this.handleResize = this.handleResize.bind(this);
    this.rootRef = /*#__PURE__*/createRef();
    this.genuineRef = /*#__PURE__*/createRef();
  }

  componentDidMount() {
    this.isRtl = isRtl();
    this.play();
  }

  componentDidUpdate() {
    const {
      width
    } = this.rootRef.current.getBoundingClientRect();
    const {
      slideWidths,
      totalWidth
    } = calcWidths(this.genuineRef.current);

    if (this.state.totalWidth !== totalWidth) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({
        slideWidths,
        totalWidth,
        showControls: width < totalWidth
      });
    }
  }

  componentWillUnmount() {
    this.stop();
    clearTimeout(this.movingCallback);
  }

  handlePrevClick() {
    this.stop();
    this.setCurrentSlide(this.state.current - 1);
  }

  handleNextClick() {
    this.stop();
    this.setCurrentSlide(this.state.current + 1);
  }

  play() {
    this.playTimer = setTimeout(() => {
      this.setCurrentSlide(this.state.current + 1);
      this.play();
    }, this.playSpeed);
  }

  stop() {
    if (this.playTimer) {
      clearTimeout(this.playTimer);
      this.playTimer = null;
    }
  }

  setCurrentSlide(next) {
    const {
      slideWidths,
      moving
    } = this.state;

    if (moving) {
      return;
    }

    let current = next;

    if (current < 0) {
      current = slideWidths.length - 1;
    }

    if (current >= slideWidths.length) {
      current = 0;
    }

    this.setState({
      current,
      next,
      moving: true
    });
    this.movingCallback = setTimeout(() => {
      this.movingCallback = null;
      this.setState({
        moving: false
      });
    }, this.speed);
  }

  handleResize({
    bounds: {
      width
    }
  }) {
    const node = this.genuineRef.current;
    const {
      slideWidths,
      totalWidth
    } = calcWidths(node);
    this.setState({
      slideWidths,
      totalWidth,
      showControls: width < totalWidth
    });
  }

  listStyle() {
    const {
      current,
      next,
      moving,
      slideWidths,
      totalWidth
    } = this.state;
    const moveTo = moving ? next : current;
    let x = -totalWidth + 26;

    if (moveTo < 0) {
      for (let i = moveTo; i < 0; i++) {
        x += slideWidths[i + slideWidths.length];
      }
    } else {
      for (let i = 0; i < moveTo; i++) {
        x -= slideWidths[i % slideWidths.length];
      }
    }

    if (this.isRtl) {
      x = -x;
    }

    return {
      WebkitTransform: `translateX(${x ? `${x}px` : 0})`,
      transform: `translateX(${x ? `${x}px` : 0})`,
      WebkitTransition: moving ? `-webkit-transform ${this.speed}ms ease` : null,
      transition: moving ? `transform ${this.speed}ms ease` : null
    };
  }

  render() {
    const {
      showControls
    } = this.state;
    const {
      baseClassName,
      className,
      children,
      ...props
    } = this.props;
    return /*#__PURE__*/React.createElement(Measure, {
      onResize: this.handleResize,
      bounds: true,
      innerRef: node => {
        this.rootRef.current = node;
      }
    }, ({
      measureRef
    }) => /*#__PURE__*/React.createElement("section", _extends({
      ref: measureRef,
      className: classNames(baseClassName, className)
    }, props), /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__slides`,
      style: showControls ? this.listStyle() : null
    }, showControls && children, /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__genuine-slides`,
      ref: this.genuineRef
    }, children), showControls && children), showControls && /*#__PURE__*/React.createElement("div", {
      className: `${baseClassName}__controls`
    }, /*#__PURE__*/React.createElement("button", {
      type: "button",
      className: classNames(`${baseClassName}__control`, `${baseClassName}__control--previous`),
      onClick: this.handlePrevClick
    }, /*#__PURE__*/React.createElement(Icon, {
      name: "chevron-left",
      flipHorizontal: this.isRtl,
      className: `${baseClassName}__control-icon`
    })), /*#__PURE__*/React.createElement("button", {
      type: "button",
      className: classNames(`${baseClassName}__control`, `${baseClassName}__control--next`),
      onClick: this.handleNextClick
    }, /*#__PURE__*/React.createElement(Icon, {
      name: "chevron-right",
      flipHorizontal: this.isRtl,
      className: `${baseClassName}__control-icon`
    })))));
  }

}

Carousel.propTypes = {
  /**
   * Slides
   * @since 0.0.42
   */
  children: PropTypes.node,

  /**
   * @ignore
   */
  className: PropTypes.string,

  /**
   * @ignore
   */
  baseClassName: PropTypes.string
};
Carousel.defaultProps = {
  children: null,
  className: null,
  baseClassName: `${CLS_PREFIX}carousel`
};
export default Carousel;