<template>
	<div class="list" ref="list" :style="{backgroundSize:`100% ${itemHeight}px`}" @touchstart="handleStart" @touchmove="handleMove"
	 @touchend="handleEnd">
		<ul :style="[ulStyle, {'transform':`translate3d(0px, ${startTop}px, 0px)`}]">
			<li v-for="(item, index) in column" :key="index" @click="selectItem(index)">{{item}}</li>
		</ul>
	</div>
</template>

<script>
	import {
		getClient
	} from './utils.js'
	const DEFAULT_DURATION = 200
	// 惯性滑动思路:
	// 在手指离开屏幕时，如果和上一次 move 时的间隔小于 `LIMIT_TIME` 且 move
	// 距离大于 `LIMIT_DISTANCE` 时，执行惯性滑动
	const LIMIT_TIME = 300
	const LIMIT_DISTANCE = 15
	export default {
		props: {
			defaultIndex: {
				// type: Number,
				default: 0
			},
			pickerId: {
				type: Number,
				default: 0
			},
			column: {
				type: Array,
				default: () => ([])
			},
			boxHeight: Number,
			itemHeight: Number,
			rowNumber: Number
		},
		data() {
			return {
				startTop: '0px',
				ulStyle: {
					transitionDuration: `0ms`,
					transitionProperty: `none`,
					lineHeight: `${this.itemHeight}px`
				}
			}
		},
		computed: {
			count() {
				return this.column.length
			},
			getRoNumber() {
				return Math.floor(this.rowNumber / 2)
			}
		},
		mounted() {
			this.init()
		},
		watch: {
			column(n, o) {
				// console.log(n, o)
				const halfBox = (this.boxHeight - this.itemHeight) / 2
				this.bottom = halfBox + this.itemHeight
				this.top = halfBox - this.count * this.itemHeight
			},
			defaultIndex(v, o) {
				this.setTop(this.defaultIndex)
			}
		},
		methods: {
			init() {
				this.setTop(this.defaultIndex)
				const halfBox = (this.boxHeight - this.itemHeight) / 2
				this.bottom = halfBox + this.itemHeight
				this.top = halfBox - this.count * this.itemHeight
			},
			selectItem(index) {
				if (index === this.defaultIndex) {
					return
				}
				this.setTop(index)
			},
			// 根据index 设置滚动位置
			setTop(index = 0) {
				const {
					boxHeight,
					itemHeight
				} = this
				this.startTop = ((boxHeight - itemHeight) / 2) - (index * itemHeight)
				this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`
				this.selectIndex = index
				this.change()
			},
			handleStart(e) {
				this.distStartTop = getClient(e).y
				this.touchStartTime = Date.now()
				// ----
				this.startY = getClient(e).y
				this.momentumTop = this.startTop

				this.ulStyle.transitionDuration = `0ms`
				this.ulStyle.transitionProperty = `none`
			},
			handleMove(e) {
				this.disY = getClient(e).y - this.startY
				this.startY = getClient(e).y
				if (this.startTop >= this.bottom) {
					this.startTop = this.bottom
				} else if (this.startTop <= this.top) {
					this.startTop = this.top
				} else {
					this.startTop += this.disY
				}
				this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`
				const now = Date.now()

				if (now - this.touchStartTime > LIMIT_TIME) {
					this.touchStartTime = now
					this.momentumTop = this.startTop
				}
				e.preventDefault()
				e.stopPropagation()
			},
			handleEnd() {
				const distance = this.startTop - this.momentumTop
				const duration = Date.now() - this.touchStartTime
				const allowMomentum = duration < LIMIT_TIME && Math.abs(distance) > LIMIT_DISTANCE
				if (allowMomentum) {
					this.toMove(distance, duration)
				} else {
					this.setTranfromTop()
				}
			},
			setTranfromTop() {
				this.ulStyle.transitionProperty = `all`
				this.ulStyle.transitionDuration = `${DEFAULT_DURATION}ms`
				if (this.startTop >= this.bottom - this.itemHeight) {
					this.setTop()
				} else if (this.startTop <= this.top + this.itemHeight) {
					this.setTop(this.count - 1)
				} else {
					let index = Math.round((this.startTop) / this.itemHeight)
					this.startTop = index * this.itemHeight
					if (this.startTop > this.bottom) {
						this.startTop = this.bottom - this.itemHeight
						index = -this.getRoNumber
					} else if (this.startTop < this.top) {
						this.startTop = this.top + this.itemHeight
						index = this.count + 1
					}
					this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`
					index = this.getRoNumber - index
					if (this.selectIndex !== index) {
						this.selectIndex = index
						this.change()
					}
				}
			},
			toMove(distance, duration) {
				const speed = Math.abs(distance / duration)
				distance = this.startTop + (speed / 0.002) * (distance < 0 ? -1 : 1)
				this.ulStyle.transitionProperty = `all`
				this.ulStyle.transitionDuration = `1000ms`
				this.setTop(Math.min(Math.max(Math.round(-distance / this.itemHeight), 0), this.count - 1))
			},
			change() {
				this.$emit('change', this.column[this.selectIndex], this.pickerId, this.selectIndex)
			},
			mousewheel(e) {
				e.preventDefault()
				e.stopPropagation()
				this.ulStyle.transitionDuration = `0ms`
				this.ulStyle.transitionProperty = `none`
				const {
					deltaX,
					deltaY
				} = e
				if (Math.abs(deltaX) < Math.abs(deltaY)) {
					this.startTop = this.startTop - deltaY
					let b = this.bottom - this.itemHeight
					let t = this.top + this.itemHeight
					let shouldMove = true
					if (this.startTop > b) {
						this.startTop = b
						shouldMove = false
					} else if (this.startTop < t) {
						this.startTop = t
						shouldMove = false
					}
					this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`
					if (shouldMove) {
						clearInterval(this.wheelTimer)
						this.wheelTimer = setTimeout(this.setTranfromTop, 100)
					}
				}
			}
		},
		beforeDestroy() {
		}
	}
</script>

<style lang="scss">
	@import '../style/uview.theme.scss';

	.list {
		margin: 0;
		padding: 0;
		flex: 1;
		width: 100%;
		height: 100%;
		overflow: hidden;
		position: relative;
		background: linear-gradient(180deg, rgba(242, 246, 252, 1), rgba(242, 246, 252, 1)) left center / 100% 48px no-repeat;

		ul {
			margin: 0;
			padding: 0;
			transition-timing-function: cubic-bezier(0.23, 1, 0.68, 1);
			line-height: 44px;
			list-style: none;
		}

		li {
			font-weight: bold;
			margin: 0;
			padding: 0;
			overflow: hidden;
			white-space: nowrap;
			text-overflow: ellipsis;
			padding: 0 5px;
			color: $u-main-color;
			background-color: transparent;
		}
	}
</style>
