/* IMPORT */
import { FileType, TargetEvent } from './enums.js';
import LazyMapSet from './lazy_map_set.js';
import Utils from './utils.js';
import WatcherStats from './watcher_stats.js';
/* MAIN */
class WatcherPoller {
    constructor() {
        /* VARIABLES */
        this.inos = {};
        this.paths = new LazyMapSet();
        this.stats = new Map();
    }
    /* API */
    getIno(targetPath, event, type) {
        const inos = this.inos[event];
        if (!inos)
            return;
        const ino = inos[targetPath];
        if (!ino)
            return;
        if (type && ino[1] !== type)
            return;
        return ino[0];
    }
    getStats(targetPath) {
        return this.stats.get(targetPath);
    }
    async poll(targetPath, timeout) {
        const stats = await Utils.fs.poll(targetPath, timeout);
        if (!stats)
            return;
        const isSupported = stats.isFile() || stats.isDirectory();
        if (!isSupported)
            return;
        return new WatcherStats(stats);
    }
    reset() {
        this.inos = {};
        this.paths = new LazyMapSet();
        this.stats = new Map();
    }
    async update(targetPath, timeout) {
        const prev = this.getStats(targetPath);
        const next = await this.poll(targetPath, timeout);
        this.updateStats(targetPath, next);
        if (!prev && next) {
            if (next.isFile()) {
                this.updateIno(targetPath, TargetEvent.ADD, next);
                return [TargetEvent.ADD];
            }
            if (next.isDirectory()) {
                this.updateIno(targetPath, TargetEvent.ADD_DIR, next);
                return [TargetEvent.ADD_DIR];
            }
        }
        else if (prev && !next) {
            if (prev.isFile()) {
                this.updateIno(targetPath, TargetEvent.UNLINK, prev);
                return [TargetEvent.UNLINK];
            }
            if (prev.isDirectory()) {
                this.updateIno(targetPath, TargetEvent.UNLINK_DIR, prev);
                return [TargetEvent.UNLINK_DIR];
            }
        }
        else if (prev && next) {
            if (prev.isFile()) {
                if (next.isFile()) {
                    if (prev.ino === next.ino && !prev.size && !next.size)
                        return []; // Same path, same content and same file, nothing actually changed
                    this.updateIno(targetPath, TargetEvent.CHANGE, next);
                    return [TargetEvent.CHANGE];
                }
                if (next.isDirectory()) {
                    this.updateIno(targetPath, TargetEvent.UNLINK, prev);
                    this.updateIno(targetPath, TargetEvent.ADD_DIR, next);
                    return [TargetEvent.UNLINK, TargetEvent.ADD_DIR];
                }
            }
            else if (prev.isDirectory()) {
                if (next.isFile()) {
                    this.updateIno(targetPath, TargetEvent.UNLINK_DIR, prev);
                    this.updateIno(targetPath, TargetEvent.ADD, next);
                    return [TargetEvent.UNLINK_DIR, TargetEvent.ADD];
                }
                if (next.isDirectory()) {
                    if (prev.ino === next.ino)
                        return []; // Same path and same directory, nothing actually changed
                    this.updateIno(targetPath, TargetEvent.UNLINK_DIR, prev);
                    this.updateIno(targetPath, TargetEvent.ADD_DIR, next);
                    return [TargetEvent.UNLINK_DIR, TargetEvent.ADD_DIR];
                }
            }
        }
        return [];
    }
    updateIno(targetPath, event, stats) {
        const inos = this.inos[event] = this.inos[event] || (this.inos[event] = {});
        const type = stats.isFile() ? FileType.FILE : FileType.DIR;
        inos[targetPath] = [stats.ino, type];
    }
    updateStats(targetPath, stats) {
        if (stats) {
            this.paths.set(stats.ino, targetPath);
            this.stats.set(targetPath, stats);
        }
        else {
            const ino = this.stats.get(targetPath)?.ino || -1;
            this.paths.delete(ino, targetPath);
            this.stats.delete(targetPath);
        }
    }
}
/* EXPORT */
export default WatcherPoller;
