"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get curry () {
        return curry;
    },
    get curryRight () {
        return curryRight;
    },
    get debounce () {
        return debounce;
    },
    get fastCall () {
        return fastCall;
    },
    get isFunction () {
        return isFunction;
    },
    get partial () {
        return partial;
    },
    get pipe () {
        return pipe;
    },
    get throttle () {
        return throttle;
    },
    get throttleAfterHits () {
        return throttleAfterHits;
    }
});
const _array = require("./array");
const _mixed = require("./mixed");
function isFunction(func) {
    return typeof func === 'function';
}
function throttle(func, wait = 200) {
    let lastCalled = 0;
    const result = {
        lastCallThrottled: true
    };
    let lastTimer = null;
    /**
   * @param {...*} args The list of arguments passed during the function invocation.
   * @returns {object}
   */ function _throttle(...args) {
        const stamp = Date.now();
        let needCall = false;
        result.lastCallThrottled = true;
        if (!lastCalled) {
            lastCalled = stamp;
            needCall = true;
        }
        const remaining = wait - (stamp - lastCalled);
        if (needCall) {
            result.lastCallThrottled = false;
            func.apply(this, args);
        } else {
            if (lastTimer) {
                clearTimeout(lastTimer);
            }
            lastTimer = setTimeout(()=>{
                result.lastCallThrottled = false;
                func.apply(this, args);
                lastCalled = 0;
                lastTimer = undefined;
            }, remaining);
        }
        return result;
    }
    return _throttle;
}
function throttleAfterHits(func, wait = 200, hits = 10) {
    const funcThrottle = throttle(func, wait);
    let remainHits = hits;
    /**
   *
   */ function _clearHits() {
        remainHits = hits;
    }
    /**
   * @param {*} args The list of arguments passed during the function invocation.
   * @returns {*}
   */ function _throttleAfterHits(...args) {
        if (remainHits) {
            remainHits -= 1;
            return func.apply(this, args);
        }
        return funcThrottle.apply(this, args);
    }
    _throttleAfterHits.clearHits = _clearHits;
    return _throttleAfterHits;
}
function debounce(func, wait = 200) {
    let lastTimer = null;
    let result;
    /**
   * @param {*} args The list of arguments passed during the function invocation.
   * @returns {*}
   */ function _debounce(...args) {
        if (lastTimer) {
            clearTimeout(lastTimer);
        }
        lastTimer = setTimeout(()=>{
            lastTimer = null;
            result = func.apply(this, args);
        }, wait);
        return result;
    }
    /**
   * Clears the scheduled invocation so the debounced function does not run later.
   */ function cancel() {
        if (lastTimer !== null) {
            clearTimeout(lastTimer);
            lastTimer = null;
        }
    }
    _debounce.cancel = cancel;
    return _debounce;
}
function pipe(...functions) {
    const [firstFunc, ...restFunc] = functions;
    return function _pipe(...args) {
        return (0, _array.arrayReduce)(restFunc, (acc, fn)=>fn(acc), firstFunc.apply(this, args));
    };
}
function partial(func, ...params) {
    return function _partial(...restParams) {
        return func.apply(this, params.concat(restParams));
    };
}
function curry(func) {
    const argsLength = func.length;
    /**
   * @param {*} argsSoFar The list of arguments passed during the function invocation.
   * @returns {Function}
   */ function given(argsSoFar) {
        return function _curry(...params) {
            const passedArgsSoFar = argsSoFar.concat(params);
            let result;
            if (passedArgsSoFar.length >= argsLength) {
                result = func.apply(this, passedArgsSoFar);
            } else {
                result = given(passedArgsSoFar);
            }
            return result;
        };
    }
    return given([]);
}
function curryRight(func) {
    const argsLength = func.length;
    /**
   * @param {*} argsSoFar The list of arguments passed during the function invocation.
   * @returns {Function}
   */ function given(argsSoFar) {
        return function _curry(...params) {
            const passedArgsSoFar = argsSoFar.concat(params.reverse());
            let result;
            if (passedArgsSoFar.length >= argsLength) {
                result = func.apply(this, passedArgsSoFar);
            } else {
                result = given(passedArgsSoFar);
            }
            return result;
        };
    }
    return given([]);
}
function fastCall(func, context, arg1, arg2, arg3, arg4, arg5, arg6) {
    if ((0, _mixed.isDefined)(arg6)) {
        return func.call(context, arg1, arg2, arg3, arg4, arg5, arg6);
    } else if ((0, _mixed.isDefined)(arg5)) {
        return func.call(context, arg1, arg2, arg3, arg4, arg5);
    } else if ((0, _mixed.isDefined)(arg4)) {
        return func.call(context, arg1, arg2, arg3, arg4);
    } else if ((0, _mixed.isDefined)(arg3)) {
        return func.call(context, arg1, arg2, arg3);
    } else if ((0, _mixed.isDefined)(arg2)) {
        return func.call(context, arg1, arg2);
    } else if ((0, _mixed.isDefined)(arg1)) {
        return func.call(context, arg1);
    }
    return func.call(context);
}
