import Container from "../display/Container";
import Graphics from "../graphics/Graphics";
import { MouseEvent } from "../events/MouseEvent";
import { Event } from "../events/Event";
import { Tween } from "../../tween";
// import  Tween  from "../../tweenSimple/Tween";

/**
 * 滚动视图
 * @class ScrollPage
 * @public
 * @extends Container
 * @since 1.0.0
 */
export class ScrollPage extends Container {
    /**
     * 横向还是纵向 默认为纵向
     * @property isVertical
     * @type {boolean}
     * @private
     * @since 1.0.0
     * @default true
     */
    protected isVertical: boolean = true;
    /**
     * 可见区域的宽
     * @property viewWidth
     * @type {number}
     * @private
     * @since 1.0.0
     * @default 0
     */
    private viewWidth: number = 0;
    /**
     * 可见区域的高
     * @property viewHeight
     * @type {number}
     * @private
     * @since 1.0.0
     * @default 0
     */
    private viewHeight: number = 0;
    private _tweenId: any = 0;
    /**
     * 整个滚动的最大距离值
     * @property maxDistance
     * @type {number}
     * @public
     * @since 1.0.0
     * @default 1040
     */
    public maxDistance: number = 1040;
    /**
     * @property 滚动距离
     * @type {number}
     * @protected
     * @default 0
     * @since 1.0.0
     */
    protected distance: number = 0;
    /**
     * 最小鼠标滑动距离
     * @type {number}
     */
    private minDis: number = 2;
    /**
     * 遮罩对象
     * @property maskObj
     * @since 1.0.0
     * @private
     * @type {Graphics}
     */
    private maskObj: Graphics = new Graphics();
    /**
     * 真正的容器对象，所有滚动的内容都应该是添加到这个容器中
     * @property view
     * @public
     * @since 1.0.0
     * @type {Container}
     */
    public view: Container = new Container();
    /**
     * 最后鼠标经过的坐标值
     * @property lastValue
     * @private
     * @since 1.0.0
     * @type {number}
     */
    private lastValue: number = 0;
    /**
     * 速度
     * @property speed
     * @protected
     * @since 1.0.0
     * @type {number}
     */
    protected speed: number = 0;
    /**
     * 加速度
     * @property addSpeed
     * @private
     * @since 1.0.0
     * @type {number}
     */
    private addSpeed: number = 0;
    /**
     * 是否是停止滚动状态
     * @property isStop
     * @public
     * @since 1.0.0
     * @type {boolean}
     * @default true
     */
    public isStop: boolean = true;
    /**
     * 滚动的最大速度，直接影响一次滑动之后最长可以滚多远
     * @property maxSpeed
     * @public
     * @since 1.0.0
     * @default 100
     * @type {number}
     */
    public maxSpeed: number = 100;
    /**
     * 摩擦力,值越大，减速越快
     * @property fSpeed
     * @public
     * @since 1.0.0
     * @default 20
     * @type {number}
     */
    public fSpeed: number = 20;
    protected paramXY: string = "y";
    private stopTimes: number = -1;
    private isMouseDownState: number = 0;
    /**
     * 是否是通过scrollTo方法在滑动中
     * @property autoScroll
     * @since 1.0.2
     * @type {boolean}
     * @private
     * @default false
     */
    private autoScroll: boolean = false;

