"use strict";
var MainThreadFileSystem_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MainThreadFileSystem = void 0;
const tslib_1 = require("tslib");
const di_1 = require("@opensumi/di");
const ide_connection_1 = require("@opensumi/ide-connection");
const ide_core_browser_1 = require("@opensumi/ide-core-browser");
const ensure_dir_1 = require("@opensumi/ide-core-common/lib/browser-fs/ensure-dir");
const common_1 = require("@opensumi/ide-file-service/lib/common");
const vscode_1 = require("../../../common/vscode");
const converter_1 = require("../../../common/vscode/converter");
const file_system_1 = require("../../../common/vscode/file-system");
let MainThreadFileSystem = MainThreadFileSystem_1 = class MainThreadFileSystem {
    constructor(rpcProtocol) {
        this.rpcProtocol = rpcProtocol;
        this.disposable = new ide_core_browser_1.Disposable();
        this._fileProvider = new Map();
        this._proxy = this.rpcProtocol.getProxy(vscode_1.ExtHostAPIIdentifier.ExtHostFileSystem);
        const infoProxy = this.rpcProtocol.getProxy(vscode_1.ExtHostAPIIdentifier.ExtHostFileSystemInfo);
        for (const entry of this._fileService.listCapabilities()) {
            infoProxy.$acceptProviderInfos(entry.scheme, entry.capabilities);
        }
        this.disposable.addDispose(this._fileService.onDidChangeFileSystemProviderRegistrations((e) => { var _a, _b; return infoProxy.$acceptProviderInfos(e.scheme, (_b = (_a = e.provider) === null || _a === void 0 ? void 0 : _a.capabilities) !== null && _b !== void 0 ? _b : null); }));
        this.disposable.addDispose(this._fileService.onDidChangeFileSystemProviderCapabilities((e) => infoProxy.$acceptProviderInfos(e.scheme, e.provider.capabilities)));
    }
    dispose() {
        this.disposable.dispose();
        this._fileProvider.forEach((value) => value.dispose());
        this._fileProvider.clear();
    }
    $registerFileSystemProvider(handle, scheme, capabilities) {
        this.disposable.addDispose(this.schemeRegistry.registerFileSystemProvider({ scheme }));
        this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, capabilities, handle, this._proxy));
    }
    $unregisterProvider(handle) {
        (0, ide_core_browser_1.dispose)(this._fileProvider.get(handle));
        this._fileProvider.delete(handle);
    }
    $onFileSystemChange(handle, changes) {
        const fileProvider = this._fileProvider.get(handle);
        if (!fileProvider) {
            throw new Error('Unknown file provider');
        }
        fileProvider.$onFileSystemChange(changes);
    }
    // --- consumer fs, vscode.workspace.fs
    $stat(uri) {
        return this._fileService
            .getFileStat(ide_core_browser_1.URI.revive(uri).toString())
            .then((stat) => (0, converter_1.toFileStat)(stat))
            .catch(MainThreadFileSystem_1._handleError);
    }
    $readdir(uri) {
        return this._fileService
            .getFileStat(ide_core_browser_1.URI.revive(uri).toString())
            .then((stat) => {
            if (!stat) {
                throw new Error('file stat undefined');
            }
            if (!stat.isDirectory) {
                const err = new Error(stat.uri);
                err.name = file_system_1.FileSystemProviderErrorCode.FileNotADirectory;
                throw err;
            }
            return !stat.children
                ? []
                : stat.children.map((child) => [new ide_core_browser_1.URI(child.uri).displayName, MainThreadFileSystem_1._asFileType(child)]);
        })
            .catch(MainThreadFileSystem_1._handleError);
    }
    static _asFileType(stat) {
        let res = 0;
        if (stat.type && stat.type === common_1.FileType.File) {
            res += common_1.FileType.File;
        }
        else if (stat.isDirectory) {
            res += common_1.FileType.Directory;
        }
        if (stat.isSymbolicLink) {
            res += common_1.FileType.SymbolicLink;
        }
        return res;
    }
    $readFile(uri) {
        return this._fileService
            .readFile(ide_core_browser_1.URI.revive(uri).toString())
            .then((file) => file.content.buffer)
            .catch(MainThreadFileSystem_1._handleError);
    }
    async $writeFile(uri, content) {
        try {
            const _uri = ide_core_browser_1.URI.revive(uri);
            const stat = await this._fileService.getFileStat(_uri.toString(), false);
            if (!stat) {
                // 文件不存在
                await (0, ensure_dir_1.ensureDir)(new ide_core_browser_1.URI(_uri).path.dir.toString(), {
                    mkdir: (path) => this.$mkdir(ide_core_browser_1.URI.file(path).codeUri),
                    access: (path) => this._fileService.access(ide_core_browser_1.URI.file(path).codeUri.toString()),
                });
                await this._fileService.createFile(_uri.toString(), { content: ide_core_browser_1.BinaryBuffer.wrap(content).toString() });
            }
            else {
                await this._fileService.setContent(stat, content);
            }
        }
        catch (error) {
            return MainThreadFileSystem_1._handleError(error);
        }
    }
    $rename(source, target, opts) {
        return this._fileService
            .move(ide_core_browser_1.URI.revive(source).toString(), ide_core_browser_1.URI.revive(target).toString(), opts)
            .then(() => undefined)
            .catch(MainThreadFileSystem_1._handleError);
    }
    $copy(source, target, opts) {
        return this._fileService
            .copy(ide_core_browser_1.URI.revive(source).toString(), ide_core_browser_1.URI.revive(target).toString(), opts)
            .then(() => undefined)
            .catch(MainThreadFileSystem_1._handleError);
    }
    $mkdir(uri) {
        return this._fileService
            .createFolder(ide_core_browser_1.URI.revive(uri).toString())
            .then(() => undefined)
            .catch(MainThreadFileSystem_1._handleError);
    }
    $delete(uri, opts) {
        return this._fileService
            .delete(ide_core_browser_1.URI.revive(uri).toString(), { moveToTrash: opts.useTrash })
            .catch(MainThreadFileSystem_1._handleError);
    }
    static _handleError(err) {
        if (err instanceof common_1.FileOperationError) {
            switch (err.fileOperationResult) {
                case 1 /* FileOperationResult.FILE_NOT_FOUND */:
                    err.name = file_system_1.FileSystemProviderErrorCode.FileNotFound;
                    break;
                case 0 /* FileOperationResult.FILE_IS_DIRECTORY */:
                    err.name = file_system_1.FileSystemProviderErrorCode.FileIsADirectory;
                    break;
                case 6 /* FileOperationResult.FILE_PERMISSION_DENIED */:
                    err.name = file_system_1.FileSystemProviderErrorCode.NoPermissions;
                    break;
                case 4 /* FileOperationResult.FILE_MOVE_CONFLICT */:
                    err.name = file_system_1.FileSystemProviderErrorCode.FileExists;
                    break;
            }
        }
        throw err;
    }
};
exports.MainThreadFileSystem = MainThreadFileSystem;
tslib_1.__decorate([
    (0, di_1.Autowired)(common_1.IFileServiceClient),
    tslib_1.__metadata("design:type", Object)
], MainThreadFileSystem.prototype, "_fileService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(common_1.IBrowserFileSystemRegistry),
    tslib_1.__metadata("design:type", Object)
], MainThreadFileSystem.prototype, "schemeRegistry", void 0);
exports.MainThreadFileSystem = MainThreadFileSystem = MainThreadFileSystem_1 = tslib_1.__decorate([
    (0, di_1.Injectable)({ multiple: true }),
    tslib_1.__metadata("design:paramtypes", [Object])
], MainThreadFileSystem);
class RemoteFileSystemProvider {
    get readonly() {
        return !!(this.capabilities & 2048 /* FileSystemProviderCapabilities.Readonly */);
    }
    constructor(fileService, scheme, capabilities, _handle, _proxy) {
        this._handle = _handle;
        this._proxy = _proxy;
        this._onDidChange = new ide_core_browser_1.Emitter();
        this.onDidChangeFile = this._onDidChange.event;
        this.onDidChangeCapabilities = ide_core_browser_1.Event.None;
        this.capabilities = capabilities;
        this._registration = fileService.registerProvider(scheme, this);
    }
    dispose() {
        this._registration.dispose();
        this._onDidChange.dispose();
    }
    watch(resource, opts) {
        const session = Math.random();
        this._proxy.$watch(this._handle, session, resource, opts);
        return session;
    }
    unwatch(session) {
        this._proxy.$unwatch(this._handle, session);
    }
    $onFileSystemChange(changes) {
        this._onDidChange.fire(changes.map(RemoteFileSystemProvider._createFileChange));
    }
    static _createFileChange(dto) {
        return { uri: dto.uri, type: dto.type };
    }
    // --- forwarding calls
    async stat(resource) {
        const stat = await this.doGetStat(resource);
        return stat;
    }
    async readFile(resource) {
        const buffer = await this._proxy.$readFile(this._handle, resource);
        return buffer;
    }
    writeFile(resource, content, opts) {
        return this._proxy.$writeFile(this._handle, resource, content, opts);
    }
    delete(resource, opts) {
        return this._proxy.$delete(this._handle, resource, opts);
    }
    createDirectory(resource) {
        return this._proxy.$mkdir(this._handle, resource);
    }
    readDirectory(resource) {
        return this._proxy.$readdir(this._handle, resource);
    }
    rename(resource, target, opts) {
        return this._proxy.$rename(this._handle, resource, target, opts);
    }
    copy(resource, target, opts) {
        return this._proxy.$copy(this._handle, resource, target, opts);
    }
    async doGetStat(resource, depth = 1) {
        var _a;
        const stat = await this._proxy.$stat(this._handle, resource);
        const mainStat = (0, converter_1.fromFileStat)(stat, resource);
        if (mainStat.isDirectory) {
            mainStat.children = await this.doGetChildren(resource, depth);
        }
        mainStat.readonly =
            Boolean(((_a = stat.permissions) !== null && _a !== void 0 ? _a : 0) & file_system_1.FilePermission.Readonly) ||
                Boolean(this.capabilities & 2048 /* FileSystemProviderCapabilities.Readonly */);
        return mainStat;
    }
    async doGetChildren(resource, depth) {
        if (depth <= 0) {
            return [];
        }
        const nameTypeTuples = await this.readDirectory(resource);
        // 在我们的设计中stat支持递归获取多层children，默认获取第一层
        const children = await Promise.all(nameTypeTuples
            .map((item) => new ide_core_browser_1.URI(resource).resolve(item[0]))
            .map((childUri) => this.doGetStat(childUri.codeUri, depth - 1)));
        return children;
    }
}
//# sourceMappingURL=main.thread.file-system.js.map