import { Injectable, Inject, SkipSelf, Optional } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';
var availablePrefixs = ['moz', 'ms', 'webkit'];
function requestAnimationFramePolyfill() {
    var lastTime = 0;
    return function (callback) {
        var currTime = new Date().getTime();
        var timeToCall = Math.max(0, 16 - (currTime - lastTime));
        var id = window.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
        lastTime = currTime + timeToCall;
        return id;
    };
}
function getRequestAnimationFrame() {
    if (typeof window === 'undefined') {
        return function () { };
    }
    if (window.requestAnimationFrame) {
        // https://github.com/vuejs/vue/issues/4465
        return window.requestAnimationFrame.bind(window);
    }
    var prefix = availablePrefixs.filter(function (key) { return key + "RequestAnimationFrame" in window; })[0];
    return prefix
        ? window[prefix + "RequestAnimationFrame"]
        : requestAnimationFramePolyfill();
}
var reqAnimFrame = getRequestAnimationFrame();
function easeInOutCubic(t, b, c, d) {
    var cc = c - b;
    t /= d / 2;
    if (t < 1) {
        return cc / 2 * t * t * t + b;
    }
    else {
        return cc / 2 * ((t -= 2) * t * t + 2) + b;
    }
}
var NzScrollService = (function () {
    function NzScrollService(doc) {
        this.doc = doc;
    }
    /** 设置 `el` 滚动条位置 */
    NzScrollService.prototype.setScrollTop = function (el, topValue) {
        if (topValue === void 0) { topValue = 0; }
        if (el === window) {
            this.doc.body.scrollTop = topValue;
            this.doc.documentElement.scrollTop = topValue;
        }
        else {
            el.scrollTop = topValue;
        }
    };
    /** 获取 `el` 相对于视窗距离 */
    NzScrollService.prototype.getOffset = function (el) {
        var ret = {
            top: 0,
            left: 0
        };
        if (!el || !el.getClientRects().length)
            return ret;
        var rect = el.getBoundingClientRect();
        if (rect.width || rect.height) {
            var doc = el.ownerDocument.documentElement;
            ret.top = rect.top - doc.clientTop;
            ret.left = rect.left - doc.clientLeft;
        }
        else {
            ret.top = rect.top;
            ret.left = rect.left;
        }
        return ret;
    };
    /** 获取 `el` 滚动条位置 */
    NzScrollService.prototype.getScroll = function (el, top) {
        if (top === void 0) { top = true; }
        if (!el)
            el = window;
        var prop = top ? 'pageYOffset' : 'pageXOffset';
        var method = top ? 'scrollTop' : 'scrollLeft';
        var isWindow = el === window;
        var ret = isWindow ? el[prop] : el[method];
        if (isWindow && typeof ret !== 'number')
            ret = this.doc.documentElement[method];
        return ret;
    };
    /**
   * 使用动画形式将 `el` 滚动至某位置
   *
   * @param {(Element | Window)} containerEl 容器，默认 `window`
   * @param {number} [targetTopValue=0] 滚动至目标 `top` 值，默认：0，相当于顶部
   * @param {Function} [easing] 动作算法，默认：`easeInOutCubic`
   * @param {Function} [callback] 动画结束后回调
   */
    NzScrollService.prototype.scrollTo = function (containerEl, targetTopValue, easing, callback) {
        var _this = this;
        if (targetTopValue === void 0) { targetTopValue = 0; }
        if (!containerEl)
            containerEl = window;
        var scrollTop = this.getScroll(containerEl);
        var startTime = Date.now();
        var frameFunc = function () {
            var timestamp = Date.now();
            var time = timestamp - startTime;
            _this.setScrollTop(containerEl, (easing || easeInOutCubic)(time, scrollTop, targetTopValue, 450));
            if (time < 450) {
                reqAnimFrame(frameFunc);
            }
            else {
                if (callback)
                    callback();
            }
        };
        reqAnimFrame(frameFunc);
    };
    return NzScrollService;
}());
export { NzScrollService };
NzScrollService.decorators = [
    { type: Injectable },
];
/** @nocollapse */
NzScrollService.ctorParameters = function () { return [
    { type: Document, decorators: [{ type: Inject, args: [DOCUMENT,] },] },
]; };
export function SCROLL_SERVICE_PROVIDER_FACTORY(doc, scrollService) {
    return scrollService || new NzScrollService(doc);
}
export var SCROLL_SERVICE_PROVIDER = {
    provide: NzScrollService,
    useFactory: SCROLL_SERVICE_PROVIDER_FACTORY,
    deps: [DOCUMENT, [new Optional(), new SkipSelf(), NzScrollService]]
};
