'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');

var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _objectAssign = require('object-assign');

var _objectAssign2 = _interopRequireDefault(_objectAssign);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var styles = {
  wrapper: {
    width: '100%',
    height: '100%',
    overflow: 'hidden',
    position: 'relative'
  },
  frame: {
    top: 0,
    width: '100%',
    height: '100%',
    position: 'absolute'
  }
};

var wrapper = void 0;
var frames = {};

var Carousel = function (_React$Component) {
  (0, _inherits3.default)(Carousel, _React$Component);

  function Carousel(props) {
    (0, _classCallCheck3.default)(this, Carousel);

    var _this = (0, _possibleConstructorReturn3.default)(this, (Carousel.__proto__ || (0, _getPrototypeOf2.default)(Carousel)).call(this, props));

    _this.state = {
      current: 0
    };
    _this.mounted = false;
    _this.onTouchStart = _this.onTouchStart.bind(_this);
    _this.onTouchMove = _this.onTouchMove.bind(_this);
    _this.onTouchEnd = _this.onTouchEnd.bind(_this);
    _this.autoSlide = _this.autoSlide.bind(_this);
    _this.prev = _this.prev.bind(_this);
    _this.next = _this.next.bind(_this);

    if (props.loop === false && props.auto) {
      console.warn('[re-carousel] Auto-slide only works in loop mode.');
    }
    return _this;
  }

  (0, _createClass3.default)(Carousel, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      this.mounted = true;
      this.prepareAutoSlide();
      var childCount = _react.Children.count(this.props.children);

      // Hide all frames
      for (var i = 1; i < childCount; i++) {
        frames['f' + i].style.opacity = 0;
      }
    }
  }, {
    key: 'componentWillUnmount',
    value: function componentWillUnmount() {
      this.mounted = false;
      this.clearAutoTimeout();
    }
  }, {
    key: 'onTouchStart',
    value: function onTouchStart(e) {
      var childCount = _react.Children.count(this.props.children);
      if (childCount < 2) return;

      this.clearAutoTimeout();
      this.updateFrameSize();
      this.prepareSiblingFrames();

      var _ref = e.touches && e.touches[0] || e,
          pageX = _ref.pageX,
          pageY = _ref.pageY;

      this.setState({
        startX: pageX,
        startY: pageY,
        deltaX: 0,
        deltaY: 0
      });

      wrapper.addEventListener('touchmove', this.onTouchMove, { passive: true });
      wrapper.addEventListener('mousemove', this.onTouchMove, { passive: true });
      wrapper.addEventListener('touchend', this.onTouchEnd, true);
      wrapper.addEventListener('mouseup', this.onTouchEnd, true);
    }
  }, {
    key: 'onTouchMove',
    value: function onTouchMove(e) {
      if (e.touches && e.touches.length > 1) return;

      this.clearAutoTimeout();

      var _ref2 = e.touches && e.touches[0] || e,
          pageX = _ref2.pageX,
          pageY = _ref2.pageY;

      var deltaX = pageX - this.state.startX;
      var deltaY = pageY - this.state.startY;
      this.setState({
        deltaX: deltaX,
        deltaY: deltaY
      });

      var childCount = _react.Children.count(this.props.children);

      // when reach frames edge in non-loop mode, reduce drag effect.
      if (!this.props.loop) {
        if (this.state.current === childCount - 1) {
          deltaX < 0 && (deltaX /= 3);
          deltaY < 0 && (deltaY /= 3);
        }
        if (this.state.current === 0) {
          deltaX > 0 && (deltaX /= 3);
          deltaY > 0 && (deltaY /= 3);
        }
      }

      this.moveFramesBy(deltaX, deltaY);
    }
  }, {
    key: 'onTouchEnd',
    value: function onTouchEnd() {
      var _this2 = this;

      var direction = this.decideEndPosition();
      direction && this.transitFramesTowards(direction);

      // cleanup
      wrapper.removeEventListener('touchmove', this.onTouchMove);
      wrapper.removeEventListener('mousemove', this.onTouchMove);
      wrapper.removeEventListener('touchend', this.onTouchEnd, true);
      wrapper.removeEventListener('mouseup', this.onTouchEnd, true);

      setTimeout(function () {
        return _this2.prepareAutoSlide();
      }, this.props.duration);
    }
  }, {
    key: 'decideEndPosition',
    value: function decideEndPosition() {
      var _state = this.state,
          _state$deltaX = _state.deltaX,
          deltaX = _state$deltaX === undefined ? 0 : _state$deltaX,
          _state$deltaY = _state.deltaY,
          deltaY = _state$deltaY === undefined ? 0 : _state$deltaY,
          current = _state.current;
      var _props = this.props,
          axis = _props.axis,
          loop = _props.loop,
          minMove = _props.minMove,
          children = _props.children;

      var childLength = _react.Children.count(children);

      switch (axis) {
        case 'x':
          if (loop === false) {
            if (current === 0 && deltaX > 0) return 'origin';
            if (current === childLength - 1 && deltaX < 0) return 'origin';
          }
          if (Math.abs(deltaX) < minMove) return 'origin';
          return deltaX > 0 ? 'right' : 'left';
        case 'y':
          if (loop === false) {
            if (current === 0 && deltaY > 0) return 'origin';
            if (current === childLength - 1 && deltaY < 0) return 'origin';
          }
          if (Math.abs(deltaY) < minMove) return 'origin';
          return deltaY > 0 ? 'down' : 'up';
        default:
      }
    }
  }, {
    key: 'moveFramesBy',
    value: function moveFramesBy(deltaX, deltaY) {
      var _state$movingFrames = this.state.movingFrames,
          prev = _state$movingFrames.prev,
          current = _state$movingFrames.current,
          next = _state$movingFrames.next;
      var _state2 = this.state,
          frameWidth = _state2.frameWidth,
          frameHeight = _state2.frameHeight;


      switch (this.props.axis) {
        case 'x':
          translateXY(current, deltaX, 0);
          if (deltaX < 0) {
            translateXY(next, deltaX + frameWidth, 0);
          } else {
            translateXY(prev, deltaX - frameWidth, 0);
          }
          break;
        case 'y':
          translateXY(current, 0, deltaY);
          if (deltaY < 0) {
            translateXY(next, 0, deltaY + frameHeight);
          } else {
            translateXY(prev, 0, deltaY - frameHeight);
          }
          break;
        default:
      }
    }
  }, {
    key: 'prepareAutoSlide',
    value: function prepareAutoSlide() {
      var _this3 = this;

      if (_react.Children.count(this.props.children) < 2) return;

      this.clearAutoTimeout();
      this.updateFrameSize(function () {
        _this3.prepareSiblingFrames();
      });

      // auto slide only avalible in loop mode
      if (this.mounted && this.props.loop && this.props.auto) {
        var slideTimeoutID = setTimeout(this.autoSlide, this.props.interval);
        this.setState({ slider: slideTimeoutID });
      }
    }

    // auto slide to 'next' or 'prev'

  }, {
    key: 'autoSlide',
    value: function autoSlide(rel) {
      var _this4 = this;

      this.clearAutoTimeout();

      switch (rel) {
        case 'prev':
          this.transitFramesTowards(this.props.axis === 'x' ? 'right' : 'down');
          break;
        case 'next':
        default:
          this.transitFramesTowards(this.props.axis === 'x' ? 'left' : 'up');
      }

      // prepare next move after animation
      setTimeout(function () {
        return _this4.prepareAutoSlide();
      }, this.props.duration);
    }
  }, {
    key: 'next',
    value: function next() {
      var current = this.state.current;

      var childCount = _react.Children.count(this.props.children);
      if (!this.props.loop && current === childCount - 1) return false;
      this.autoSlide('next');
    }
  }, {
    key: 'prev',
    value: function prev() {
      if (!this.props.loop && this.state.current === 0) return false;
      this.autoSlide('prev');
    }
  }, {
    key: 'clearAutoTimeout',
    value: function clearAutoTimeout() {
      clearTimeout(this.state.slider);
    }
  }, {
    key: 'updateFrameSize',
    value: function updateFrameSize(cb) {
      var _window$getComputedSt = window.getComputedStyle(wrapper),
          width = _window$getComputedSt.width,
          height = _window$getComputedSt.height;

      this.setState({
        frameWidth: parseFloat(width.split('px')[0]),
        frameHeight: parseFloat(height.split('px')[0])
      }, cb);
    }
  }, {
    key: 'prepareSiblingFrames',
    value: function prepareSiblingFrames() {
      var siblings = {
        current: frames['f' + this.getFrameId()],
        prev: frames['f' + this.getFrameId('prev')],
        next: frames['f' + this.getFrameId('next')]
      };

      if (!this.props.loop) {
        this.state.current === 0 && (siblings.prev = undefined);
        this.state.current === _react.Children.count(this.props.children) - 1 && (siblings.next = undefined);
      }

      this.setState({ movingFrames: siblings });

      // prepare frames position
      translateXY(siblings.current, 0, 0);
      if (this.props.axis === 'x') {
        translateXY(siblings.prev, -this.state.frameWidth, 0);
        translateXY(siblings.next, this.state.frameWidth, 0);
      } else {
        translateXY(siblings.prev, 0, -this.state.frameHeight);
        translateXY(siblings.next, 0, this.state.frameHeight);
      }

      return siblings;
    }
  }, {
    key: 'getFrameId',
    value: function getFrameId(pos) {
      var children = this.props.children;
      var current = this.state.current;

      var total = _react.Children.count(children);
      switch (pos) {
        case 'prev':
          return (current - 1 + total) % total;
        case 'next':
          return (current + 1) % total;
        default:
          return current;
      }
    }
  }, {
    key: 'transitFramesTowards',
    value: function transitFramesTowards(direction) {
      var _state$movingFrames2 = this.state.movingFrames,
          prev = _state$movingFrames2.prev,
          current = _state$movingFrames2.current,
          next = _state$movingFrames2.next;
      var _props2 = this.props,
          duration = _props2.duration,
          axis = _props2.axis;


      var newCurrentId = this.state.current;
      switch (direction) {
        case 'up':
          translateXY(current, 0, -this.state.frameHeight, duration);
          translateXY(next, 0, 0, duration);
          newCurrentId = this.getFrameId('next');
          break;
        case 'down':
          translateXY(current, 0, this.state.frameHeight, duration);
          translateXY(prev, 0, 0, duration);
          newCurrentId = this.getFrameId('prev');
          break;
        case 'left':
          translateXY(current, -this.state.frameWidth, 0, duration);
          translateXY(next, 0, 0, duration);
          newCurrentId = this.getFrameId('next');
          break;
        case 'right':
          translateXY(current, this.state.frameWidth, 0, duration);
          translateXY(prev, 0, 0, duration);
          newCurrentId = this.getFrameId('prev');
          break;
        default:
          // back to origin
          translateXY(current, 0, 0, duration);
          if (axis === 'x') {
            translateXY(prev, -this.state.frameWidth, 0, duration);
            translateXY(next, this.state.frameWidth, 0, duration);
          } else if (axis === 'y') {
            translateXY(prev, 0, -this.state.frameHeight, duration);
            translateXY(next, 0, this.state.frameHeight, duration);
          }
      }

      this.setState({ current: newCurrentId });
    }

    // debugFrames () {
    //   console.log('>>> DEBUG-FRAMES: current', this.state.current)
    //   const len = this.state.frames.length
    //   for (let i = 0; i < len; ++i) {
    //     const ref = this.refs['f' + i]
    //     console.info(ref.innerText.trim(), ref.style.transform)
    //   }
    // }

  }, {
    key: 'render',
    value: function render() {
      var _this5 = this;

      var current = this.state.current;
      var _props3 = this.props,
          children = _props3.children,
          widgets = _props3.widgets,
          axis = _props3.axis,
          loop = _props3.loop,
          auto = _props3.auto,
          interval = _props3.interval,
          className = _props3.className;


      return _react2.default.createElement(
        'div',
        {
          ref: function ref(_wrapper) {
            wrapper = _wrapper;
          },
          className: className,
          style: (0, _objectAssign2.default)({}, styles.wrapper, this.props.style),
          onTouchStart: this.onTouchStart,
          onMouseDown: this.onTouchStart },
        _react.Children.map(children, function (child, i) {
          var frameStyle = (0, _objectAssign2.default)({ zIndex: 99 - i }, styles.frame);
          return _react2.default.createElement(
            'div',
            { ref: function ref(_f) {
                frames['f' + i] = _f;
              }, key: i, style: frameStyle },
            child
          );
        }),
        widgets && [].concat(widgets).map(function (Widget, i) {
          return _react2.default.createElement(Widget, {
            key: i,
            index: current,
            total: _react.Children.count(children),
            prevHandler: _this5.prev,
            nextHandler: _this5.next,
            axis: axis, loop: loop, auto: auto, interval: interval });
        })
      );
    }
  }]);
  return Carousel;
}(_react2.default.Component);

Carousel.propTypes = {
  axis: _propTypes2.default.oneOf(['x', 'y']),
  auto: _propTypes2.default.bool,
  loop: _propTypes2.default.bool,
  interval: _propTypes2.default.number,
  duration: _propTypes2.default.number,
  widgets: _propTypes2.default.arrayOf(_propTypes2.default.func),
  style: _propTypes2.default.object,
  minMove: _propTypes2.default.number
};

Carousel.defaultProps = {
  axis: 'x',
  auto: false,
  loop: false,
  interval: 5000,
  duration: 300,
  minMove: 42
};

function translateXY(el, x, y) {
  var duration = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;

  if (!el) return;

  el.style.opacity = '1';

  // animation
  el.style.transitionDuration = duration + 'ms';
  el.style.webkitTransitionDuration = duration + 'ms';

  el.style.transfrom = 'translate(' + x + 'px, ' + y + 'px)';
  el.style.webkitTransform = 'translate(' + x + 'px, ' + y + 'px) translateZ(0)';
}

exports.default = Carousel;
//# sourceMappingURL=Carousel.js.map