text: import Nerv from 'nervjs'
  import classNames from 'classnames'
  import './style/swiper.scss'
  import _ from '../../../utils/parse-type'
  
  /**
   * props 类型检测
   *
   * @param {Object} props
   */
  function parseType (props) {
    const {
      current
    } = props
  
    // 抛出错误信息
    const throwErrorMsg = type => {
      throw new TypeError(type + ' must be number')
    }
  
    if (current) _.isNumber(current) ? '' : throwErrorMsg('current')
  }
  class Swiper extends Nerv.Component {
    constructor (props) {
      super(props)
      parseType(this.props)
  
      this.state = {
        currentIndex: parseInt(this.props.current),
        containerWidth: 0,
        containerHeight: 0,
        // touch
        touching: false,
        og: 0,
        ogTranslate: 0,
        touchId: undefined,
        translate: 0,
        animating: false
      }
      this.SwiperTimer = null
      this.handleTouchStart = this.handleTouchStart.bind(this)
      this.handleTouchMove = this.handleTouchMove.bind(this)
      this.handleTouchEnd = this.handleTouchEnd.bind(this)
      this.pauseAutoPlay = this.pauseAutoPlay.bind(this)
      this.autoplay = this.autoplay.bind(this)
      this.computedChangeContainer = this.computedChangeContainer.bind(this)
      this.updateContainerBox = this.updateContainerBox.bind(this)
    }
  
    componentDidMount () {
      this.updateContainerBox(this.props.children)
  
      if (this.props.autoplay) this.autoplay(this.props.interval)
    }
  
    componentWillReceiveProps (nextProps) {
      this.updateContainerBox(nextProps.children)
      const { interval, autoplay, circular } = nextProps
      this.pauseAutoPlay()
      // this.updateCurrentIndex(current)
      if (!circular) {
        this.computedChangeContainer()
      }
      if (!autoplay) return
  
      this.autoplay(interval)
    }
  
    componentWillUnmount () {
      this.pauseAutoPlay()
    }
  
    // 在开关衔接滑动的时候，计算当前下标
    computedChangeContainer () {
      if (this.props.children.length - 1 === this.state.currentIndex) {
        this.pauseAutoPlay()
        return true
      }
      return false
    }
  
    // 更新容器的宽高
    updateContainerBox (children) {
      let $container = Nerv.findDOMNode(this.SwiperWp)
      let childLen = children.length || 1
      let currentIndex = this.state.currentIndex
      // 默认偏移量
      let offsetVal = this.props.vertical
        ? -$container.offsetHeight * (currentIndex + 1)
        : -$container.offsetWidth * (currentIndex + 1)
      childLen = childLen + 2
  
      this.setState({
        containerWidth: $container.offsetWidth, // 外层容器宽
        containerHeight: $container.offsetHeight, // 外层容器高
        wrapperWidth: !this.props.vertical // 轮播容器 是否纵向滑动，不是的话计算总宽度
          ? $container.offsetWidth * childLen
          : $container.offsetWidth,
        wrapperHeight: this.props.vertical // 轮播容器 是否纵向滑动，是的话计算总高度
          ? $container.offsetHeight * childLen
          : $container.offsetHeight,
        // 计算指定下标位置
        translate: offsetVal
      })
    }
  
    // 更新下标
    updateCurrentIndex (currentIndex) {
      let cur = currentIndex === this.props.children.length - 1 ? 0 : currentIndex
      let tr = this.state.translate
      let slideVal // 纵向还是横向滚动长度
  
      if (!this.props.vertical) {
        slideVal = this.state.containerWidth * Math.abs(currentIndex - this.state.currentIndex)
      } else {
        slideVal = this.state.containerHeight * Math.abs(currentIndex - this.state.currentIndex)
      }
      this.setState(
        {
          animating: true,
          translate: tr - slideVal,
          currentIndex: cur
        },
        () => {
          setTimeout(() => {
            this.computedTranslate()
          }, this.props.duration)
        }
      )
    }
  
    // 判断当前是否在最后一页
    isLastIndex () {
      return this.state.currentIndex === this.props.children.length - 1
    }
  
    // 判断当前是否在第一页
    isFirstIndex () {
      return this.state.currentIndex === 0
    }
  
    handleTouchStart (e) {
      if (this.state.animating) return
      if (this.state.touching || this.props.children.length <= 1) return
      if (this.props.autoplay) this.pauseAutoPlay()
      let og = 0
  
      if (!this.props.vertical) {
        og = e.targetTouches[0].pageX - this.state.translate
      } else {
        og = e.targetTouches[0].pageY - this.state.translate
      }
  
      this.touchStartX = e.touches[0].pageX
      this.touchStartY = e.touches[0].pageY
      this.setState({
        touching: true,
        ogTranslate: this.state.translate,
        touchId: e.targetTouches[0].identifier,
        og: og,
        animating: false
      })
    }
    handleTouchMove (e) {
      // 非衔接滑动的时候 判断首尾页的时候禁止拖动
      if (!this.props.circular) {
        // 计算偏移量、 判断左滑右滑动
        let touchEndX = e.touches[0].pageX
        let touchEndY = e.touches[0].pageY
        let offsetMoveX = touchEndX - this.touchStartX
        let offsetMoveY = touchEndY - this.touchStartY
        if (this.isFirstIndex()) {
          if (
            (this.props.vertical && offsetMoveY > 0) ||
            (!this.props.vertical && offsetMoveX > 0)
          ) {
            return
          }
        }
        if (this.isLastIndex()) {
          if (
            (this.props.vertical && offsetMoveY < 0) ||
            (!this.props.vertical && offsetMoveX < 0)
          ) {
            return
          }
        }
      }
      if (!this.state.touching || this.props.children.length <= 1) return
      if (e.targetTouches[0].identifier !== this.state.touchId) return
  
      e.preventDefault()
  
      let diff = this.state.translate
  
      if (!this.props.vertical) {
        const pageX = e.targetTouches[0].pageX
        diff = pageX - this.state.og
      } else {
        // vertical
        const pageY = e.targetTouches[0].pageY
        diff = pageY - this.state.og
      }
  
      this.setState({
        translate: diff
      })
    }
  
    handleTouchEnd (e) {
      if (!this.state.touching || this.props.children.length <= 1) return
      let translate = this.state.translate
      let max = !this.props.vertical
        ? this.state.wrapperWidth - this.state.containerWidth
        : this.state.wrapperHeight - this.state.containerHeight
      let currentIndex = this.state.currentIndex
      let ogIndex = currentIndex
      if (translate > 0) {
        // start
        translate = 0
      } else if (translate < -max) {
        translate = -max
      } else {
        // default case
        let changeV = this.isChangeSlide(translate, currentIndex)
        translate = changeV.translate
        currentIndex = changeV.currentIndex
      }
  
      this.setState(
        {
          touching: false,
          og: 0,
          touchId: undefined,
          ogTranslate: 0,
          animating: true,
          translate,
          currentIndex
        },
        () =>
          setTimeout(() => {
            this.computedTranslate()
          }, this.props.duration)
      )
  
      if (this.props.onChange) {
        Object.defineProperty(e, 'detail', {
          enumerable: true,
          value: {
            current: currentIndex,
            source: 'touch'
          }
        })
        this.props.onChange(e)
      }
      if (this.props.autoplay) this.pauseAutoPlay()
    }
  
    computedTranslate () {
      // if (this.props.circular) {
      let prvTranslate = this.state.translate
      // 横纵向
      if (!this.props.vertical) {
        if (prvTranslate === 0) {
          prvTranslate = -(
            this.state.wrapperWidth -
            this.state.containerWidth * 2
          )
        }
        // 减一个宽度是因为最后的静默回滚到最前面 滑块本身还有一个 translate位移量
        if (
          prvTranslate === -(this.state.wrapperWidth - this.state.containerWidth)
        ) {
          prvTranslate = -this.state.containerWidth
        }
      } else {
        if (prvTranslate === 0) {
          prvTranslate = -(
            this.state.wrapperHeight -
            this.state.containerHeight * 2
          )
        }
        // 减一个宽度是因为最后的静默回滚到最前面 滑块本身还有一个 translate位移量
        if (
          prvTranslate ===
          -(this.state.wrapperHeight - this.state.containerHeight)
        ) {
          prvTranslate = -this.state.containerHeight
        }
      }
  
      this.setState({
        animating: false,
        translate: prvTranslate
      })
      // } else {
      //   this.setState({animating: false})
      // }
    }
  
    // 自增下标点计算
    addCurrentIndex (currentIndex) {
      return currentIndex === this.props.children.length - 1
        ? 0
        : (currentIndex += 1)
    }
  
    autoplay (interval) {
      this.SwiperTimer = setInterval(() => {
        this.slideNext()
      }, interval)
    }
  
    pauseAutoPlay () {
      clearInterval(this.SwiperTimer)
    }
  
    slideNext () {
      if (!this.props.circular) {
        if (this.computedChangeContainer()) {
          return
        }
      }
      let cur = this.addCurrentIndex(this.state.currentIndex)
      let tr = this.state.translate
      let slideVal // 纵向还是横向滚动长度
  
      if (!this.props.vertical) {
        slideVal = this.state.containerWidth
      } else {
        slideVal = this.state.containerHeight
      }
      this.setState(
        {
          animating: true,
          translate: tr - slideVal,
          currentIndex: cur
        },
        () => {
          setTimeout(() => {
            this.computedTranslate()
          }, this.props.duration)
        }
      )
      if (this.props.onChange) {
        let e = new TouchEvent('touchend')
        Object.defineProperty(e, 'detail', {
          enumerable: true,
          value: {
            current: cur,
            source: 'autoplay'
          }
        })
        this.props.onChange(e)
      }
    }
  
    isChangeSlide (translate, currentIndex) {
      // 判读滑动到大于一半才过去
      let threshold = !this.props.vertical
        ? this.state.containerWidth / 2
        : this.state.containerHeight / 2
      let diff = Math.abs(translate - this.state.ogTranslate)
      let isNext = translate - this.state.ogTranslate < 0
  
      if (diff > threshold) {
        if (isNext) {
          // next slide
          translate =
            this.state.ogTranslate -
            (!this.props.vertical
              ? this.state.containerWidth
              : this.state.containerHeight)
          currentIndex = this.addCurrentIndex(currentIndex)
        } else {
          // prev slide
          translate =
            this.state.ogTranslate +
            (!this.props.vertical
              ? this.state.containerWidth
              : this.state.containerHeight)
          currentIndex =
            currentIndex === 0
              ? (currentIndex = this.props.children.length - 1)
              : (currentIndex -= 1)
        }
      } else {
        // revert back
        translate = this.state.ogTranslate
      }
      return { translate, currentIndex }
    }
  
    renderPagination (indicatorColor, indicatorActiveColor) {
      if (Array.isArray(this.props.children)) {
        const childs = this.props.children.map((child, i) => {
          let clx = classNames('swiper__pagination-bullet', {
            active: i === this.state.currentIndex
          })
          let indiStyle = {
            background:
              i === this.state.currentIndex ? indicatorActiveColor : indicatorColor
          }
          return <span className={clx} key={i} style={indiStyle} />
        })
        return childs
      } else {
        let indiStyle = {
          background: indicatorActiveColor
        }
        return <span className={'swiper__pagination-bullet active'} key='1' style={indiStyle} />
      }
    }
  
    render () {
      const {
        className,
        indicatorDots,
        vertical,
        children,
        circular,
        duration
      } = this.props
      const cls = classNames('swiper__container', className, {
        'swiper__container-vertical': vertical,
        'swiper__container-horizontal': !vertical
      })
  
      let items = [].concat(children)
      // 衔接滑动增加首尾
      // if (circular) {
      if (items.length !== 0) {
        const firstItem = items[0]
        const lastItem = items[items.length - 1]
        items.push(firstItem)
        items.unshift(lastItem)
      }
      // }
      let wrapperStyle = {
        width: this.state.wrapperWidth,
        height: this.state.wrapperHeight,
        transition: this.state.animating
          ? `transform ${duration}ms ease-in-out`
          : 'none',
        transform: `translate(${!vertical ? this.state.translate : 0}px, ${
          vertical ? this.state.translate : 0
        }px)`
      }
  
      return (
        <div
          className={cls}
          ref={SwiperWp => {
            this.SwiperWp = SwiperWp
          }}
          onTouchStart={this.handleTouchStart}
          onTouchMove={this.handleTouchMove}
          onTouchEnd={this.handleTouchEnd}
        >
          <div className='swiper__wrapper' style={wrapperStyle}>
            {items.map((child, i) => {
              const c = child.props.children
              // 没有子元素直接返回
              if (c.length === 0) return <div className='swiper__item' />
              const cls = classNames('swiper__item', c.props.className)
              // 样式继承追加。 有可能 Object 或者是 String
              let sty
              if (typeof c.props.style === 'string') {
                let display = !vertical
                  ? ';display: inline-block;'
                  : ';display: block;'
                let verticalAlign = !vertical
                  ? ';vertical-align: top;'
                  : ';vertical-align:bottom;'
                let w = `;width: ${this.state.containerWidth}px;`
                let h = `;height: ${this.state.containerHeight}px;`
                sty = c.props.style + verticalAlign + display + w + h
              } else {
                sty = Object.assign({}, c.props.style, {
                  display: !vertical ? 'inline-block' : 'block',
                  verticalAlign: !vertical ? 'top' : 'bottom',
                  width: this.state.containerWidth,
                  height: this.state.containerHeight
                })
              }
              if (circular) i = i - 1
              return Nerv.cloneElement(c, {
                key: i,
                className: cls,
                style: sty,
                onClick: child.props.onClick
              })
            })}
          </div>
  
          {indicatorDots ? (
            <div className='swiper__pagination'>
              {this.renderPagination(
                this.props.indicatorColor,
                this.props.indicatorActiveColor
              )}
            </div>
          ) : (
            false
          )}
        </div>
      )
    }
  }
  
  // 默认配置
  Swiper.defaultProps = {
    indicatorDots: false, // 是否显示面板指示点
    indicatorColor: 'rgba(0, 0, 0, .3)', // 指示点颜色
    indicatorActiveColor: '#000000', // 当前选中的指示点颜色
    autoplay: false, // 自动播放
    current: 0, // 当前滑块位置
    interval: 5000, // 切换时间间隔
    duration: 500, // 滑动动画时长
    circular: false, // 是否采用衔接滑动
    vertical: false // 滑动方向是否为纵向
  }
  
  class SwiperItem extends Nerv.Component {
    constructor (props) {
      super(props)
    }
  
    render () {
      return ''
    }
  }
  
  export { SwiperItem, Swiper }
  