"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
const FileBase_1 = require("./FileBase");
const FileSystemStorage_1 = require("./FileSystemStorage");
const StorageUtilities_1 = require("./StorageUtilities");
const Log_1 = require("../core/Log");
class FileSystemFile extends FileBase_1.default {
    _name;
    _parentFolder;
    lastSavedSize;
    _handle;
    _writeHandle;
    get handle() {
        return this._handle;
    }
    set handle(newHandle) {
        this._handle = newHandle;
    }
    get writeHandle() {
        return this._writeHandle;
    }
    set writeHandle(newHandle) {
        this._writeHandle = newHandle;
    }
    get name() {
        return this._name;
    }
    get parentFolder() {
        return this._parentFolder;
    }
    get fullPath() {
        return this._parentFolder.fullPath + FileSystemStorage_1.default.fileSystemFolderDelimiter + this.name;
    }
    get size() {
        if (this.content == null) {
            return -1;
        }
        return this.content.length;
    }
    constructor(parentFolder, fileName) {
        super();
        this.lastSavedSize = -1;
        this._parentFolder = parentFolder;
        this._name = fileName;
    }
    async getHandle() {
        if (!this._handle) {
            if (this._writeHandle) {
                return this._writeHandle;
            }
            if (this.parentFolder) {
                const parentFolderHandle = await this.parentFolder.getHandle();
                if (parentFolderHandle) {
                    try {
                        this._handle = await parentFolderHandle.getFileHandle(this.name, {
                            create: false,
                        });
                    }
                    catch (e) {
                        return; // if the file doesn't exist an exception will be thrown
                        //Log.debugAlert("File r/o retrieval: " + e);
                    }
                }
            }
        }
        return this._handle;
    }
    async ensureWriteHandle() {
        if (!this._writeHandle) {
            if (this.parentFolder) {
                await this.parentFolder.ensureWriteHandle();
                if (this.parentFolder.writeHandle) {
                    try {
                        this._writeHandle = await this.parentFolder.writeHandle.getFileHandle(this.name, {
                            create: true,
                        });
                    }
                    catch (e) {
                        Log_1.default.debugAlert("File r/w retrieval: " + e);
                    }
                }
            }
        }
        Log_1.default.assert(this._writeHandle !== undefined, "No folder handle.");
        return this._writeHandle;
    }
    get isContentLoaded() {
        return this.lastLoadedOrSaved != null || this.modified != null;
    }
    async deleteThisFile(skipRemoveFromParent) {
        if (this.parentFolder.storage.readOnly) {
            throw new Error("Can't save read-only file.");
        }
        if (skipRemoveFromParent !== true) {
            this._parentFolder._removeFile(this);
        }
        await this._parentFolder._removeFileExistence(this.name);
        return true;
    }
    async moveTo(newStorageRelativePath) {
        const newFolderPath = StorageUtilities_1.default.getFolderPath(newStorageRelativePath);
        const newFileName = StorageUtilities_1.default.getLeafName(newStorageRelativePath);
        if (newFileName.length < 2) {
            throw new Error("New path is not correct.");
        }
        const newParentFolder = await this._parentFolder.storage.ensureFolderFromStorageRelativePath(newFolderPath);
        if (newParentFolder.files[newFileName] !== undefined) {
            throw new Error("File exists at specified path.");
        }
        await this.loadContent();
        const originalName = this._name;
        const originalParentFolder = this._parentFolder;
        this._name = newFileName;
        this._parentFolder = newParentFolder;
        this.modified = new Date();
        newParentFolder._addExistingFile(this);
        originalParentFolder._removeFileExistence(originalName);
        return true;
    }
    async loadContent(force) {
        if (force || !this.lastLoadedOrSaved) {
            const handle = await this.getHandle();
            if (handle) {
                const file = await handle.getFile();
                const encoding = StorageUtilities_1.default.getEncodingByFileName(file.name);
                if (encoding === StorageUtilities_1.EncodingType.ByteBuffer) {
                    const stream = file.stream();
                    let result = undefined;
                    let reader = undefined;
                    try {
                        reader = stream.getReader();
                    }
                    catch (e) {
                        Log_1.default.debugAlert("Could not get a reader for for file (first): " + this.storageRelativePath + " (" + file.name + ")");
                    }
                    if (reader) {
                        try {
                            result = await reader.read();
                        }
                        catch (e) {
                            Log_1.default.debugAlert("Could not read content for file (first): " + this.storageRelativePath + " (" + file.name + ")");
                        }
                        const byteArrays = [];
                        let length = 0;
                        do {
                            if (result && result.value) {
                                byteArrays.push(result.value);
                                length += result.value.length;
                            }
                            try {
                                result = await reader.read();
                            }
                            catch (e) {
                                Log_1.default.debugAlert("Could not read content for file: " + this.storageRelativePath + " (" + file.name + ")");
                            }
                        } while (result && !result.done);
                        const mergedArray = new Uint8Array(length);
                        let offset = 0;
                        for (const byteArray of byteArrays) {
                            mergedArray.set(byteArray, offset);
                            offset += byteArray.length;
                        }
                        this._content = mergedArray;
                    }
                }
                else if (encoding === StorageUtilities_1.EncodingType.Utf8String) {
                    this._content = await file.text();
                }
            }
            else {
                this._content = null;
            }
            this.lastLoadedOrSaved = new Date();
        }
        return this.lastLoadedOrSaved;
    }
    setContent(newContent) {
        const areEqual = StorageUtilities_1.default.contentsAreEqual(this._content, newContent);
        if (!areEqual) {
            if (!this.lastLoadedOrSaved) {
                this.lastLoadedOrSaved = new Date();
                this.lastLoadedOrSaved = new Date(this.lastLoadedOrSaved.getTime() - 1);
                // Log.debugAlert("Setting a file without loading it first.");
            }
            this._content = newContent;
            this.contentWasModified();
        }
    }
    async saveContent(force) {
        if (this.parentFolder.storage.readOnly) {
            throw new Error("Can't save read-only file.");
        }
        if (this.needsSave || force) {
            Log_1.default.assert(this.content !== null, "Null content found.");
            if (this.content !== null) {
                const handle = await this.ensureWriteHandle();
                if (handle) {
                    const writable = await handle.createWritable();
                    await writable.write(this.content);
                    await writable.close();
                }
                await this._parentFolder.save(false);
            }
        }
        this.lastLoadedOrSaved = new Date();
        return this.lastLoadedOrSaved;
    }
}
exports.default = FileSystemFile;

//# sourceMappingURL=../maps/storage/FileSystemFile.js.map
