"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var api_1 = require("./api");
var utils_1 = require("./utils");
var id = 0;
var MemoryFileSystem = /** @class */ (function () {
    function MemoryFileSystem(baseUrl, ignore) {
        if (baseUrl === void 0) { baseUrl = "memory-" + id++; }
        this.baseUrl = baseUrl;
        this.events = utils_1.makeEventsEmitter();
        this.root = new api_1.Directory('', '');
        this.isIgnored = function () { return false; };
        this.baseUrl += '/';
        if (ignore) {
            this.isIgnored = utils_1.getIsIgnored(ignore);
        }
        ;
    }
    MemoryFileSystem.prototype.getPathTarget = function (pathArr) {
        var current = this.root;
        var _loop_1 = function () {
            var targetName = pathArr.shift();
            if (targetName && current.children) {
                var node = current.children.find(function (_a) {
                    var name = _a.name;
                    return name === targetName;
                });
                if (api_1.isDir(node)) {
                    current = node;
                }
                else {
                    return { value: null };
                }
            }
            else {
                return { value: null };
            }
        };
        while (pathArr.length) {
            var state_1 = _loop_1();
            if (typeof state_1 === "object")
                return state_1.value;
        }
        return current;
    };
    MemoryFileSystem.prototype.saveFile = function (fullPath, newContent) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.saveFileSync(fullPath, newContent)];
            });
        });
    };
    MemoryFileSystem.prototype.deleteFile = function (fullPath) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.deleteFileSync(fullPath)];
            });
        });
    };
    MemoryFileSystem.prototype.deleteDirectory = function (fullPath, recursive) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.deleteDirectorySync(fullPath, recursive)];
            });
        });
    };
    MemoryFileSystem.prototype.ensureDirectory = function (fullPath) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.ensureDirectorySync(fullPath)];
            });
        });
    };
    MemoryFileSystem.prototype.loadTextFile = function (fullPath) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.loadTextFileSync(fullPath)];
            });
        });
    };
    MemoryFileSystem.prototype.loadDirectoryTree = function (fullPath) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.loadDirectoryTreeSync(fullPath)];
            });
        });
    };
    MemoryFileSystem.prototype.loadDirectoryChildren = function (fullPath) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.loadDirectoryChildrenSync(fullPath)];
            });
        });
    };
    MemoryFileSystem.prototype.saveFileSync = function (fullPath, newContent) {
        if (this.isIgnored(fullPath)) {
            throw new Error("Unable to save ignored path: '" + fullPath + "'");
        }
        var pathArr = utils_1.getPathNodes(fullPath);
        var fileName = pathArr.pop();
        if (!fileName) {
            throw new Error("root is not a legal file name");
        }
        this.ensureDirectorySync(pathArr.join(api_1.pathSeparator));
        var parent = this.getPathTarget(pathArr);
        if (!parent) {
            // we get here if findNode couldn't resolve the parent and the node is not the root dir.
            // this should not happen after running ensureDirectory()
            throw new Error("unexpected error: not a legal file name? '" + fullPath + "'");
        }
        var existingChild = parent.children.find(function (_a) {
            var name = _a.name;
            return name === fileName;
        });
        if (api_1.isDir(existingChild)) {
            throw new Error("file save error for path '" + fullPath + "'");
        }
        if (api_1.isFile(existingChild)) {
            if (existingChild.content !== newContent) {
                existingChild.content = newContent;
                var type = 'fileChanged';
                this.events.emit(type, { type: type, fullPath: fullPath, newContent: newContent });
            }
        }
        else {
            var type = 'fileCreated';
            parent.children.push(new api_1.File(fileName, fullPath, newContent));
            this.events.emit(type, { type: type, fullPath: fullPath, newContent: newContent });
        }
    };
    MemoryFileSystem.prototype.deleteFileSync = function (fullPath) {
        var pathArr = utils_1.getPathNodes(fullPath);
        var parent = pathArr.length ? this.getPathTarget(pathArr.slice(0, pathArr.length - 1)) : null;
        if (api_1.isDir(parent) && !this.isIgnored(fullPath)) {
            var node_1 = parent.children.find(function (_a) {
                var name = _a.name;
                return name === pathArr[pathArr.length - 1];
            });
            if (api_1.isFile(node_1)) {
                parent.children = parent.children.filter(function (_a) {
                    var name = _a.name;
                    return name !== node_1.name;
                });
                this.events.emit('fileDeleted', { type: 'fileDeleted', fullPath: fullPath });
            }
            else if (api_1.isDir(node_1)) {
                throw new Error("Directory is not a file '" + fullPath + "'");
            }
        }
    };
    MemoryFileSystem.prototype.deleteDirectorySync = function (fullPath, recursive) {
        var pathArr = utils_1.getPathNodes(fullPath);
        if (pathArr.length === 0) {
            throw new Error("Can't delete root directory");
        }
        var parent = this.getPathTarget(pathArr.slice(0, pathArr.length - 1));
        if (api_1.isDir(parent) && !this.isIgnored(fullPath)) {
            var node_2 = parent.children.find(function (_a) {
                var name = _a.name;
                return name === pathArr[pathArr.length - 1];
            });
            if (api_1.isFile(node_2)) {
                throw new Error("File is not a directory '" + fullPath + "'");
            }
            else if (api_1.isDir(node_2)) {
                if (!recursive && node_2.children.length) {
                    throw new Error("Directory is not empty '" + fullPath + "'");
                }
                else {
                    parent.children = parent.children.filter(function (_a) {
                        var name = _a.name;
                        return name !== node_2.name;
                    });
                    this.recursiveEmitDeletion(node_2);
                }
            }
        }
    };
    MemoryFileSystem.prototype.ensureDirectorySync = function (fullPath) {
        var _this = this;
        if (this.isIgnored(fullPath)) {
            throw new Error("Unable to read and write ignored path: '" + fullPath + "'");
        }
        utils_1.getPathNodes(fullPath).reduce(function (current, nodeName) {
            var next = current.children.find(function (_a) {
                var name = _a.name;
                return name === nodeName;
            });
            if (api_1.isDir(next)) {
                return next;
            }
            if (api_1.isFile(next)) {
                throw new Error("File is not a directory " + next.fullPath);
            }
            var newDir = new api_1.Directory(nodeName, current.fullPath ? [current.fullPath, nodeName].join(api_1.pathSeparator) : nodeName);
            current.children.push(newDir);
            _this.events.emit('directoryCreated', {
                type: 'directoryCreated',
                fullPath: newDir.fullPath
            });
            return newDir;
        }, this.root);
    };
    MemoryFileSystem.prototype.loadTextFileSync = function (fullPath) {
        if (this.isIgnored(fullPath)) {
            throw new Error("Unable to read ignored path: '" + fullPath + "'");
        }
        var pathArr = utils_1.getPathNodes(fullPath);
        var parent = pathArr.length ? this.getPathTarget(pathArr.slice(0, pathArr.length - 1)) : null;
        if (api_1.isDir(parent)) {
            var node = parent.children.find(function (_a) {
                var name = _a.name;
                return name === pathArr[pathArr.length - 1];
            });
            if (api_1.isFile(node)) {
                return node.content || '';
            }
            else if (api_1.isDir(node)) {
                throw new Error("File is a directory " + fullPath);
            }
        }
        throw new Error("Cannot find file " + fullPath);
    };
    MemoryFileSystem.prototype.loadDirectoryTreeSync = function (fullPath) {
        if (fullPath === void 0) { fullPath = ''; }
        if (this.isIgnored(fullPath)) {
            throw new Error("Unable to read ignored path: '" + fullPath + "'");
        }
        var pathArr = utils_1.getPathNodes(fullPath);
        var dir = pathArr.length ? this.getPathTarget(pathArr) : this.root;
        if (!dir) {
            throw new Error("Unable to read folder in path: '" + fullPath + "'");
        }
        return this.parseTree(dir);
    };
    MemoryFileSystem.prototype.loadDirectoryChildrenSync = function (fullPath) {
        if (this.isIgnored(fullPath)) {
            throw new Error("Unable to read ignored path: '" + fullPath + "'");
        }
        var pathArr = utils_1.getPathNodes(fullPath);
        var dir = pathArr.length ? this.getPathTarget(pathArr) : this.root;
        if (!dir) {
            throw new Error("Unable to read folder in path: '" + fullPath + "'");
        }
        return dir.children.map(function (child) { return api_1.isDir(child) ? new api_1.ShallowDirectory(child.name, child.fullPath) : new api_1.File(child.name, child.fullPath); });
    };
    MemoryFileSystem.prototype.parseTree = function (node) {
        var _this = this;
        return new api_1.Directory(node.name, node.fullPath, node.children.map(function (child) { return api_1.isDir(child) ? _this.parseTree(child) : new api_1.File(child.name, child.fullPath); }));
    };
    MemoryFileSystem.prototype.recursiveEmitDeletion = function (node) {
        var _this = this;
        this.events.emit('directoryDeleted', { type: 'directoryDeleted', fullPath: node.fullPath });
        node.children.forEach(function (child) {
            if (api_1.isDir(child))
                _this.recursiveEmitDeletion(child);
            _this.events.emit('fileDeleted', { type: 'fileDeleted', fullPath: child.fullPath });
        });
    };
    return MemoryFileSystem;
}());
exports.MemoryFileSystem = MemoryFileSystem;
//# sourceMappingURL=memory-fs.js.map