"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
const IProjectItemData_1 = require("./IProjectItemData");
const Log_1 = require("./../core/Log");
const IProjectItemData_2 = require("./IProjectItemData");
const ste_events_1 = require("ste-events");
const StorageUtilities_1 = require("../storage/StorageUtilities");
const EntityTypeDefinition_1 = require("../minecraft/EntityTypeDefinition");
const IProjectData_1 = require("./IProjectData");
const MCWorld_1 = require("../minecraft/MCWorld");
const ZipStorage_1 = require("../storage/ZipStorage");
const Utilities_1 = require("../core/Utilities");
const IStorage_1 = require("../storage/IStorage");
const ProjectItemUtilities_1 = require("./ProjectItemUtilities");
const ProjectAutogeneration_1 = require("./ProjectAutogeneration");
const ProjectItemRelations_1 = require("./ProjectItemRelations");
const ProjectItemVariant_1 = require("./ProjectItemVariant");
const IProjectItemVariant_1 = require("./IProjectItemVariant");
const Database_1 = require("../minecraft/Database");
const ProjectVariant_1 = require("./ProjectVariant");
const MinecraftUtilities_1 = require("../minecraft/MinecraftUtilities");
class ProjectItem {
    _data;
    _project;
    _onPropertyChanged = new ste_events_1.EventDispatcher();
    _onFileRetrieved = new ste_events_1.EventDispatcher();
    _onFolderRetrieved = new ste_events_1.EventDispatcher();
    _onLoaded = new ste_events_1.EventDispatcher();
    _defaultFile;
    _defaultFolder;
    _pendingLoadRequests = [];
    _isLoading = false;
    _isFileContentProcessed = false;
    _imageUrlBase64Cache;
    _pack;
    _primaryFile;
    _accessoryFolder;
    parentItems;
    childItems;
    unfulfilledRelationships;
    _variants;
    constructor(parent, incomingData) {
        this._project = parent;
        this._defaultFile = null;
        this._defaultFolder = null;
        this._accessoryFolder = null;
        this._isFileContentProcessed = false;
        this._variants = {};
        this._handleMCWorldLoaded = this._handleMCWorldLoaded.bind(this);
        this.sortVariantsMostImportantFirst = this.sortVariantsMostImportantFirst.bind(this);
        this.sortVariantsMostImportantLast = this.sortVariantsMostImportantLast.bind(this);
        if (incomingData) {
            this._data = incomingData;
        }
        else {
            this._data = {
                variants: {},
                itemType: IProjectItemData_2.ProjectItemType.unknown,
                projectPath: null,
                storageType: IProjectItemData_1.ProjectItemStorageType.singleFile,
                tags: [],
                name: "",
            };
        }
    }
    get parentItemCount() {
        if (this.parentItems === undefined) {
            return 0;
        }
        return this.parentItems.length;
    }
    get childItemCount() {
        if (this.childItems === undefined) {
            return 0;
        }
        return this.childItems.length;
    }
    get unfulfilledRelationshipsCount() {
        if (this.unfulfilledRelationships === undefined) {
            return 0;
        }
        return this.unfulfilledRelationships.length;
    }
    get isInWorld() {
        return this._data.isInWorld;
    }
    set isInWorld(isInWorld) {
        this._data.isInWorld = isInWorld;
    }
    get project() {
        return this._project;
    }
    get onPropertyChanged() {
        return this._onPropertyChanged.asEvent();
    }
    get onLoaded() {
        return this._onLoaded.asEvent();
    }
    get onFileRetrieved() {
        return this._onFileRetrieved.asEvent();
    }
    get onFolderRetrieved() {
        return this._onFolderRetrieved.asEvent();
    }
    get gitHubReference() {
        return this._data.gitHubReference;
    }
    get isInFileContainer() {
        if (!this.projectPath) {
            return false;
        }
        return this.projectPath.indexOf("#") >= 0;
    }
    get isFileContainerStorageItem() {
        return (this.itemType === IProjectItemData_2.ProjectItemType.zip ||
            this.itemType === IProjectItemData_2.ProjectItemType.MCWorld ||
            this.itemType === IProjectItemData_2.ProjectItemType.MCProject ||
            this.itemType === IProjectItemData_2.ProjectItemType.MCAddon ||
            this.itemType === IProjectItemData_2.ProjectItemType.MCPack ||
            this.itemType === IProjectItemData_2.ProjectItemType.MCTemplate);
    }
    hasCustomVariants() {
        for (const key in this._data.variants) {
            if (key !== "") {
                return true;
            }
        }
        return false;
    }
    hasVersionSliceCustomVariants() {
        for (const key in this._data.variants) {
            const varType = this._data.variants[key].variantType;
            if (key !== "" &&
                (varType === IProjectItemVariant_1.ProjectItemVariantType.versionSlice || varType === IProjectItemVariant_1.ProjectItemVariantType.versionSliceAlt)) {
                return true;
            }
        }
        return false;
    }
    _shouldEnsureDefaultVariant() {
        return (this.defaultFile && (this.defaultFile.content || !this.hasCustomVariants())) || this.defaultFolder;
    }
    getVariant(variantName) {
        if (variantName === "" && this._shouldEnsureDefaultVariant()) {
            return this.ensureDefaultVariant();
        }
        return this._variants[variantName];
    }
    get isWorld() {
        return (this.itemType === IProjectItemData_2.ProjectItemType.MCProject ||
            this.itemType === IProjectItemData_2.ProjectItemType.MCWorld ||
            this.itemType === IProjectItemData_2.ProjectItemType.MCTemplate ||
            this.itemType === IProjectItemData_2.ProjectItemType.worldFolder);
    }
    static getGitHubSignature(info) {
        let sig = info.owner + "|" + info.repoName + "|";
        if (info.branch !== undefined) {
            sig += info.branch;
        }
        if (info.folder !== undefined) {
            sig += "|" + info.folder;
        }
        return sig;
    }
    get defaultVariant() {
        if (this._shouldEnsureDefaultVariant()) {
            return this.ensureDefaultVariant();
        }
        return this._variants[""];
    }
    async ensureAccessoryFolder() {
        if (this._accessoryFolder) {
            return this._accessoryFolder;
        }
        const rootAccessoryFolder = await this.project.ensureProjectItemAccessoryFolder();
        const folderPath = ProjectItemUtilities_1.default.getAccessoryFolderPathFromFilePath(this);
        this._accessoryFolder = await rootAccessoryFolder.ensureFolderFromRelativePath(folderPath);
        return this._accessoryFolder;
    }
    ensureDefaultVariant() {
        return this.ensureVariant("");
    }
    getVariantList() {
        if (this.defaultFile || this.defaultFolder) {
            this.ensureDefaultVariant();
        }
        return this._getVariantList();
    }
    _getVariantList() {
        const vararr = [];
        for (const key in this._data.variants) {
            const variant = this.ensureVariant(key);
            vararr.push(variant);
        }
        return vararr;
    }
    getVariantListMostImportantLast() {
        const vararr = [];
        const varKeys = Object.keys(this._data.variants);
        varKeys.sort(this.sortVariantsMostImportantLast);
        for (const key of varKeys) {
            const variant = this.ensureVariant(key);
            vararr.push(variant);
        }
        return vararr;
    }
    getVariantListMostImportantFirst() {
        const vararr = [];
        const varKeys = Object.keys(this._data.variants);
        varKeys.sort(this.sortVariantsMostImportantFirst);
        for (const key of varKeys) {
            const variant = this.ensureVariant(key);
            vararr.push(variant);
        }
        return vararr;
    }
    hasNonDefaultVariant() {
        const vararr = this._getVariantList();
        if (vararr.length === 0) {
            return false;
        }
        if (vararr.length > 1) {
            return true;
        }
        if (vararr[0].label !== "") {
            return true;
        }
        return false;
    }
    ensureVariant(label) {
        label = ProjectVariant_1.default.canonicalizeVariantLabel(label);
        if (!Utilities_1.default.isUsableAsObjectKey(label)) {
            Log_1.default.unsupportedToken(label);
            throw new Error();
        }
        if (!this._variants[label]) {
            const pv = this.project.ensureVariant(label);
            if (!this._data.variants) {
                this._data.variants = {};
            }
            if (this._data.variants[label] === undefined) {
                this._data.variants[label] = { label: label, variantType: IProjectItemVariant_1.ProjectItemVariantType.general };
            }
            this._primaryFile = undefined;
            this._variants[label] = new ProjectItemVariant_1.default(this, this._data.variants[label], pv);
        }
        return this._variants[label];
    }
    /// NOTE: ProjectItem.ensureFileStorage or ensureStorage should be called before this method.
    getFile(variantName) {
        if (variantName === undefined || variantName === "") {
            return this._defaultFile;
        }
        const variant = this.ensureVariant(variantName);
        return variant.file;
    }
    /// NOTE: ProjectItem.ensureFolderStorage or ensureStorage should be called before this method.
    getFolder(variantName) {
        if (variantName === undefined || variantName === "") {
            return this._defaultFolder;
        }
        const variant = this.ensureVariant(variantName);
        return variant.folder;
    }
    /// NOTE: ProjectItem.ensure*Storage should be called before this method.
    async getPack() {
        if (this._pack) {
            return this._pack;
        }
        let thisPath = undefined;
        if (this._defaultFile) {
            thisPath = this._defaultFile.storageRelativePath;
        }
        else if (this._defaultFolder) {
            thisPath = this._defaultFolder.storageRelativePath;
        }
        if (thisPath === undefined) {
            return undefined;
        }
        thisPath = StorageUtilities_1.default.canonicalizePath(thisPath);
        await this.project.ensurePacks();
        for (const pack of this.project.packs) {
            if (thisPath.startsWith(StorageUtilities_1.default.canonicalizePath(pack.folder.storageRelativePath))) {
                this._pack = pack;
                return this._pack;
            }
        }
        return undefined;
    }
    addUnfulfilledRelationship(path, itemType, isVanillaDependent) {
        let pir = {
            parentItem: this,
            path: path,
            itemType: itemType,
            isVanillaDependent: isVanillaDependent === true,
        };
        if (this.unfulfilledRelationships === undefined) {
            this.unfulfilledRelationships = [];
        }
        this.unfulfilledRelationships.push(pir);
    }
    async ensureDependencies() {
        await ProjectItemRelations_1.default.calculateForItem(this);
    }
    addChildItem(childItem) {
        if (this.childItems) {
            for (const rel of this.childItems) {
                if (rel.childItem === childItem && rel.parentItem === this) {
                    return;
                }
            }
        }
        if (childItem === this) {
            return;
        }
        if (ProjectItemUtilities_1.default.wouldBeCircular(childItem)) {
            return;
        }
        let hasChild = false;
        let childHasParent = false;
        if (this.childItems === undefined) {
            this.childItems = [];
        }
        if (childItem.parentItems === undefined) {
            childItem.parentItems = [];
        }
        for (const existingRelation of this.childItems) {
            if (existingRelation.childItem === childItem && existingRelation.parentItem === this) {
                hasChild = true;
            }
        }
        for (const existingRelation of childItem.parentItems) {
            if (existingRelation.childItem === childItem && existingRelation.parentItem === this) {
                childHasParent = true;
            }
        }
        const pir = {
            parentItem: this,
            childItem: childItem,
        };
        if (!hasChild) {
            this.childItems.push(pir);
        }
        if (!childHasParent) {
            childItem.parentItems.push(pir);
        }
    }
    addParentItem(parentItem) {
        if (ProjectItemUtilities_1.default.wouldBeCircular(parentItem)) {
            return;
        }
        if (parentItem === this) {
            return;
        }
        if (this.parentItems === undefined) {
            this.parentItems = [];
        }
        if (parentItem.childItems === undefined) {
            parentItem.childItems = [];
        }
        let hasParent = false;
        let parentHasChild = false;
        for (const existingRelation of this.parentItems) {
            if (existingRelation.parentItem === parentItem && existingRelation.childItem === this) {
                hasParent = true;
            }
        }
        for (const existingRelation of parentItem.childItems) {
            if (existingRelation.parentItem === parentItem && existingRelation.childItem === this) {
                parentHasChild = true;
            }
        }
        const pir = {
            parentItem: parentItem,
            childItem: this,
        };
        if (!hasParent) {
            this.parentItems.push(pir);
        }
        if (!parentHasChild) {
            parentItem.childItems.push(pir);
        }
    }
    toString() {
        return this.itemType + ": " + this.projectPath;
    }
    /// NOTE: ProjectItem.ensure*Storage should be called before this method.
    async getPackRelativePath() {
        const pack = await this.getPack();
        if (!pack) {
            return undefined;
        }
        if (this._defaultFile) {
            return this._defaultFile.getFolderRelativePath(pack.folder);
        }
        else if (this._defaultFolder) {
            return this._defaultFolder.getFolderRelativePath(pack.folder);
        }
        return undefined;
    }
    static gitHubReferencesEqual(refA, refB) {
        if (refA === refB) {
            return true;
        }
        if (refA === undefined && refB === undefined) {
            return true;
        }
        if (refA !== undefined &&
            refB !== undefined &&
            refA.owner === refB.owner &&
            refA.repoName === refB.repoName &&
            refA.folder === refB.folder &&
            refA.branch === refB.branch) {
            return true;
        }
        return false;
    }
    set gitHubReference(value) {
        if (ProjectItem.gitHubReferencesEqual(this._data.gitHubReference, value)) {
            return;
        }
        this._data.gitHubReference = value;
        this._project.notifyProjectItemChanged(this);
    }
    get title() {
        return (StorageUtilities_1.default.getContaineredFileLeafPath(this.projectPath) +
            " (" +
            ProjectItemUtilities_1.default.getDescriptionForType(this._data.itemType).toLowerCase() +
            ")");
    }
    get typeTitle() {
        return ProjectItemUtilities_1.default.getDescriptionForType(this._data.itemType);
    }
    getPackFolderName() {
        if (this.projectPath === undefined || this.projectPath === null) {
            return undefined;
        }
        let folderStoragePath = StorageUtilities_1.default.getFolderPath(this.projectPath);
        if (folderStoragePath === undefined) {
            return undefined;
        }
        let folderStoragePathLower = folderStoragePath.toLowerCase();
        if (this.project.packs.length > 2) {
            const endOfPacks = folderStoragePathLower.indexOf("_packs/");
            if (endOfPacks > 0) {
                const endOfPacksSegment = folderStoragePathLower.indexOf("/", endOfPacks + 7);
                if (endOfPacksSegment > 0) {
                    return folderStoragePath.substring(endOfPacks + 7, endOfPacksSegment);
                }
            }
        }
        return undefined;
    }
    get folderPath() {
        if (this.projectPath === undefined || this.projectPath === null) {
            return undefined;
        }
        return StorageUtilities_1.default.getFolderPath(this.projectPath);
    }
    getFolderGroupingPath() {
        if (this.projectPath === undefined || this.projectPath === null) {
            return undefined;
        }
        let folderStoragePath = StorageUtilities_1.default.getFolderPath(this.projectPath);
        if (folderStoragePath === undefined) {
            return undefined;
        }
        folderStoragePath = MinecraftUtilities_1.default.clearCommonTerms(folderStoragePath);
        let folderStoragePathLower = folderStoragePath.toLowerCase();
        const folderTypeRoots = ProjectItemUtilities_1.default.getFolderRootsForType(this.itemType);
        folderTypeRoots.push("zip");
        for (const folderTypeRoot of folderTypeRoots) {
            if (this.project.hasMultiplePacksOfSameType) {
                folderStoragePath = Utilities_1.default.replaceAllCaseInsensitive(folderStoragePath, "/" + folderTypeRoot + "/", "/");
            }
            else {
                const start = folderStoragePathLower.indexOf("/" + folderTypeRoot + "/");
                if (start >= 0) {
                    let packPrefix = this.getPackFolderName();
                    if (packPrefix === undefined) {
                        packPrefix = "";
                    }
                    else {
                        packPrefix += " ";
                    }
                    folderStoragePath = packPrefix + folderStoragePath.substring(start + 2 + folderTypeRoot.length);
                    folderStoragePathLower = folderStoragePath.toLowerCase();
                }
            }
        }
        folderStoragePath = folderStoragePath.replace(/#/gi, " ").trim();
        return folderStoragePath;
    }
    getSchemaPath() {
        return ProjectItemUtilities_1.default.getSchemaPathForType(this.itemType);
    }
    getFormPath() {
        return ProjectItemUtilities_1.default.getFormPathForType(this.itemType);
    }
    get errorStatus() {
        return this._data.errorStatus;
    }
    set errorStatus(newErrorStatus) {
        this._data.errorStatus = newErrorStatus;
    }
    get source() {
        return this._data.source;
    }
    set source(newSource) {
        this._data.source = newSource;
    }
    get errorMessage() {
        return this._data.errorMessage;
    }
    set errorMessage(newErrorMessage) {
        this._data.errorMessage = newErrorMessage;
    }
    get projectPath() {
        if (this._data.projectPath === undefined && this._data.storagePath) {
            this._data.projectPath = this._data.storagePath;
            return this._data.storagePath;
        }
        return this._data.projectPath;
    }
    set projectPath(newBasePath) {
        this._data.projectPath = newBasePath;
    }
    get effectiveEditPreference() {
        const ep = this.editPreference;
        if (ep === IProjectItemData_1.ProjectItemEditPreference.projectDefault) {
            return this._project.editPreference;
        }
        else if (ep === IProjectItemData_1.ProjectItemEditPreference.forceRaw) {
            return IProjectData_1.ProjectEditPreference.raw;
        }
        else {
            return IProjectData_1.ProjectEditPreference.summarized;
        }
    }
    get editPreference() {
        if (this._data.editPreference === undefined) {
            return IProjectItemData_1.ProjectItemEditPreference.projectDefault;
        }
        return this._data.editPreference;
    }
    set editPreference(newEditPreference) {
        this._data.editPreference = newEditPreference;
    }
    get storageType() {
        if (this._data.storageType === undefined) {
            return IProjectItemData_1.ProjectItemStorageType.singleFile;
        }
        return this._data.storageType;
    }
    set storageType(newStorageType) {
        this._data.storageType = newStorageType;
    }
    get creationType() {
        return this._data.creationType;
    }
    set creationType(newCreationType) {
        this._data.creationType = newCreationType;
    }
    get itemType() {
        return this._data.itemType;
    }
    get defaultFile() {
        return this._defaultFile;
    }
    sortVariantsMostImportantLast(a, b) {
        if (!this._variants) {
            this._getVariantList();
        }
        if (!this._variants) {
            return Utilities_1.default.staticCompare(a, b);
        }
        const va = this._variants[a];
        const vb = this._variants[b];
        if (!va || !vb || !va.label || !vb.label) {
            return 0;
        }
        if ((va.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSlice &&
            vb.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSlice) ||
            (va.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSliceAlt &&
                vb.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSliceAlt)) {
            const versionIndexA = Database_1.default.getVersionIndexFromVersionStr(va.label);
            const versionIndexB = Database_1.default.getVersionIndexFromVersionStr(vb.label);
            return versionIndexA - versionIndexB;
        }
        return Utilities_1.default.staticCompare(va.label.toString(), vb.label.toString());
    }
    sortVariantsMostImportantFirst(a, b) {
        if (!this._variants) {
            this._getVariantList();
        }
        if (!this._variants) {
            return Utilities_1.default.staticCompare(a, b);
        }
        const va = this._variants[a];
        const vb = this._variants[b];
        if (!va || !vb || !va.label || !vb.label) {
            return 0;
        }
        if ((va.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSlice &&
            vb.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSlice) ||
            (va.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSliceAlt &&
                vb.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSliceAlt)) {
            const versionIndexA = Database_1.default.getVersionIndexFromVersionStr(va.label);
            const versionIndexB = Database_1.default.getVersionIndexFromVersionStr(vb.label);
            return versionIndexB - versionIndexA;
        }
        return vb.label.localeCompare(va.label);
    }
    get primaryVariantLabel() {
        const variantKeys = Object.keys(this._variants);
        // if we have version slices, return the latest one that has a file
        if (this.hasVersionSliceCustomVariants()) {
            variantKeys.sort(this.sortVariantsMostImportantFirst);
            for (const variantName of variantKeys) {
                const variant = this._variants[variantName];
                if (variant.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSlice ||
                    variant.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSliceAlt) {
                    if (variant.file) {
                        return variant.label;
                    }
                }
            }
        }
        if (this._defaultFile) {
            return undefined;
        }
        for (const variantName of variantKeys) {
            if (variantName) {
                const variant = this._variants[variantName];
                if (variant.file) {
                    return variant.label;
                }
            }
        }
        return undefined;
    }
    get primaryFile() {
        if (this._primaryFile) {
            return this._primaryFile;
        }
        // if we have version slices, return the latest one that has a file
        if (this.hasVersionSliceCustomVariants()) {
            const variantKeys = Object.keys(this._variants);
            variantKeys.sort(this.sortVariantsMostImportantFirst);
            for (const variantName of variantKeys) {
                const variant = this._variants[variantName];
                if (variant.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSlice ||
                    variant.variantType === IProjectItemVariant_1.ProjectItemVariantType.versionSliceAlt) {
                    if (variant.file) {
                        this._primaryFile = variant.file;
                        return this._primaryFile;
                    }
                }
            }
        }
        if (this._defaultFile && (!this._defaultFile.isContentLoaded || this._defaultFile.content)) {
            return this._defaultFile;
        }
        const variantKeys = Object.keys(this._variants);
        variantKeys.sort(this.sortVariantsMostImportantFirst);
        for (const variantName of variantKeys) {
            if (variantName) {
                const variant = this._variants[variantName];
                if (variant.file) {
                    this._primaryFile = variant.file;
                    return this._primaryFile;
                }
            }
        }
        // as a last fallback, return an assumedly content-less default file
        if (this._defaultFile) {
            this._primaryFile = this._defaultFile;
            return this._primaryFile;
        }
        return null;
    }
    get defaultFolder() {
        return this._defaultFolder;
    }
    set itemType(newItemType) {
        this._data.itemType = newItemType;
        this._onPropertyChanged.dispatch(this, "itemType");
        this._project.notifyProjectItemChanged(this);
    }
    get isContentLoaded() {
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.folder) {
            if (!this.defaultFolder) {
                return false;
            }
            if (!this.defaultFolder.isLoaded) {
                return false;
            }
            if (this.itemType === IProjectItemData_2.ProjectItemType.worldFolder) {
                if (!this.defaultFolder.manager || !(this.defaultFolder.manager instanceof MCWorld_1.default)) {
                    return false;
                }
                const world = this.defaultFolder.manager;
                return world.isLoaded;
            }
            return true;
        }
        else if (this.storageType === IProjectItemData_1.ProjectItemStorageType.singleFile) {
            const itemFile = this.primaryFile;
            if (!itemFile) {
                return false;
            }
            if (!itemFile.isContentLoaded) {
                return false;
            }
            if (this.isWorld) {
                if (!itemFile.manager || !(itemFile.manager instanceof MCWorld_1.default)) {
                    return false;
                }
                const world = itemFile.manager;
                return world.isLoaded;
            }
            return this._isFileContentProcessed;
        }
        Log_1.default.unexpectedContentState();
        return false;
    }
    get tags() {
        return this._data.tags;
    }
    async setFile(file) {
        if (file !== this._defaultFile) {
            this._defaultFile = file;
            this._isFileContentProcessed = false;
        }
    }
    get needsSave() {
        if (this._defaultFile === null &&
            this.creationType === IProjectItemData_1.ProjectItemCreationType.generated &&
            this.storageType === IProjectItemData_1.ProjectItemStorageType.singleFile) {
            return true;
        }
        if (this._defaultFile === null) {
            return false;
        }
        let val = this._defaultFile.needsSave;
        if (!val) {
            if (this.isFileContainerStorageItem &&
                this._defaultFile.fileContainerStorage &&
                this._defaultFile.fileContainerStorage instanceof ZipStorage_1.default) {
                val = this._defaultFile.fileContainerStorage.isContentUpdated;
            }
            if (!val) {
                const jsFile = this.getJavaScriptLibTwin();
                if (jsFile !== undefined) {
                    val = jsFile.needsSave;
                }
            }
        }
        return val;
    }
    updateProjectPath() {
        if (this._project && this._project.projectFolder) {
            if (this._defaultFile) {
                this.projectPath = this._defaultFile.getFolderRelativePath(this._project.projectFolder);
            }
            else if (this._defaultFolder) {
                this.projectPath = this._defaultFolder.getFolderRelativePath(this._project.projectFolder);
            }
        }
    }
    async rename(newFileBaseName) {
        if (!this.isContentLoaded) {
            await this.loadContent();
        }
        await this._project.ensureProjectFolder();
        if (this._project.projectFolder === undefined || this._project.projectFolder === null) {
            return;
        }
        if (this._defaultFile !== null) {
            await this._defaultFile.moveTo(this._defaultFile.parentFolder.storageRelativePath + newFileBaseName + "." + this._defaultFile.type);
            this._data.name = newFileBaseName + "." + this._defaultFile.type;
            this.projectPath = this._defaultFile.getFolderRelativePath(this._project.projectFolder);
            this.storageType = IProjectItemData_1.ProjectItemStorageType.singleFile;
        }
        else {
            this._data.name = newFileBaseName;
        }
        this._onPropertyChanged.dispatch(this, "name");
        this._project.notifyProjectItemChanged(this);
    }
    async deleteItem() {
        if (!this.isContentLoaded) {
            await this.loadContent();
        }
        await ProjectItemRelations_1.default.deleteLinksFromParents(this);
        if (this._defaultFile !== null) {
            await this._defaultFile.deleteThisFile();
        }
        this._project.removeItem(this);
    }
    get imageUrl() {
        if (this._imageUrlBase64Cache === null) {
            return undefined;
        }
        if (this._imageUrlBase64Cache) {
            return this._imageUrlBase64Cache;
        }
        if (this.itemType === IProjectItemData_2.ProjectItemType.worldFolder) {
            if (this.defaultFolder) {
                if (this.defaultFolder.manager instanceof MCWorld_1.default) {
                    const world = this.defaultFolder.manager;
                    if (world.isLoaded) {
                        this._imageUrlBase64Cache = "data:image/jpg;base64, " + world.imageBase64;
                        return this._imageUrlBase64Cache;
                    }
                }
            }
        }
        else if (this.isWorld) {
            const itemFile = this.primaryFile;
            if (itemFile) {
                if (itemFile.manager instanceof MCWorld_1.default) {
                    const world = itemFile.manager;
                    if (world.isLoaded) {
                        return "data:image/jpg;base64, " + world.imageBase64;
                    }
                }
            }
        }
        else if (this.projectPath && ProjectItemUtilities_1.default.isImageType(this.itemType)) {
            if (this.projectPath && this.projectPath.endsWith(".tga")) {
                this._imageUrlBase64Cache = null;
            }
            else if (this._defaultFile && this._defaultFile.content && this._defaultFile.content instanceof Uint8Array) {
                if (this._defaultFile.content.length > 10000) {
                    this._imageUrlBase64Cache = null;
                    return undefined;
                }
                this._imageUrlBase64Cache = "data:image/jpg;base64, " + Utilities_1.default.uint8ArrayToBase64(this._defaultFile.content);
                return this._imageUrlBase64Cache;
            }
        }
        return undefined;
    }
    get name() {
        if (this.itemType === IProjectItemData_2.ProjectItemType.worldFolder) {
            if (this.defaultFolder) {
                if (this.defaultFolder.manager instanceof MCWorld_1.default) {
                    const world = this.defaultFolder.manager;
                    if (world.isLoaded) {
                        return world.name;
                    }
                }
            }
        }
        else if (this.itemType === IProjectItemData_2.ProjectItemType.MCWorld || this.itemType === IProjectItemData_2.ProjectItemType.MCTemplate) {
            const itemFile = this.primaryFile;
            if (itemFile) {
                if (itemFile.manager instanceof MCWorld_1.default) {
                    const world = itemFile.manager;
                    if (world.isLoaded) {
                        return world.name;
                    }
                }
            }
        }
        // for certain types of project items, the name of the file is critical
        if (this.projectPath &&
            (this.itemType === IProjectItemData_2.ProjectItemType.js ||
                this.itemType === IProjectItemData_2.ProjectItemType.ts ||
                this.itemType === IProjectItemData_2.ProjectItemType.testJs ||
                this.itemType === IProjectItemData_2.ProjectItemType.structure)) {
            return StorageUtilities_1.default.getLeafName(this.projectPath);
        }
        if (this._data.name !== undefined) {
            return this._data.name;
        }
        if (this.projectPath) {
            return StorageUtilities_1.default.getLeafName(this.projectPath);
        }
        return "untitled";
    }
    async loadFolder() {
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.folder) {
            if (this._defaultFolder === null &&
                this.projectPath !== null &&
                this.projectPath !== undefined &&
                this.projectPath.startsWith("/") &&
                this._project.projectFolder !== null &&
                this._project.projectFolder !== undefined) {
                const prefixPaths = this.projectPath.split("#");
                if (prefixPaths.length > 1) {
                    let folderToLoadFrom = this._project.projectFolder;
                    for (let i = 0; i < prefixPaths.length - 1; i++) {
                        if (folderToLoadFrom) {
                            const zipFile = await folderToLoadFrom.ensureFileFromRelativePath(prefixPaths[i]);
                            if (!zipFile.isContentLoaded) {
                                await zipFile.loadContent();
                            }
                            if (zipFile.content && zipFile.content instanceof Uint8Array) {
                                if (!zipFile.fileContainerStorage) {
                                    const zipStorage = new ZipStorage_1.default();
                                    zipStorage.storagePath = zipFile.storageRelativePath + "#";
                                    await zipStorage.loadFromUint8Array(zipFile.content, zipFile.name);
                                    zipFile.fileContainerStorage = zipStorage;
                                }
                                folderToLoadFrom = zipFile.fileContainerStorage.rootFolder;
                            }
                            else {
                                folderToLoadFrom = undefined;
                            }
                        }
                    }
                    if (folderToLoadFrom) {
                        this._defaultFolder = await folderToLoadFrom.ensureFolderFromRelativePath(prefixPaths[prefixPaths.length - 1]);
                    }
                    else {
                        // Log.debugAlert("Unable to parse a containerized file path of '" + this.storagePath + "'");
                        return null;
                    }
                }
                else {
                    this._defaultFolder = await this._project.projectFolder.ensureFolderFromRelativePath(this.projectPath);
                }
                await this._defaultFolder.load();
                this._onFolderRetrieved.dispatch(this, this._defaultFolder);
                if (this.itemType === IProjectItemData_2.ProjectItemType.worldFolder) {
                    const mcworld = await MCWorld_1.default.ensureMCWorldOnFolder(this._defaultFolder, this._project, this._handleMCWorldLoaded);
                    if (mcworld) {
                        this.errorMessage = mcworld.storageErrorMessage;
                        if (mcworld.storageErrorStatus === IStorage_1.StorageErrorStatus.unprocessable) {
                            this.errorStatus = IProjectItemData_1.ProjectItemErrorStatus.unprocessable;
                        }
                        else {
                            this.errorStatus = IProjectItemData_1.ProjectItemErrorStatus.none;
                        }
                    }
                }
                else {
                    this._fireLoadedEvent();
                }
            }
            return this._defaultFolder;
        }
        return undefined;
    }
    _handleMCWorldLoaded(world, worldA) {
        this._fireLoadedEvent();
    }
    _fireLoadedEvent() {
        if (this._onLoaded && this.isContentLoaded) {
            this._onLoaded.dispatch(this, this);
        }
    }
    async getManager() {
        if (!this.isContentLoaded) {
            await this.loadContent();
        }
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.singleFile && this._defaultFile) {
            return this._defaultFile.manager;
        }
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.folder && this._defaultFolder) {
            return this._defaultFolder.manager;
        }
        return undefined;
    }
    async ensureStorage() {
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.folder) {
            await this.loadFolder();
        }
        else if (this.storageType === IProjectItemData_1.ProjectItemStorageType.singleFile) {
            await this.ensureFileStorage();
        }
    }
    get isStorageEnsured() {
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.folder) {
            return !!this._defaultFolder;
        }
        return !!this.primaryFile;
    }
    async loadContentDirect() {
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.folder) {
            await this.loadFolder();
        }
        else if (this.storageType === IProjectItemData_1.ProjectItemStorageType.singleFile) {
            await this.loadFileContent();
        }
    }
    async ensureFileStorage() {
        if (this.storageType === IProjectItemData_1.ProjectItemStorageType.singleFile &&
            this._defaultFile === null &&
            this.projectPath !== null &&
            this.projectPath !== undefined &&
            this.projectPath.startsWith("/") &&
            this._project.projectFolder !== null &&
            this._project.projectFolder !== undefined) {
            const prefixPaths = this.projectPath.split("#");
            if (prefixPaths.length > 1) {
                let folderToLoadFrom = this._project.projectFolder;
                for (let i = 0; i < prefixPaths.length - 1; i++) {
                    if (folderToLoadFrom) {
                        const zipFile = await folderToLoadFrom.ensureFileFromRelativePath(prefixPaths[i]);
                        if (!zipFile.isContentLoaded) {
                            await zipFile.loadContent();
                        }
                        if (zipFile.content && zipFile.content instanceof Uint8Array) {
                            if (!zipFile.fileContainerStorage) {
                                const zipStorage = new ZipStorage_1.default();
                                zipStorage.storagePath = zipFile.storageRelativePath + "#";
                                await zipStorage.loadFromUint8Array(zipFile.content, zipFile.name);
                                zipFile.fileContainerStorage = zipStorage;
                            }
                            folderToLoadFrom = zipFile.fileContainerStorage.rootFolder;
                        }
                        else {
                            folderToLoadFrom = undefined;
                        }
                    }
                }
                if (folderToLoadFrom) {
                    this._defaultFile = await folderToLoadFrom.ensureFileFromRelativePath(prefixPaths[prefixPaths.length - 1]);
                    this._isFileContentProcessed = false;
                }
                else {
                    Log_1.default.debugAlert("Unable to parse a containerized file path of '" + this.projectPath + "'");
                    return null;
                }
            }
            else {
                this._defaultFile = await this._project.projectFolder.ensureFileFromRelativePath(this.projectPath);
                this._isFileContentProcessed = false;
            }
        }
        return this._defaultFile;
    }
    async loadFileContent() {
        if (this._isFileContentProcessed && this._defaultFile) {
            return this._defaultFile;
        }
        if (!this._defaultFile) {
            await this.ensureFileStorage();
        }
        const variants = this._getVariantList();
        for (const variant of variants) {
            await variant.ensureAndLoadFileStorage();
        }
        if (this._defaultFile) {
            await this.loadFileStorage();
        }
        return this._defaultFile;
    }
    async loadFileStorage() {
        if (!this._isFileContentProcessed && this._defaultFile) {
            if (this._data.creationType === IProjectItemData_1.ProjectItemCreationType.generated) {
                await ProjectAutogeneration_1.default.updateItemAutogeneration(this, true);
            }
            else {
                if (!this._defaultFile.isContentLoaded) {
                    await this._defaultFile.loadContent();
                }
            }
            await ProjectAutogeneration_1.default.updateItemAutogeneratedSideFiles(this);
            this._isFileContentProcessed = true;
            this._onFileRetrieved.dispatch(this, this._defaultFile);
            if (this.itemType === IProjectItemData_2.ProjectItemType.MCWorld || this.itemType === IProjectItemData_2.ProjectItemType.MCTemplate) {
                const mcworld = await MCWorld_1.default.ensureOnFile(this._defaultFile, this._project, this._handleMCWorldLoaded);
                if (mcworld) {
                    this.errorMessage = mcworld.storageErrorMessage;
                    if (mcworld.storageErrorStatus === IStorage_1.StorageErrorStatus.unprocessable) {
                        this.errorStatus = IProjectItemData_1.ProjectItemErrorStatus.unprocessable;
                    }
                    else {
                        this.errorStatus = IProjectItemData_1.ProjectItemErrorStatus.none;
                    }
                }
            }
            else if (this.itemType === IProjectItemData_2.ProjectItemType.entityTypeBehavior) {
                await EntityTypeDefinition_1.default.ensureOnFile(this._defaultFile);
                this._fireLoadedEvent();
            }
            else {
                this._fireLoadedEvent();
            }
        }
    }
    async getJsonObject() {
        let strContent = await this.getStringContent();
        if (!strContent) {
            return undefined;
        }
        let obj = undefined;
        try {
            strContent = Utilities_1.default.fixJsonContent(strContent);
            obj = JSON.parse(strContent);
        }
        catch (e) {
            Log_1.default.debug("Could not parse content '" + strContent + "': " + e, this.project.name);
        }
        return obj;
    }
    async getStringContent() {
        if (!this.isContentLoaded) {
            await this.loadContent();
        }
        const pf = this.primaryFile;
        if (!pf) {
            return undefined;
        }
        if (!pf.isContentLoaded) {
            await pf.loadContent();
        }
        if (pf.content instanceof Uint8Array || pf.content === null) {
            return undefined;
        }
        return pf.content;
    }
    async getContentAsJson() {
        const file = await this.loadFileContent();
        return file && (await StorageUtilities_1.default.getJsonObject(file));
    }
    async loadContent() {
        if (this.isContentLoaded) {
            return true;
        }
        if (this._isLoading) {
            const pendingLoad = this._pendingLoadRequests;
            const prom = (resolve, reject) => {
                pendingLoad.push(resolve);
            };
            await new Promise(prom);
            return true;
        }
        else {
            this._isLoading = true;
            await this.loadContentDirect();
            this._isLoading = false;
            const pendingLoad = this._pendingLoadRequests;
            this._pendingLoadRequests = [];
            for (const prom of pendingLoad) {
                prom(undefined);
            }
            return true;
        }
    }
    async prepareToSave() {
        if (!this.isContentLoaded) {
            await this.loadContent();
        }
        await ProjectAutogeneration_1.default.updateItemAutogeneration(this);
        await ProjectAutogeneration_1.default.updateItemAutogeneratedSideFiles(this);
        if (!this.isInFileContainer &&
            this.isFileContainerStorageItem &&
            this.primaryFile &&
            this.primaryFile.fileContainerStorage &&
            this.primaryFile.fileContainerStorage instanceof ZipStorage_1.default) {
            const zs = this.primaryFile.fileContainerStorage;
            if (zs.isContentUpdated && (zs.errorStatus === undefined || zs.errorStatus === IStorage_1.StorageErrorStatus.none)) {
                const op = await this._project.carto.notifyOperationStarted("Zipping file '" + this.primaryFile.storageRelativePath + "'...");
                const bytes = await zs.generateUint8ArrayAsync();
                await this._project.carto.notifyOperationEnded(op, "Done zipping file '" + this.primaryFile.storageRelativePath + "'.");
                this.primaryFile.setContent(bytes);
            }
        }
    }
    getJavaScriptLibTwin() {
        if (!this._defaultFile) {
            return undefined;
        }
        if (this.itemType === IProjectItemData_2.ProjectItemType.ts) {
            const libScriptsFolder = this.project.getLibScriptsFolder();
            if (!libScriptsFolder) {
                return undefined;
            }
            const jsTwinName = StorageUtilities_1.default.canonicalizeName(StorageUtilities_1.default.getBaseFromName(this._defaultFile.name) + ".js");
            return libScriptsFolder.ensureFile(jsTwinName);
        }
        return undefined;
    }
    getFunctionTwin() {
        if (!this._defaultFile) {
            return undefined;
        }
        if (this.itemType === IProjectItemData_2.ProjectItemType.actionSet) {
            const functionTwinName = StorageUtilities_1.default.canonicalizeName(StorageUtilities_1.default.getBaseFromName(this._defaultFile.name) + ".mcfunction");
            let functionFolder = this._defaultFile.parentFolder;
            if (functionFolder.name === "scripts" && functionFolder.parentFolder) {
                functionFolder = functionFolder.parentFolder.ensureFolder("functions");
            }
            return functionFolder.files[functionTwinName];
        }
        return undefined;
    }
    async saveContent() {
        if (this._defaultFile) {
            await this._defaultFile.saveContent();
            // these next two are associated with action set
            const jsFile = this.getJavaScriptLibTwin();
            if (jsFile !== undefined && jsFile.needsSave) {
                await jsFile.saveContent();
            }
            const functionFile = this.getFunctionTwin();
            if (functionFile !== undefined && functionFile.needsSave) {
                await functionFile.saveContent();
            }
        }
    }
    hasTag(name) {
        return this.tags.includes(name);
    }
    ensureTag(name) {
        if (this.hasTag(name)) {
            return;
        }
        this.tags.push(name);
    }
}
exports.default = ProjectItem;

//# sourceMappingURL=../maps/app/ProjectItem.js.map
