text: import React from 'react';
  import PropTypes from 'prop-types';
  import { getBEMClasses } from '../../../helpers/cssClassesHelper';
  
  import './APVerticalScroller.css';
  
  const scrollerClasses = getBEMClasses('ap-vertical-scroller');
  
  class APVerticalScroller extends React.Component {
    constructor(props) {
      super(props);
  
      this.state = {
        isAtRest: true
      };
  
      this.handleOnScroll = this.handleOnScroll.bind(this);
    }
  
    componentDidMount() {
      this.scrollToRest();
    }
  
    componentDidUpdate() {
      let descendantCount = this.getDescendantCount(this, 4);
      if (descendantCount !== this.descendantCount) {
        // handle change
        this.descendantCount = descendantCount;
        if (this.state.isAtRest) {
          this.scrollToRest();
        }
      }
      if (this.state.isAtRest) {
        this.resetUserScrolled();
      }
    }
  
    resetUserScrolled = (callback = () => {}) => {
      this.userScrolled = false;
      callback();
    };
  
    getDescendantCount(item, levels) {
      if (levels <= 0 || !item || !item.props || !item.props.children) return 0;
      const children = item.props.children;
      if (Array.isArray(children)) {
        if (levels > 1) {
          return children.reduce((acc, curr) => {
            return acc + 1 + this.getDescendantCount(curr, levels - 1);
          }, 0);
        } else {
          return children.length;
        }
      } else {
        if (levels > 1) {
          return 1 + this.getDescendantCount(children, levels - 1);
        } else {
          return 1;
        }
      }
    }
  
    userScrolled = false;
  
    handleUserScrolled = () => {
      if (this.state.isAtRest) return (this.userScrolled = false);
      this.userScrolled = true;
    };
  
    handleOnScroll(event) {
      if (!this.el) {
        return;
      }
  
      this.handleUserScrolled();
  
      const clientHeight = this.el.clientHeight;
      const scrollHeight = this.el.scrollHeight;
      const newScroll = event.currentTarget.scrollTop;
      const scrollTop = newScroll;
      const scrollBottom = scrollHeight - clientHeight - newScroll;
      const isAtRestPrev = this.state.isAtRest;
      const isAtRest =
        (this.props.restPosition === 'top' && scrollTop <= 0) ||
        (this.props.restPosition === 'bottom' && scrollBottom <= 0);
  
      this.setState({ isAtRest });
  
      if (isAtRestPrev !== isAtRest) {
        // call event handlers
        if (this.props.onScrollRestChange) {
          this.props.onScrollRestChange(isAtRest);
        }
      }
    }
  
    getIsAtRest() {
      return this.state.isAtRest;
    }
  
    scrollTo(value, animate) {
      if (this.el) {
        if (animate) {
          this.scrollToAnimate(this.el, value, 200);
        } else {
          this.el.scrollTop = value;
        }
      }
    }
  
    scrollToRest(animate) {
      if (!this.userScrolled || this.state.isAtRest) {
        if (this.props.restPosition !== 'bottom') {
          // default to top
          this.scrollTo(0, animate);
        } else {
          // bottom
          if (this.el) {
            this.scrollTo(this.el.scrollHeight, animate);
          }
        }
      }
    }
  
    render() {
      const {
        children,
        styleName,
        restPosition,
        onScrollRestChange,
        customClass,
        ...otherProps
      } = this.props;
      return (
        <div
          ref={el => (this.el = el)}
          className={`${scrollerClasses(
            null,
            this.state.isAtRest ? 'at-rest' : null
          )} ${customClass}`}
          onScroll={this.handleOnScroll}
          {...otherProps}>
          {children}
        </div>
      );
    }
  
    // animation from https://codepen.io/rebosante/pen/eENYBv
    scrollToAnimate(element, to, duration) {
      var start = element.scrollTop,
        change = to - start,
        currentTime = 0,
        increment = 20;
      const animateScroll = () => {
        currentTime += increment;
        var val = this.easeInOutQuad(currentTime, start, change, duration);
        element.scrollTop = val;
        if (currentTime < duration) {
          setTimeout(animateScroll, increment);
        }
      };
      animateScroll();
    }
  
    //t = current time
    //b = start value
    //c = change in value
    //d = duration
    easeInOutQuad(t, b, c, d) {
      t /= d / 2;
      if (t < 1) return (c / 2) * t * t + b;
      t--;
      return (-c / 2) * (t * (t - 2) - 1) + b;
    }
  }
  APVerticalScroller.propTypes = {
    restPosition: PropTypes.string,
    onScrollRestChange: PropTypes.func,
    customClass: PropTypes.string
  };
  
  export default APVerticalScroller;
  