"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectMetaCategory = exports.NewItemTypeAddMode = exports.NewEntityTypeAddMode = void 0;
const StorageUtilities_1 = require("../storage/StorageUtilities");
const MinecraftUtilities_1 = require("../minecraft/MinecraftUtilities");
const Project_1 = require("./Project");
const IProjectItemData_1 = require("./IProjectItemData");
const Database_1 = require("../minecraft/Database");
const Log_1 = require("../core/Log");
const Utilities_1 = require("../core/Utilities");
const IProjectData_1 = require("./IProjectData");
const BehaviorManifestDefinition_1 = require("../minecraft/BehaviorManifestDefinition");
const NpmPackageDefinition_1 = require("../devproject/NpmPackageDefinition");
const ResourceManifestDefinition_1 = require("../minecraft/ResourceManifestDefinition");
const ProjectItemUtilities_1 = require("./ProjectItemUtilities");
const Pack_1 = require("../minecraft/Pack");
const BlockTypeDefinition_1 = require("../minecraft/BlockTypeDefinition");
const ProjectUpdateRunner_1 = require("../updates/ProjectUpdateRunner");
const ProjectStandard_1 = require("./ProjectStandard");
const ProjectAutogeneration_1 = require("./ProjectAutogeneration");
const TypeScriptDefinition_1 = require("../minecraft/TypeScriptDefinition");
const Constants_1 = require("../core/Constants");
const ProjectContent_1 = require("./ProjectContent");
var NewEntityTypeAddMode;
(function (NewEntityTypeAddMode) {
    NewEntityTypeAddMode[NewEntityTypeAddMode["baseId"] = 0] = "baseId";
})(NewEntityTypeAddMode = exports.NewEntityTypeAddMode || (exports.NewEntityTypeAddMode = {}));
var NewItemTypeAddMode;
(function (NewItemTypeAddMode) {
    NewItemTypeAddMode[NewItemTypeAddMode["baseId"] = 0] = "baseId";
})(NewItemTypeAddMode = exports.NewItemTypeAddMode || (exports.NewItemTypeAddMode = {}));
var ProjectMetaCategory;
(function (ProjectMetaCategory) {
    ProjectMetaCategory[ProjectMetaCategory["mix"] = 0] = "mix";
    ProjectMetaCategory[ProjectMetaCategory["worldTemplate"] = 1] = "worldTemplate";
    ProjectMetaCategory[ProjectMetaCategory["texturePack"] = 2] = "texturePack";
    ProjectMetaCategory[ProjectMetaCategory["addOn"] = 3] = "addOn";
    ProjectMetaCategory[ProjectMetaCategory["skinPack"] = 4] = "skinPack";
    ProjectMetaCategory[ProjectMetaCategory["persona"] = 5] = "persona";
})(ProjectMetaCategory = exports.ProjectMetaCategory || (exports.ProjectMetaCategory = {}));
class ProjectUtilities {
    static async ensureContentInDefaultScriptFile(project, signatureToken, content, placeAtBottom) {
        const defaultScriptFile = await project.getDefaultScriptsFile();
        if (defaultScriptFile) {
            if (!defaultScriptFile.isContentLoaded) {
                await defaultScriptFile.loadContent();
            }
            if (typeof defaultScriptFile.content === "string" && defaultScriptFile.content.length > 0) {
                if (defaultScriptFile.content.indexOf(signatureToken) < 0) {
                    let newContent = defaultScriptFile.content;
                    if (!placeAtBottom) {
                        newContent = content + newContent;
                    }
                    else {
                        newContent = newContent + content;
                    }
                    defaultScriptFile.setContent(newContent);
                    await defaultScriptFile.saveContent();
                }
            }
        }
    }
    static async getDefaultFolderForPack(project, packType) {
        if (packType === Pack_1.PackType.behavior) {
            return await project.getDefaultBehaviorPackFolder();
        }
        else if (packType === Pack_1.PackType.resource) {
            return await project.getDefaultResourcePackFolder();
        }
        else if (packType === Pack_1.PackType.skin) {
            return await project.getDefaultSkinPackFolder();
        }
        else if (packType === Pack_1.PackType.design) {
            return await project.getDefaultSkinPackFolder();
        }
        throw new Error();
    }
    static getPackTypeName(packType) {
        switch (packType) {
            case Pack_1.PackType.behavior:
                return "Behavior";
            case Pack_1.PackType.resource:
                return "Resource";
            case Pack_1.PackType.skin:
                return "Skin";
            default:
                return "Unknown";
        }
    }
    static async ensureJsonItem(project, jsonContent, fileName) {
        if (!project.projectFolder) {
            return undefined;
        }
        const typeInfo = ProjectItemUtilities_1.default.inferTypeFromJsonContent(jsonContent, fileName);
        let packType = typeInfo.packType;
        if (packType === undefined) {
            packType = Pack_1.PackType.behavior;
        }
        const baseFolder = await ProjectItemUtilities_1.default.getDefaultFolderForType(project, typeInfo.itemType);
        if (!baseFolder) {
            return undefined;
        }
        let folderPath = baseFolder.getFolderRelativePath(project.projectFolder);
        if (folderPath === undefined) {
            return undefined;
        }
        fileName = StorageUtilities_1.default.getUniqueChildFolderName(fileName, baseFolder);
        const contentFile = baseFolder.ensureFile(fileName);
        contentFile.setContent(jsonContent);
        contentFile.saveContent();
        const relPath = contentFile.getFolderRelativePath(project.projectFolder);
        if (relPath !== undefined) {
            return project.ensureItemByProjectPath(relPath, IProjectItemData_1.ProjectItemStorageType.singleFile, fileName, typeInfo.itemType, Project_1.FolderContext.unknown, undefined, IProjectItemData_1.ProjectItemCreationType.normal);
        }
        return undefined;
    }
    static getItemsFromSearch(project, searchResults) {
        if (searchResults === undefined) {
            return [];
        }
        const searchItems = [];
        for (const val of searchResults) {
            for (const item of project.items) {
                if (item.projectPath && val.value === item.projectPath) {
                    searchItems.push(item);
                }
            }
        }
        return searchItems;
    }
    static getItemFromAnnotatedValue(project, value) {
        for (const item of project.items) {
            if (item.projectPath === value.value) {
                return item;
            }
        }
        return undefined;
    }
    static async isVibrantVisualsCompatible(project) {
        for (const item of project.items) {
            await item.loadFileContent();
            if (item.primaryFile) {
                const manifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(item.primaryFile);
                if (manifestJson && manifestJson.capabilities && manifestJson.capabilities.includes("pbr")) {
                    return true;
                }
            }
        }
        return false;
    }
    static isVibrantVisualsEnhanced(project) {
        for (const item of project.items) {
            if (ProjectItemUtilities_1.default.isVibrantVisualsRelated(item)) {
                return true;
            }
        }
        return false;
    }
    static async ensureDefaultItems(project) {
        if (project.focus === IProjectData_1.ProjectFocus.gameTests && project.projectFolder !== null) {
            const bpFolder = await project.ensureDefaultBehaviorPackFolder();
            const defaultPath = bpFolder.getFolderRelativePath(project.projectFolder);
            let pi = project.ensureItemByTag("gametestjs", "Test", IProjectItemData_1.ProjectItemType.testJs, defaultPath + "scripts/test.js", IProjectItemData_1.ProjectItemStorageType.singleFile);
            let file = await pi.loadFileContent();
            if (file !== null) {
                let content = "";
                if (project.preferredScriptLanguage === IProjectData_1.ProjectScriptLanguage.typeScript) {
                    content = ProjectContent_1.default.getDefaultTestTypeScript(this.name, StorageUtilities_1.default.getBaseFromName("test"));
                }
                else {
                    content = ProjectContent_1.default.getDefaultTestJavaScript(this.name, StorageUtilities_1.default.getBaseFromName("test"));
                }
                file.setContent(content);
            }
            await project.ensureJsIndexFile();
            pi = project.ensureItemByTag("manifestjson", "manifest", IProjectItemData_1.ProjectItemType.behaviorPackManifestJson, defaultPath + "manifest.json", IProjectItemData_1.ProjectItemStorageType.singleFile, IProjectItemData_1.ProjectItemCreationType.generated);
            pi = project.ensureItemByTag("gameteststructure", "Basic", IProjectItemData_1.ProjectItemType.structure, defaultPath + "structures/gametests/basic.mcstructure", IProjectItemData_1.ProjectItemStorageType.singleFile);
            file = await pi.loadFileContent();
            if (file !== null) {
                const result = ProjectContent_1.default.generateDefaultStructure();
                if (result !== undefined) {
                    file.setContent(result);
                }
            }
        }
    }
    static hasEntities(project) {
        const projectItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.entityTypeBehavior);
        if (projectItems.length > 0) {
            return true;
        }
        const projectItemsResource = project.getItemsByType(IProjectItemData_1.ProjectItemType.entityTypeResource);
        if (projectItemsResource.length > 0) {
            return true;
        }
        return false;
    }
    static hasBlocks(project) {
        const projectItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.blockTypeBehavior);
        if (projectItems.length > 0) {
            return true;
        }
        return false;
    }
    static hasItems(project) {
        const projectItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.itemTypeBehavior);
        if (projectItems.length > 0) {
            return true;
        }
        return false;
    }
    static async hasDocumentationMetadata(folder, depth) {
        await folder.load();
        for (const folderName in folder.folders) {
            if (folderName === "checkpoint_input" ||
                folderName === "metadata" ||
                folderName === "type_definitions" ||
                folderName === "typedefs") {
                return true;
            }
            if (depth === undefined || depth < 5) {
                const isMetadata = await ProjectUtilities.hasDocumentationMetadata(folder, depth ? depth + 1 : 1);
                if (isMetadata) {
                    return true;
                }
            }
        }
        return false;
    }
    static async prepareProjectForDocumentation(project) {
        await project.ensureProjectFolder();
        if (!project.projectFolder) {
            return;
        }
        const hasMetadata = await ProjectUtilities.hasDocumentationMetadata(project.projectFolder);
        if (hasMetadata) {
            return;
        }
        const result = await Database_1.default.loadPreviewMetadataFolder();
        if (result) {
            project.accessoryFolders = [result];
        }
    }
    static async getBaseBehaviorPackPath(project) {
        const bpFolder = await project.ensureDefaultBehaviorPackFolder();
        if (project.projectFolder === null) {
            return undefined;
        }
        const defaultPath = bpFolder.getFolderRelativePath(project.projectFolder);
        return defaultPath;
    }
    static async getBaseResourcePackPath(project) {
        const rpFolder = await project.ensureDefaultResourcePackFolder();
        if (project.projectFolder === null) {
            return undefined;
        }
        const defaultPath = rpFolder.getFolderRelativePath(project.projectFolder);
        return defaultPath;
    }
    static async applyScriptEntryPoint(project, newScriptEntryPoint) {
        project.scriptEntryPoint = newScriptEntryPoint;
        if (project.editPreference === IProjectData_1.ProjectEditPreference.summarized && project.defaultBehaviorPackUniqueId) {
            const itemsCopy = project.getItemsCopy();
            for (const projectItem of itemsCopy) {
                if (projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const manifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (manifestJson &&
                            manifestJson.definition &&
                            Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, project.defaultBehaviorPackUniqueId)) {
                            const sm = manifestJson.ensureScriptModule(project.title, project.description);
                            sm.entry = project.scriptEntryPoint;
                            manifestJson.save();
                        }
                    }
                }
            }
        }
    }
    static async applyDescription(project, newDescription) {
        project.description = newDescription;
        if (project.editPreference === IProjectData_1.ProjectEditPreference.summarized && project.defaultBehaviorPackUniqueId) {
            const itemsCopy = project.getItemsCopy();
            for (const projectItem of itemsCopy) {
                if (projectItem.itemType === IProjectItemData_1.ProjectItemType.packageJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const npmPackageJson = await NpmPackageDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (npmPackageJson && npmPackageJson.definition) {
                            npmPackageJson.definition.description = newDescription;
                            await npmPackageJson.save();
                        }
                    }
                }
                else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const manifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (manifestJson &&
                            manifestJson.definition &&
                            Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, project.defaultBehaviorPackUniqueId)) {
                            const header = manifestJson.ensureHeader(project.title, project.description);
                            header.description = newDescription;
                            await manifestJson.save();
                        }
                    }
                }
                else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const manifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (manifestJson &&
                            manifestJson.definition &&
                            Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, project.defaultResourcePackUniqueId)) {
                            const header = manifestJson.ensureHeader(project.title, project.description);
                            header.description = newDescription;
                            await manifestJson.save();
                        }
                    }
                }
            }
        }
    }
    static async applyCreator(project, newCreator) {
        project.creator = newCreator;
    }
    static async applyShortName(project, newShortName) {
        project.shortName = newShortName;
    }
    static async ensureGeneratedWith(project, isToolWeb) {
        const appName = isToolWeb ? "mctoolsweb" : "mctoolscli";
        if (project.editPreference === IProjectData_1.ProjectEditPreference.summarized && project.defaultBehaviorPackUniqueId) {
            const itemsCopy = project.getItemsCopy();
            for (const projectItem of itemsCopy) {
                if (projectItem.primaryFile && projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    const bpManifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                    if (bpManifestJson && bpManifestJson.definition) {
                        bpManifestJson.ensureGeneratedWith(appName, Constants_1.constants.version);
                        await bpManifestJson.save();
                    }
                }
                else if (projectItem.primaryFile && projectItem.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    const rpManifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                    if (rpManifestJson && rpManifestJson.definition) {
                        rpManifestJson.ensureGeneratedWith(appName, Constants_1.constants.version);
                        await rpManifestJson.save();
                    }
                }
            }
        }
    }
    static async applyTitle(project, newTitle) {
        project.title = newTitle;
        if (project.editPreference === IProjectData_1.ProjectEditPreference.summarized && project.defaultBehaviorPackUniqueId) {
            const itemsCopy = project.getItemsCopy();
            for (const projectItem of itemsCopy) {
                if (projectItem.primaryFile && projectItem.itemType === IProjectItemData_1.ProjectItemType.packageJson) {
                    const npmPackageJson = await NpmPackageDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                    if (npmPackageJson && npmPackageJson.definition) {
                        npmPackageJson.definition.name = newTitle;
                        await npmPackageJson.save();
                    }
                }
                else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const manifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (manifestJson &&
                            manifestJson.definition &&
                            Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, project.defaultBehaviorPackUniqueId)) {
                            const header = manifestJson.ensureHeader(project.title, project.description);
                            header.name = newTitle;
                            await manifestJson.save();
                        }
                    }
                }
                else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const manifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (manifestJson &&
                            manifestJson.definition &&
                            Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, project.defaultResourcePackUniqueId)) {
                            const header = manifestJson.ensureHeader(project.title, project.description);
                            header.name = newTitle;
                            await manifestJson.save();
                        }
                    }
                }
            }
        }
    }
    static async applyBehaviorPackUniqueId(project, newBehaviorPackId) {
        const oldBehaviorPackId = project.defaultBehaviorPackUniqueId;
        await project.setDefaultBehaviorPackUniqueIdAndUpdateDependencies(newBehaviorPackId);
        if (project.editPreference === IProjectData_1.ProjectEditPreference.summarized && project.defaultBehaviorPackUniqueId) {
            let bpackCount = 0;
            const itemsCopy = project.getItemsCopy();
            for (const projectItem of itemsCopy) {
                if (projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    bpackCount++;
                }
            }
            for (const projectItem of itemsCopy) {
                if (projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const manifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (manifestJson &&
                            manifestJson.definition &&
                            (bpackCount <= 1 ||
                                Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, project.defaultBehaviorPackUniqueId) ||
                                Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, oldBehaviorPackId))) {
                            const header = manifestJson.ensureHeader(project.title, project.description);
                            header.uuid = newBehaviorPackId;
                            manifestJson.save();
                        }
                    }
                }
            }
        }
    }
    static async applyResourcePackUniqueId(project, newResourcePackId) {
        const oldResourcePackId = project.defaultResourcePackUniqueId;
        await project.setDefaultResourcePackUniqueIdAndUpdateDependencies(newResourcePackId);
        if (project.editPreference === IProjectData_1.ProjectEditPreference.summarized && project.defaultResourcePackUniqueId) {
            let rpackCount = 0;
            const itemsCopy = project.getItemsCopy();
            for (const projectItem of itemsCopy) {
                if (projectItem.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    rpackCount++;
                }
            }
            for (const projectItem of itemsCopy) {
                if (projectItem.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    await projectItem.loadFileContent();
                    if (projectItem.primaryFile) {
                        const manifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                        if (manifestJson &&
                            manifestJson.definition &&
                            (rpackCount <= 1 ||
                                Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, project.defaultResourcePackUniqueId) ||
                                Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, oldResourcePackId))) {
                            const header = manifestJson.ensureHeader(project.title, project.description);
                            header.uuid = newResourcePackId;
                            manifestJson.save();
                        }
                    }
                }
            }
        }
    }
    static getSuggestedProjectShortName(creator, name) {
        return this.getSuggestedShortName(creator) + "_" + this.getSuggestedShortName(name);
    }
    static getSuggestedShortName(caption) {
        caption = caption.trim().replace(/-/g, "");
        caption = caption.replace(/_/g, "");
        caption = caption.replace(/ /g, "");
        caption = caption.replace(/:/g, "");
        caption = caption.replace(/;/g, "");
        caption = caption.replace(/=/g, "");
        let capitalStr = "";
        for (let i = 0; i < caption.length; i++) {
            if (caption[i] >= "A" && caption[i] <= "Z") {
                capitalStr += caption[i].toLowerCase();
            }
        }
        if (capitalStr.length > 1) {
            return capitalStr;
        }
        if (caption.length <= 4) {
            return caption.toLowerCase();
        }
        return caption.substring(0, 4).toLowerCase();
    }
    static getSuggestedProjectName(project) {
        return this.getSuggestedProjectNameFromElements(project.id, project.gitHubFolder, project.gitHubRepoName);
    }
    static getSuggestedProjectNameFromElements(id, gitHubFolder, gitHubRepoName) {
        let projName = "my";
        if (id) {
            projName += id;
        }
        else if (gitHubFolder !== undefined) {
            projName += gitHubFolder;
            projName = projName.replace(" behavior_packs", "");
        }
        else {
            projName += gitHubRepoName;
        }
        projName = projName.replace(/_/gi, "");
        projName = projName.replace(/\//gi, "");
        projName = projName.replace(/\\/gi, "");
        projName = projName.replace(/ /gi, "");
        return projName;
    }
    static async getBaseScriptsPath(project) {
        const scriptsFolder = await project.ensureDefaultScriptsFolder();
        if (project.projectFolder === null) {
            return undefined;
        }
        return scriptsFolder.getFolderRelativePath(project.projectFolder);
    }
    static async renameDefaultFolders(project, newTokenName) {
        const bpFolder = await project.getDefaultBehaviorPackFolder(true);
        const rpFolder = await project.getDefaultResourcePackFolder(true);
        newTokenName = MinecraftUtilities_1.default.makeNameFolderSafe(newTokenName);
        if (bpFolder) {
            try {
                await bpFolder.rename(newTokenName);
            }
            catch (e) {
                // perhaps folder could not be renamed because a folder exists; continue in this case.
                Log_1.default.error(e.toString());
            }
        }
        if (rpFolder) {
            try {
                await rpFolder.rename(newTokenName);
            }
            catch (e) {
                // perhaps folder could not be renamed because a folder exists; continue in this case.
                Log_1.default.error(e.toString());
            }
        }
    }
    static async processNewProject(project, title, description, suggestedShortName, isWeb) {
        await project.inferProjectItemsFromFiles();
        if (suggestedShortName) {
            await ProjectUtilities.renameDefaultFolders(project, suggestedShortName);
        }
        await ProjectAutogeneration_1.default.updateProjectAutogeneration(project, true);
        await ProjectUtilities.randomizeAllUids(project);
        await ProjectUtilities.applyTitle(project, title);
        await ProjectUtilities.applyDescription(project, description);
        await ProjectUtilities.ensureGeneratedWith(project, isWeb);
        await ProjectStandard_1.default.ensureIsStandard(project);
        const pur = new ProjectUpdateRunner_1.default(project);
        await pur.updateProject();
        await project.save(true);
    }
    static async setNewModuleId(project, newModuleId, oldModuleId) {
        const itemsCopy = project.getItemsCopy();
        let setResourcePack = false;
        for (let i = 0; i < itemsCopy.length; i++) {
            const pi = itemsCopy[i];
            if (pi.primaryFile) {
                if (pi.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson && !setResourcePack) {
                    const rpManifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (rpManifestJson) {
                        if (rpManifestJson.definition && rpManifestJson.definition.modules) {
                            const mods = rpManifestJson.definition.modules;
                            for (const mod of mods) {
                                if (mod.uuid === oldModuleId) {
                                    mod.uuid = newModuleId;
                                }
                            }
                        }
                    }
                }
                else if (pi.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    const bpManifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (bpManifestJson) {
                        if (bpManifestJson.definition && bpManifestJson.definition.modules) {
                            const mods = bpManifestJson.definition.modules;
                            for (const mod of mods) {
                                if (mod.uuid === oldModuleId) {
                                    mod.uuid = newModuleId;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    static async getDefaultBehaviorPackFolder(project, paths) {
        const bpFolder = await project.getDefaultBehaviorPackFolder();
        if (!bpFolder) {
            return undefined;
        }
        const srFolder = await bpFolder.ensureFolderFromRelativePath(paths.join("/"));
        await srFolder.ensureExists();
        return srFolder;
    }
    static async getIsAddon(project) {
        const itemsCopy = project.getItemsCopy();
        let rpCount = 0;
        let bpCount = 0;
        for (let i = 0; i < itemsCopy.length; i++) {
            const pi = itemsCopy[i];
            if (pi.primaryFile) {
                if (pi.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    rpCount++;
                    const rpManifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (rpManifestJson) {
                        if (!rpManifestJson.hasAddonProperties()) {
                            return false;
                        }
                    }
                }
                else if (pi.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    bpCount++;
                    const bpManifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (bpManifestJson) {
                        if (!bpManifestJson.hasAddonProperties()) {
                            return false;
                        }
                    }
                }
            }
        }
        return bpCount === 1 && rpCount === 1;
    }
    static async getMetaCategory(project) {
        const itemsCopy = project.getItemsCopy();
        let rpCount = 0;
        let bpCount = 0;
        let spCount = 0;
        let personaCount = 0;
        let worldTemplateCount = 0;
        let hasPacksWithAddOnProperties = false;
        let hasPacksWithoutAddOnProperties = false;
        for (let i = 0; i < itemsCopy.length; i++) {
            const pi = itemsCopy[i];
            if (!pi.primaryFile) {
                continue;
            }
            if (pi.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                rpCount++;
                const rpManifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                if (rpManifestJson) {
                    let hasAddonProperties = rpManifestJson.hasAddonProperties();
                    if (hasAddonProperties) {
                        hasPacksWithAddOnProperties = true;
                    }
                    else {
                        hasPacksWithoutAddOnProperties = true;
                    }
                }
            }
            else if (pi.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                bpCount++;
                const bpManifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                if (bpManifestJson) {
                    let hasAddonProperties = bpManifestJson.hasAddonProperties();
                    if (hasAddonProperties) {
                        hasPacksWithAddOnProperties = true;
                    }
                    else {
                        hasPacksWithoutAddOnProperties = true;
                    }
                }
            }
            else if (pi.itemType === IProjectItemData_1.ProjectItemType.skinPackManifestJson) {
                spCount++;
            }
            else if (pi.itemType === IProjectItemData_1.ProjectItemType.personaManifestJson) {
                personaCount++;
            }
            else if (pi.itemType === IProjectItemData_1.ProjectItemType.worldTemplateManifestJson) {
                worldTemplateCount++;
            }
        }
        if (personaCount > 0) {
            return ProjectMetaCategory.persona;
        }
        if (worldTemplateCount > 0) {
            return ProjectMetaCategory.worldTemplate;
        }
        if (bpCount === 1 &&
            rpCount === 1 &&
            spCount === 0 &&
            !hasPacksWithoutAddOnProperties &&
            hasPacksWithAddOnProperties) {
            return ProjectMetaCategory.addOn;
        }
        if (bpCount === 0 && rpCount >= 1 && !hasPacksWithAddOnProperties) {
            return ProjectMetaCategory.texturePack;
        }
        if (spCount >= 0) {
            return ProjectMetaCategory.skinPack;
        }
        return ProjectMetaCategory.mix;
    }
    static getMetaCategoryDescription(category) {
        switch (category) {
            case ProjectMetaCategory.addOn:
                return "Add-On";
            case ProjectMetaCategory.worldTemplate:
                return "World Template";
            case ProjectMetaCategory.texturePack:
                return "Texture Pack";
            case ProjectMetaCategory.skinPack:
                return "Skin Pack";
            case ProjectMetaCategory.persona:
                return "Persona";
            default:
                return "Mix";
        }
    }
    static async setIsAddon(project) {
        const itemsCopy = project.getItemsCopy();
        for (let i = 0; i < itemsCopy.length; i++) {
            const pi = itemsCopy[i];
            if (pi.primaryFile) {
                if (pi.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    const rpManifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (rpManifestJson) {
                        rpManifestJson.setAddonProperties();
                    }
                }
                else if (pi.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    const bpManifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (bpManifestJson) {
                        bpManifestJson.setAddonProperties();
                    }
                }
            }
        }
    }
    static async randomizeAllUids(project) {
        const oldUids = {};
        oldUids["defaultBehaviorPack"] = project.defaultBehaviorPackUniqueId;
        oldUids["defaultResourcePack"] = project.defaultResourcePackUniqueId;
        oldUids["defaultDataPack"] = project.defaultDataUniqueId;
        oldUids["defaultScriptModulePack"] = project.defaultScriptModuleUniqueId;
        await project.setDefaultResourcePackUniqueIdAndUpdateDependencies(Utilities_1.default.createUuid());
        await project.setDefaultBehaviorPackUniqueIdAndUpdateDependencies(Utilities_1.default.createUuid());
        project.defaultDataUniqueId = Utilities_1.default.createUuid();
        project.defaultScriptModuleUniqueId = Utilities_1.default.createUuid();
        const itemsCopy = project.getItemsCopy();
        for (let i = 0; i < itemsCopy.length; i++) {
            const pi = itemsCopy[i];
            if (pi.primaryFile) {
                if (pi.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) {
                    const bpManifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (bpManifestJson) {
                        bpManifestJson.randomizeModuleUuids(project.defaultScriptModuleUniqueId, oldUids["defaultScriptModulePack"]);
                        if (bpManifestJson.id !== oldUids["defaultBehaviorPack"] &&
                            bpManifestJson.id !== project.defaultBehaviorPackUniqueId) {
                            await bpManifestJson.setUuid(Utilities_1.default.createUuid(), project);
                        }
                    }
                }
                else if (pi.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) {
                    const rpManifestJson = await ResourceManifestDefinition_1.default.ensureOnFile(pi.primaryFile);
                    if (rpManifestJson) {
                        rpManifestJson.randomizeModuleUuids(project.defaultDataUniqueId, oldUids["defaultDataModulePack"]);
                        if (rpManifestJson.id !== oldUids["defaultResourcePack"] &&
                            rpManifestJson.id !== project.defaultResourcePackUniqueId) {
                            await rpManifestJson.setUuid(Utilities_1.default.createUuid(), project);
                        }
                    }
                }
            }
        }
        await project.save();
    }
    static sanitizeProjectName(name) {
        const lastDash = name.lastIndexOf("-");
        // this is the token format of Electron Storage - remove the random token at the end
        if (lastDash === name.length - 6) {
            name = name.substring(0, name.length - 6);
        }
        return name;
    }
    static CodeReplaceTokens = ["say Hello", 'sendMessage("Hello world'];
    static ImportTypes = {
        vanilla: [
            "MinecraftDimensionTypes",
            "MinecraftBlockTypes",
            "MinecraftItemTypes",
            "MinecraftEntityTypes",
            "MinecraftEffectTypes",
            "MinecraftEnchantmentTypes",
            "MinecraftBiomeTypes",
            "MinecraftFeatureTypes",
            "MinecraftPotionEffectTypes",
            "MinecraftPotionLiquidTypes",
            "MinecraftPotionModifierTypes",
            "MinecraftCooldownCategoryTypes",
        ],
        math: ["Vector3Utils"],
        mcui: [
            "MessageFormResponse",
            "MessageFormData",
            "ActionFormData",
            "ActionFormResponse",
            "ModalFormData",
            "ModalFormResponse",
        ],
        mc: [
            "system",
            "BlockPermutation",
            "BlockSignComponent",
            "CompoundBlockVolume",
            "SignSide",
            "DyeColor",
            "ItemDurabilityComponent",
            "RawMessage",
            "RawText",
            "EntityProjectileComponent",
            "EntityQueryOptions",
            "ButtonPushAfterEvent",
            "ItemStack",
            "MolangVariableMap",
            "EntityInventoryComponent",
            "BlockInventoryComponent",
            "Enchantment",
            "ItemEnchantsComponent",
            "EntityHealthComponent",
            "EntityOnFireComponent",
            "EntityEquippableComponent",
            "EquipmentSlot",
            "EntityItemComponent",
            "EntitySpawnAfterEvent",
            "PistonActivateBeforeEvent",
            "PistonActivateAfterEvent",
            "MusicOptions",
            "WorldSoundOptions",
            "PlayerSoundOptions",
            "DisplaySlotId",
            "ObjectiveSortOrder",
            "TripWireTripAfterEvent",
            "BlockComponentTypes",
            "EntityComponentTypes",
            "ItemComponentTypes",
            "LeverActionAfterEvent",
            "Vector3",
        ],
        mced: [
            "IPlayerUISession",
            "ExtensionContext",
            "IModalToolContainer",
            "registerEditorExtension",
            "ActionManager",
            "IModalTool",
            "ActionTypes",
            "MouseProps",
            "MouseActionType",
            "MouseInputType",
            "KeyboardKey",
            "InputModifier",
            "EditorInputContext",
            "IPropertyPane",
        ],
    };
    static getTopicUrl(topic) {
        const tokens = topic.split(".");
        if (tokens.length < 1) {
            return undefined;
        }
        if (this.ImportTypes.mc.includes(tokens[0]) ||
            tokens[0] === "World" ||
            tokens[0] === "System" ||
            tokens[0] === "Dimension") {
            return ("https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server/" +
                topic.toLowerCase().replace(".", "#"));
        }
        if (this.ImportTypes.mcui.includes(tokens[0])) {
            return ("https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server-ui/" +
                topic.toLowerCase().replace(".", "#"));
        }
        if (this.ImportTypes.mced.includes(tokens[0])) {
            return ("https://learn.microsoft.com/minecraft/creator/scriptapi/minecraft/server-editor/" +
                topic.toLowerCase().replace(".", "#"));
        }
        return undefined;
    }
    static adaptFullSample(content) {
        const registerFunction = content.indexOf("export function register");
        if (registerFunction >= 0) {
            let nextParen = content.indexOf("Extension(", registerFunction);
            if (nextParen > registerFunction) {
                content = content.substring(0, registerFunction + 24) + content.substring(nextParen);
            }
        }
        return content;
    }
    static adaptSample(sampleContent, fileContent) {
        if (sampleContent.indexOf(" mc.") >= 0 && fileContent.indexOf(" as mc") <= 0) {
            sampleContent = sampleContent.replace(/mc./gi, "");
        }
        if (sampleContent.indexOf(" mcui.") >= 0 && fileContent.indexOf(" as mcui") <= 0) {
            sampleContent = sampleContent.replace(/mcui./gi, "");
        }
        return sampleContent;
    }
    static modifyImports(fileContent) {
        let startOfCode = fileContent.indexOf("(");
        let nextStartOfCode = fileContent.indexOf("function");
        if (nextStartOfCode >= 0 && nextStartOfCode < startOfCode) {
            startOfCode = nextStartOfCode;
        }
        nextStartOfCode = fileContent.indexOf("class");
        if (nextStartOfCode >= 0 && nextStartOfCode < startOfCode) {
            startOfCode = nextStartOfCode;
        }
        const previousNewLine = fileContent.lastIndexOf("\n", startOfCode);
        if (previousNewLine >= 0) {
            startOfCode = previousNewLine;
        }
        if (startOfCode > 0) {
            let introContent = fileContent.substring(0, startOfCode);
            const restOfContent = fileContent.substring(startOfCode);
            introContent = ProjectUtilities.ensureImportLines(introContent, restOfContent, "@minecraft/server", this.ImportTypes.mc);
            introContent = ProjectUtilities.ensureImportLines(introContent, restOfContent, "@minecraft/server-ui", this.ImportTypes.mcui);
            introContent = ProjectUtilities.ensureImportLines(introContent, restOfContent, "@minecraft/vanilla-data", this.ImportTypes.vanilla);
            introContent = ProjectUtilities.ensureImportLines(introContent, restOfContent, "@minecraft/math", this.ImportTypes.math);
            fileContent = introContent + restOfContent;
        }
        return fileContent;
    }
    static ensureImportLines(introSection, restOfContent, moduleName, importCollection) {
        for (const importType of importCollection) {
            if (restOfContent.indexOf(importType) >= 0) {
                let importLineIndex = introSection.indexOf('from "' + moduleName + '";');
                if (importLineIndex < 0) {
                    introSection = 'import {} from "' + moduleName + '";\n' + introSection;
                    importLineIndex = 10;
                }
                let previousNewLine = introSection.lastIndexOf("\n", importLineIndex);
                if (previousNewLine < 0) {
                    previousNewLine = 0;
                }
                let endNewLine = introSection.indexOf("\n", importLineIndex);
                if (endNewLine > previousNewLine) {
                    let importLine = introSection.substring(previousNewLine, endNewLine);
                    const leftBracket = importLine.indexOf("{");
                    const rightBracket = importLine.indexOf("}");
                    if (leftBracket > 0 && rightBracket > leftBracket) {
                        const interior = importLine.substring(leftBracket + 1, rightBracket).trim();
                        let injectToken = importType;
                        // is there one token already in the import linte
                        if (interior.length > 0) {
                            injectToken = ", " + injectToken;
                        }
                        importLine = importLine.substring(0, rightBracket) + injectToken + importLine.substring(rightBracket);
                    }
                    introSection = introSection.substring(0, previousNewLine) + importLine + introSection.substring(endNewLine);
                }
            }
        }
        return introSection;
    }
    static async ensureTypeScriptFileWith(project, token, templateSet, templateName, fileNameCore, replacers) {
        const itemsCopy = project.getItemsCopy();
        for (const projectItem of itemsCopy) {
            if (projectItem.itemType === IProjectItemData_1.ProjectItemType.ts) {
                await projectItem.loadFileContent();
                if (projectItem.primaryFile) {
                    const tsJson = await TypeScriptDefinition_1.default.ensureOnFile(projectItem.primaryFile);
                    if (tsJson?.data && tsJson.data.indexOf(token) >= 0) {
                        return;
                    }
                }
            }
        }
        const snippet = await Database_1.default.getSnippet(templateSet, templateName);
        const scriptFolder = await project.ensureDefaultScriptsFolder();
        await scriptFolder.load();
        if (!snippet) {
            Log_1.default.error("Could not find template " + templateSet, templateName);
            return;
        }
        const file = scriptFolder.ensureFile(fileNameCore + ".ts");
        let snippetInjectContent = "\n" + snippet.body.join("\n") + "\n";
        for (const replacerToken in replacers) {
            const targetReplace = replacers[replacerToken];
            if (targetReplace) {
                // replace with something better.
                while (snippetInjectContent.indexOf(replacerToken) >= 0) {
                    snippetInjectContent = snippetInjectContent.replace(replacerToken, replacers[replacerToken]);
                }
            }
        }
        file.setContent(snippetInjectContent);
        await file.saveContent();
        project.ensureItemFromFile(file, IProjectItemData_1.ProjectItemType.ts, Project_1.FolderContext.behaviorPack);
    }
    static async injectSnippet(project, snippet, fullScriptBoxReplace) {
        let snippetInjectContent = "\n" + snippet.body.join("\n") + "\n";
        const folder = await project.ensureDefaultScriptsFolder();
        await folder.load();
        // Log.debugAlert("Inject snippet considering folder: " + folder.storageRelativePath + "|" + replaceContent);
        for (const fileName in folder.files) {
            const file = folder.files[fileName];
            if (file !== undefined) {
                if (fullScriptBoxReplace && fileName === "ScriptBox.ts") {
                    snippetInjectContent = ProjectUtilities.adaptFullSample(snippetInjectContent);
                    file.setContent(snippetInjectContent);
                }
                else {
                    const type = StorageUtilities_1.default.getTypeFromName(file.name);
                    if (type === "ts" || type === "js") {
                        if (!file.isContentLoaded) {
                            await file.loadContent();
                        }
                        // Log.debugAlert("Inject snippet considering file: " + file.storageRelativePath + "|" + file.content?.length);
                        if (file.content && typeof file.content === "string") {
                            let content = file.content;
                            for (let i = 0; i < this.CodeReplaceTokens.length; i++) {
                                const token = content.indexOf(this.CodeReplaceTokens[i]);
                                if (token >= 0) {
                                    const previousNewLine = content.lastIndexOf("\n", token);
                                    const nextNewLine = content.indexOf("\n", token);
                                    if (previousNewLine >= 0 && nextNewLine > previousNewLine) {
                                        snippetInjectContent = ProjectUtilities.adaptSample(snippetInjectContent, content);
                                        content =
                                            content.substring(0, previousNewLine) + snippetInjectContent + content.substring(nextNewLine + 1);
                                        if (snippetInjectContent.indexOf("overworld") >= 0 &&
                                            snippetInjectContent.indexOf("const overworld") <= 0) {
                                            let firstComment = content.indexOf("//");
                                            if (firstComment >= 0) {
                                                content =
                                                    content.substring(0, firstComment) +
                                                        '  const overworld = mc.world.getDimension("overworld");\n' +
                                                        content.substring(firstComment, content.length);
                                            }
                                        }
                                        content = ProjectUtilities.modifyImports(content);
                                        file.setContent(content);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    static async addBlockType(project, blockTypeId, blockTypeName) {
        const defaultBehaviorPackPath = await ProjectUtilities.getBaseBehaviorPackPath(project);
        const defaultScriptsPath = await ProjectUtilities.getBaseScriptsPath(project);
        if (defaultBehaviorPackPath === undefined || defaultScriptsPath === undefined) {
            return;
        }
        await Database_1.default.getReleaseVanillaBehaviorPackFolder();
        if (Database_1.default.releaseVanillaBehaviorPackFolder === null) {
            Log_1.default.fail("Could not find default behavior pack folder");
            return;
        }
        const sourceFile = Database_1.default.releaseVanillaBehaviorPackFolder
            .ensureFolder("blocks")
            .ensureFile(blockTypeId + ".json");
        if (!sourceFile.isContentLoaded) {
            await sourceFile.loadContent(true);
        }
        if (!sourceFile.content ||
            sourceFile.content === "" ||
            sourceFile.content === "null" ||
            sourceFile.content instanceof Uint8Array) {
            Log_1.default.fail("Block at '" + sourceFile.fullPath + "' is empty.");
            return;
        }
        const name = blockTypeId ? MinecraftUtilities_1.default.canonicalizeName(blockTypeId) : "block";
        const nextBlockTypeName = blockTypeName ? blockTypeName : name;
        const candidateFilePath = await ProjectUtilities.getFileName(project, defaultBehaviorPackPath + "blocks/", nextBlockTypeName, "json", true);
        if (candidateFilePath === undefined) {
            return;
        }
        const pi = project.ensureItemByProjectPath(candidateFilePath, IProjectItemData_1.ProjectItemStorageType.singleFile, nextBlockTypeName, IProjectItemData_1.ProjectItemType.blockTypeBehavior, Project_1.FolderContext.behaviorPack, undefined, IProjectItemData_1.ProjectItemCreationType.normal);
        const file = await pi.loadFileContent();
        if (file !== null) {
            const content = Utilities_1.default.fixJsonContent(sourceFile.content);
            file.setContent(content);
            const bt = await BlockTypeDefinition_1.default.ensureOnFile(file, undefined);
            if (bt) {
                bt.id =
                    nextBlockTypeName.indexOf(":") >= 0
                        ? nextBlockTypeName
                        : project.effectiveDefaultNamespace + ":" + nextBlockTypeName;
                bt.persist();
            }
            await file.saveContent(true);
        }
        /*
        if (project.preferredScriptLanguage === ProjectScriptLanguage.javaScript) {
          const candidateJsFilePath = await ProjectUtilities.getFileName(
            project,
            defaultScriptsPath + "generated/",
            nextBlockTypeName + ".base",
            "js",
            true
          );
    
          if (candidateJsFilePath) {
            const piGenJs = project.ensureItemByProjectPath(
              candidateJsFilePath,
              ProjectItemStorageType.singleFile,
              StorageUtilities.getLeafName(candidateJsFilePath),
              ProjectItemType.blockTypeBaseJs,
              undefined,
              ProjectItemCreationType.generated
            );
    
            await ProjectAutogeneration.updateItemAutogeneration(piGenJs);
          }
        } else if (project.preferredScriptLanguage === ProjectScriptLanguage.typeScript) {
          const candidateJsFilePath = await ProjectUtilities.getFileName(
            project,
            defaultScriptsPath + "generated/",
            nextBlockTypeName + ".base",
            "ts",
            true
          );
    
          if (candidateJsFilePath) {
            const piGenJs = project.ensureItemByProjectPath(
              candidateJsFilePath,
              ProjectItemStorageType.singleFile,
              StorageUtilities.getLeafName(candidateJsFilePath),
              ProjectItemType.blockTypeBaseTs,
              undefined,
              ProjectItemCreationType.normal
            );
    
            await ProjectAutogeneration.updateItemAutogeneration(piGenJs);
          }
        }*/
    }
    static canonicalizeStoragePath(path) {
        if (!path) {
            return "";
        }
        path = path.toLowerCase();
        return path;
    }
    static canonicalizeNamespace(path) {
        if (!path) {
            return "";
        }
        path = path.toLowerCase();
        path = path.replace(/ /gi, "");
        path = path.replace(/:/gi, "");
        return path;
    }
    static async getFileName(project, basePath, baseName, extension, includeBase) {
        if (project.projectFolder === null) {
            return undefined;
        }
        let index = 0;
        if (includeBase) {
            index = -1;
        }
        let candidateFilePath = "";
        const projectFolder = project.projectFolder;
        let candidateFile = null;
        await projectFolder.ensureFolderFromRelativePath(basePath);
        await projectFolder.ensureExists();
        // find a filename not in use
        do {
            index++;
            if (index === 0) {
                candidateFilePath = basePath + baseName + "." + extension;
            }
            else {
                candidateFilePath = basePath + baseName + index + "." + extension;
            }
            candidateFile = await projectFolder.getFileFromRelativePath(candidateFilePath);
        } while (candidateFile !== null && candidateFile !== undefined);
        return candidateFilePath;
    }
}
exports.default = ProjectUtilities;

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