    public isSpringBack: boolean = true;
    /**
     * 注意滚动内容在view里加
     * @method  ScrollPage
     * @param {number} vW 可视区域宽
     * @param {number} vH 可视区域高
     * @param {number} maxDistance 最大滚动的长度
     * @param {boolean} isVertical 是纵向还是横向，也就是说是滚x还是滚y,默认值为沿y方向滚动
     * @example
     *      var sPage=new ScrollPage(640,s.stage.viewRect.height,4943);
     *      sPage.isSpringBack = false;//是否回弹
     *      stage.addChild(sPage);
     *      sPage.view.addChild(view);
     *      sPage.y=stage.viewRect.y;
     * 
     */
    constructor(vW: number, vH: number, maxDistance: number, isVertical: boolean = true, isFull = false) {
        super();
        let s: ScrollPage = this;
        s._instanceType = "ScrollPage";
        s.addChild(s.maskObj);
        s.addChild(s.view);
        if (!isFull) {
            //不全屏才设置mask
            s.view.mask = s.maskObj;
            //为了能接收鼠标事件设置_isUsedToMask
            s.maskObj._isUsedToMask = false;
        }
        s.maskObj.alpha = 0;
        s.maxDistance = maxDistance;
        s.setViewRect(vW, vH, isVertical);
        //添加到舞台，需要注意local坐标替换成stage坐标
        s.addEventListener(Event.ADDED_TO_STAGE, function (e: Event) {
            s.stage.addEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
            s.stage.addEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        });
        s.addEventListener(Event.REMOVED_FROM_STAGE, function (e: Event) {
            s.stage.removeEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
            s.stage.removeEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        });
        s.addEventListener(MouseEvent.MOUSE_DOWN, s.onMouseEvent, s, false);
        // s.addEventListener(MouseEvent.MOUSE_MOVE, s.onMouseEvent, s);
        // s.addEventListener(MouseEvent.MOUSE_UP, s.onMouseEvent, s);
        // s.addEventListener(MouseEvent.MOUSE_OUT, s.onMouseEvent, s);
        s.addEventListener(Event.ENTER_FRAME, function () {
            let view: any = s.view;
            if (s.autoScroll) return;
            if (!s.isSpringBack) {
                if (view[s.paramXY] > 0) {
                    s.addSpeed = 0;
                    s.speed = 0;
                    s.isStop = true;
                    view[s.paramXY] = 0;
                    return;
                }
                else if (view[s.paramXY] < s.distance - s.maxDistance) {
                    s.addSpeed = 0;
                    s.speed = 0;
                    s.isStop = true;
                    view[s.paramXY] = s.distance - s.maxDistance;
                    if (s.distance > s.maxDistance) view[s.paramXY] = 0;
                    return;
                }
            }
            if (!s.isStop) {
                if (Math.abs(s.speed) > 0) {
                    view[s.paramXY] += s.speed;
                    //是否超过了边界,如果超过了,则加快加速度,让其停止
                    if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                        s.speed += s.addSpeed * s.fSpeed;
                    } else {
                        s.speed += s.addSpeed;
                    }
                    //说明超过了界线,准备回弹
                    if (s.speed * s.addSpeed > 0) {
                        s.dispatchEvent(Event.SCROLL_STOP);
                        s.speed = 0;
                    }
                } else {
                    //检测是否超出了边界,如果超出了边界则回弹
                    if (s.addSpeed != 0) {
                        if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                            let tarP: number = 0;
                            // if (s.addSpeed > 0) {
                            //     if (s.distance < s.maxDistance) {
                            //         tarP = s.distance - s.maxDistance;
                            //     }
                            // }
                            if (view[s.paramXY] < s.distance - s.maxDistance) {
                                if (s.distance < s.maxDistance) {
                                    tarP = s.distance - s.maxDistance;
                                }
                            }
                            view[s.paramXY] += 0.4 * (tarP - view[s.paramXY]);
                            if (Math.abs(tarP - view[s.paramXY]) < 0.1) {
                                s.isStop = true;
                                if (s.addSpeed > 0) {
                                    s.dispatchEvent(Event.SCROLL_TO_END);
                                } else {
                                    s.dispatchEvent(Event.SCROLL_TO_HEAD);
                                }
                                s.addSpeed = 0;
                            }
                        }
                    } else {
                        s.isStop = true;
                    }
                }
            } else {
                if (s.stopTimes >= 0) {
                    s.stopTimes++;
                    if (s.stopTimes >= 15) {
                        s.speed = 0;
                        if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                            s.isStop = false;
                            s.stopTimes = -1;
                            //加一个
                            s.isMouseDownState = 0;
                        }
                    }
                }
            }
        })
    }
    /**
     * 设置可见区域，可见区域的坐标始终在本地坐标中0,0点位置
     * @method setViewRect
     * @param {number}w 设置可见区域的宽
     * @param {number}h 设置可见区域的高
     * @param {boolean} isVertical 方向
     * @public
     * @since 1.1.1
     */
    public setViewRect(w: number, h: number, isVertical: boolean): void {
        let s: ScrollPage = this;
        s.maskObj.clear();
        s.maskObj.beginFill("#000000");
        s.maskObj.drawRect(0, 0, w, h);
        s.viewWidth = w;
        s.viewHeight = h;
        s.maskObj.endFill();
        s.isVertical = isVertical;
        if (isVertical) {
            s.distance = s.viewHeight;
            s.paramXY = "y";
        } else {
            s.distance = s.viewWidth;
            s.paramXY = "x";
        }
        s.isVertical = isVertical;
    }

    private onMouseEvent(e: MouseEvent): void {
        let s = this;
        let view: any = s.view;
        // if (s.distance < s.maxDistance) {
        if (e.type == MouseEvent.MOUSE_DOWN) {
            e.stopPropagation()
            if (!s.isStop) {
                s.isStop = true;
            }
            if (s.autoScroll) {
                s.autoScroll = false;
                // Tween.kill(s._tweenId);
                // cancelAnimationFrame(s._tweenId)
                Tween.removeTweens(s.view)
            }
            if (s.isVertical) {
                s.lastValue = e.stageY//e.localY;//move事件添加到舞台的，需要用stageY
            } else {
                s.lastValue = e.stageX//e.localX;
            }
            s.speed = 0;
            s.isMouseDownState = 1;
        }
        else if (e.type == MouseEvent.MOUSE_MOVE) {
            if (s.isMouseDownState == 0) return;
            if (s.isMouseDownState == 1) {
                s.dispatchEvent(Event.SCROLL_START);
            }
            s.isMouseDownState = 2;
            let currentValue: number;
            if (s.isVertical) {
                currentValue = e.stageY//e.localY;
            } else {
                currentValue = e.stageX//e.localX;
            }
            s.speed = currentValue - s.lastValue;
            if (s.speed > s.minDis) {
                s.addSpeed = -2;
                if (s.speed > s.maxSpeed) {
                    s.speed = s.maxSpeed;
                }
            } else if (s.speed < -s.minDis) {
                if (s.speed < -s.maxSpeed) {
                    s.speed = -s.maxSpeed;
                }
                s.addSpeed = 2;
            } else {
                s.speed = 0;
            }
            if (s.speed != 0) {
                let speedPer: number = 1;
                if (view[s.paramXY] > 0 || view[s.paramXY] < s.distance - s.maxDistance) {
                    speedPer = 0.2;
                }
                view[s.paramXY] += (currentValue - s.lastValue) * speedPer;
            }
            s.lastValue = currentValue;
            s.stopTimes = 0;
        } else {
            if (!s.isMouseDownState) return;//先不加，讲道理需要，否则stage的up事件会触发这里，使得isStop改变
            s.isStop = false;
            s.stopTimes = -1;
            if (s.speed == 0 && s.isMouseDownState == 2) {
                s.dispatchEvent(Event.SCROLL_STOP);
            }
            s.isMouseDownState = 0;
        }
        // }
    }
    /**
     * 滚到指定的坐标位置
     * @method scrollTo
     * @param {number} dis 需要去到的位置,初始位置0,最大为maxDistance- s.viewWidth : s.viewHeight
     * @param {number} time 滚动需要的时间 默认为0 即没有动画效果直接跳到指定页，毫秒
     * @since 1.1.1
     * @public
     */
    public scrollTo(dis: number, time: number = 0): void {
        let s: ScrollPage = this;
        let newDis = s.paramXY == "x" ? s.viewWidth : s.viewHeight;
        if (dis < 0) {
            dis = 0;
        } else if (dis > s.maxDistance - newDis) {
            dis = s.maxDistance - newDis;
        }
        if (Math.abs(s.view[s.paramXY] + dis) > 2) {
            //tweenSimple版
            // s.autoScroll = true;
            // s.isStop = true;
            // s.isMouseDownState = 0;
            // let obj: any = {};
            // obj.onComplete = function () {
            //     s.autoScroll = false;
            // };
            // obj[s.paramXY] = -dis;
            // s._tweenId = Tween.to(s.view, time, obj);
            // if (s.speed == 0) {
            //     s.dispatchEvent(Event.SCROLL_START);
            // }

            //用Tween版
            s.autoScroll = true;
            s.isStop = true;
            s.isMouseDownState = 0;
            Tween.get(s.view)
                .to({ [s.paramXY]: -dis }, time)
                .call(() => {
                    s.view[s.paramXY] = -dis;
                    s.autoScroll = false;
                })
            if (s.speed == 0) s.dispatchEvent(Event.SCROLL_START);


            //无缓动版
            // s.isStop = true;
            // s.isMouseDownState = 0;
            // s.view[s.paramXY] = -dis;

            //用计时器版
            // s.isStop = true;
            // s.isMouseDownState = 0;
            // if (time) {
            //     s.autoScroll = true;
            //     let cdis = s.view[s.paramXY];
            //     cancelAnimationFrame(s._tweenId)
            //     let last = Date.now();
            //     let fun = () => {
            //         var deltaTime = Date.now() - last;
            //         if (deltaTime > time) {
            //             s.view[s.paramXY] = -dis;
            //             s.autoScroll = false;
            //             cancelAnimationFrame(s._tweenId)
            //         } else {
            //             s.view[s.paramXY] = (-dis - cdis) * (deltaTime / time) + cdis;
            //             s._tweenId = requestAnimationFrame(fun)
            //         }
            //     }
            //     s._tweenId = requestAnimationFrame(fun)
            //     if (s.speed == 0) s.dispatchEvent(Event.SCROLL_START);
            // } else {
            //     //直接赋值
            //     s.view[s.paramXY] = -dis;
            // }

        }
    }
    public destroy(): void {
        //Tween去掉
        Tween.removeTweens(this.view);
        let s = this;
        s.maskObj.destroy();
        s.view.destroy();
        s.maskObj = null;
        s.view = null;
        super.destroy();
    }
}
