"use strict";
/* IMPORT */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("./constants");
const watcher_locks_resolver_1 = __importDefault(require("./watcher_locks_resolver"));
/* WATCHER LOCKER */
//TODO: Use a better name for this thing, maybe "RenameDetector"
class WatcherLocker {
    /* CONSTRUCTOR */
    constructor(watcher) {
        this._watcher = watcher;
        this.reset();
    }
    /* API */
    getLockAdd(config, timeout = constants_1.RENAME_TIMEOUT) {
        const { ino, targetPath, events, locks } = config;
        const emit = () => {
            this._watcher.event(events.add, targetPath);
        };
        if (!ino)
            return emit();
        const cleanup = () => {
            locks.add.delete(ino);
            watcher_locks_resolver_1.default.remove(free);
        };
        const free = () => {
            cleanup();
            emit();
        };
        watcher_locks_resolver_1.default.add(free, timeout);
        const resolve = () => {
            const unlink = locks.unlink.get(ino);
            if (!unlink)
                return; // No matching "unlink" lock found, skipping
            cleanup();
            const targetPathPrev = unlink();
            if (targetPath === targetPathPrev) {
                if (events.change) {
                    if (this._watcher._poller.stats.has(targetPath)) {
                        this._watcher.event(events.change, targetPath);
                    }
                }
            }
            else {
                this._watcher.event(events.rename, targetPathPrev, targetPath);
            }
        };
        locks.add.set(ino, resolve);
        resolve();
    }
    getLockUnlink(config, timeout = constants_1.RENAME_TIMEOUT) {
        var _a;
        const { ino, targetPath, events, locks } = config;
        const emit = () => {
            this._watcher.event(events.unlink, targetPath);
        };
        if (!ino)
            return emit();
        const cleanup = () => {
            locks.unlink.delete(ino);
            watcher_locks_resolver_1.default.remove(free);
        };
        const free = () => {
            cleanup();
            emit();
        };
        watcher_locks_resolver_1.default.add(free, timeout);
        const overridden = () => {
            cleanup();
            return targetPath;
        };
        locks.unlink.set(ino, overridden);
        (_a = locks.add.get(ino)) === null || _a === void 0 ? void 0 : _a();
    }
    getLockTargetAdd(targetPath, timeout) {
        const ino = this._watcher._poller.getIno(targetPath, "add" /* ADD */, 2 /* FILE */);
        return this.getLockAdd({
            ino,
            targetPath,
            events: WatcherLocker.FILE_EVENTS,
            locks: this._locksFile
        }, timeout);
    }
    getLockTargetAddDir(targetPath, timeout) {
        const ino = this._watcher._poller.getIno(targetPath, "addDir" /* ADD_DIR */, 1 /* DIR */);
        return this.getLockAdd({
            ino,
            targetPath,
            events: WatcherLocker.DIR_EVENTS,
            locks: this._locksDir
        }, timeout);
    }
    getLockTargetUnlink(targetPath, timeout) {
        const ino = this._watcher._poller.getIno(targetPath, "unlink" /* UNLINK */, 2 /* FILE */);
        return this.getLockUnlink({
            ino,
            targetPath,
            events: WatcherLocker.FILE_EVENTS,
            locks: this._locksFile
        }, timeout);
    }
    getLockTargetUnlinkDir(targetPath, timeout) {
        const ino = this._watcher._poller.getIno(targetPath, "unlinkDir" /* UNLINK_DIR */, 1 /* DIR */);
        return this.getLockUnlink({
            ino,
            targetPath,
            events: WatcherLocker.DIR_EVENTS,
            locks: this._locksDir
        }, timeout);
    }
    reset() {
        this._locksAdd = new Map();
        this._locksAddDir = new Map();
        this._locksUnlink = new Map();
        this._locksUnlinkDir = new Map();
        this._locksDir = { add: this._locksAddDir, unlink: this._locksUnlinkDir };
        this._locksFile = { add: this._locksAdd, unlink: this._locksUnlink };
    }
}
WatcherLocker.DIR_EVENTS = {
    add: "addDir" /* ADD_DIR */,
    rename: "renameDir" /* RENAME_DIR */,
    unlink: "unlinkDir" /* UNLINK_DIR */
};
WatcherLocker.FILE_EVENTS = {
    add: "add" /* ADD */,
    change: "change" /* CHANGE */,
    rename: "rename" /* RENAME */,
    unlink: "unlink" /* UNLINK */
};
/* EXPORT */
exports.default = WatcherLocker;
//# sourceMappingURL=data:application/json;base64,[encoded data, 5228 characters]