<template>
    <transition name="hanzo-fade" v-if="value">
        <div
          :class="[classes(), className]"
          @touchstart.prevent="onWrapperTouchStart"          
          @touchend="onWrapperTouchEnd"
          @touchcancel="onWrapperTouchEnd"
        >
            <div :class="classes('index')" v-if="showIndex">
                <slot>
                    {{ ( active + 1 ) }} / {{ images.length }}
                </slot>
            </div>
            <h-swipe
                ref="swipe"
                :loop="loop"
                indicatorColor="white"
                :initialSwipe="startPosition"
                :showIndicators="showIndicators"
                @change="onChange"
            >
                <h-swipe-item v-for="( image, index ) in images" :key="index">
                    <img 
                        :src="image"
                        :class="classes('image')"
                        :style="imageStyle(index)" 
                        @touchstart="onTouchStart"
                        @touchmove="onTouchMove"
                        @touchend="onTouchEnd"
                        @touchcancel="onTouchEnd"
                    />
                </h-swipe-item>
            </h-swipe>
        </div>
    </transition>
</template>
<script>
import { classesMixin } from '../../common/mixins/classname';
import { PopupMixin } from '../../common/mixins/popup';
import { TouchMixin } from '../../common/mixins/touch';
import { hSwipe,  hSwipeItem } from '../swipe/index';
let classMixin = classesMixin('image-preview');
export default {
    name: "h-image-preview",
    mixins: [ classMixin, PopupMixin, TouchMixin ],
    components: {
        hSwipe, hSwipeItem
    },
    props: {
        images: Array,
        className: null,
        lazyLoad: Boolean,
        asyncClose: Boolean,
        startPosition: {
            type: Number,
            default: 0
        },
        showIndicators: {
            type: Boolean,
            default: false
        },
        loop: {
            type: Boolean,
            default: true
        },
        overlay: {
            type: Boolean,
            default: true
        },
        showIndex: {
            type: Boolean,
            default: true
        },
        minZoom: {
            type: Number,
            default: 1 / 3
        },
        maxZoom: {
            type: Number,
            default: 3
        },
        overlayClass: {
            type: String,
            default: 'hanzo-image-preview__overlay'
        },
        closeOnClickOverlay: {
            type: Boolean,
            default: true
        }
    },
    data() {
        return {
            scale: 1,
            moveX: 0,
            moveY: 0,
            active: 0,
            a: 123,
            moving: false,
            zooming: false
        };
    },
    computed: {
        imageStyle( index ) {
            return ( index ) => {
                if ( index === this.active ) {
                    const { scale } = this;
                    const style = {
                        transition: this.zooming || this.moving ? '' : '.3s all'
                    };

                    if (scale !== 1) {
                        style.transform = `scale3d(${scale}, ${scale}, 1) translate(${this.moveX /
                        scale}px, ${this.moveY / scale}px)`;
                    }

                    return style;
                } else {
                    return null;
                }
            }
        }
    },
    watch: {
        value() {
            this.active = this.startPosition;
        },

        startPosition(active) {
            this.active = active;
        }
    },
    methods: {
        onWrapperTouchStart() {
            this.touchStartTime = new Date();
        },
        onWrapperTouchEnd(event) {
            event.preventDefault();

            const deltaTime = new Date() - this.touchStartTime;
            const { offsetX = 0, offsetY = 0 } = this.$refs.swipe || {};

            // prevent long tap to close component
            if (deltaTime < 300 && offsetX < 10 && offsetY < 10) {
                const index = this.active;

                this.resetScale();
                this.$emit('close', {
                index,
                url: this.images[index]
                });

                if (!this.asyncClose) {
                this.$emit('input', false);
                }
            }
        },
        resetScale() {
            this.scale = 1;
            this.moveX = 0;
            this.moveY = 0;
        },
        onChange(active) {
            this.resetScale();
            this.active = active;
            this.$emit('change', active);
        },
        getDistance(touches) {
            return Math.sqrt(
                Math.abs(
                (touches[0].clientX - touches[1].clientX) *
                    (touches[0].clientY - touches[1].clientY)
                )
            );
        },
        range(num, min, max) {
            return Math.min(Math.max(num, min), max);
        },
        startMove(event) {
            const image = event.currentTarget;
            const rect = image.getBoundingClientRect();
            const winWidth = window.innerWidth;
            const winHeight = window.innerHeight;

            this.touchStart(event);
            this.moving = true;
            this.startMoveX = this.moveX;
            this.startMoveY = this.moveY;
            this.maxMoveX = Math.max(0, (rect.width - winWidth) / 2);
            this.maxMoveY = Math.max(0, (rect.height - winHeight) / 2);
        },
        startZoom(event) {
            this.moving = false;
            this.zooming = true;
            this.startScale = this.scale;
            this.startDistance = this.getDistance(event.touches);
        },
        onTouchStart(event) {
            const { touches } = event;
            const { offsetX = 0 } = this.$refs.swipe || {};

            if (touches.length === 1 && this.scale !== 1) {
                this.startMove(event);
            } /* istanbul ignore else */ else if (touches.length === 2 && !offsetX) {
                this.startZoom(event);
            }
        },
        onTouchMove(event) {
            const { touches } = event;
            if (this.moving || this.zooming) {
                event.preventDefault();
                event.stopPropagation();
            }

            if (this.moving) {
                this.touchMove(event);
                const moveX = this.deltaX + this.startMoveX;
                const moveY = this.deltaY + this.startMoveY;
                this.moveX = this.range(moveX, -this.maxMoveX, this.maxMoveX);
                this.moveY = this.range(moveY, -this.maxMoveY, this.maxMoveY);
            }

            if (this.zooming && touches.length === 2) {
                const distance = this.getDistance(touches);
                const scale = (this.startScale * distance) / this.startDistance;
                this.scale = this.range(scale, this.minZoom, this.maxZoom);
            }
        },
        onTouchEnd(event) {
        /* istanbul ignore else */
            if (this.moving || this.zooming) {
                let stopPropagation = true;

                if (
                this.moving &&
                this.startMoveX === this.moveX &&
                this.startMoveY === this.moveY
                ) {
                stopPropagation = false;
                }

                if (!event.touches.length) {
                this.moving = false;
                this.zooming = false;
                this.startMoveX = 0;
                this.startMoveY = 0;
                this.startScale = 1;

                if (this.scale < 1) {
                    this.resetScale();
                }
                }

                if (stopPropagation) {
                event.preventDefault();
                event.stopPropagation();
                }
            }
        }
    }
}
</script>
<style lang="less" scoped>
@import './index.less';
</style>