"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
const Utilities_1 = require("../core/Utilities");
const Database_1 = require("../minecraft/Database");
const IField_1 = require("./IField");
class DataFormUtilities {
    static generateDefaultItem(formDefinition) {
        const newDataObject = {};
        for (let i = 0; i < formDefinition.fields.length; i++) {
            const field = formDefinition.fields[i];
            if (field.defaultValue !== undefined) {
                if (typeof field.defaultValue === "string" &&
                    DataFormUtilities.isObjectFieldType(field.dataType) &&
                    Utilities_1.default.isUsableAsObjectKey(field.id)) {
                    // sometimes our docs say the default value for an object is "N/A", which is not awesome
                    newDataObject[field.id] = {};
                }
                else {
                    newDataObject[field.id] = field.defaultValue;
                }
            }
        }
        return newDataObject;
    }
    static selectSubForm(form, select) {
        const selectors = select.split("/");
        for (const selector of selectors) {
            if (selector.length > 0) {
                const field = DataFormUtilities.getFieldById(form, selector);
                if (!field || !field.subForm) {
                    throw new Error("Unable to find field " + selector + " in form " + form.id);
                }
                form = field.subForm;
            }
        }
        return form;
    }
    static mergeFields(form) {
        let fields = [];
        const fieldsByName = {};
        for (const field of form.fields) {
            if (fieldsByName[field.id]) {
                const origField = fieldsByName[field.id];
                if (!origField.alternates) {
                    origField.alternates = [];
                }
                origField.alternates.push(field);
                if (field.alternates) {
                    for (const subField of field.alternates) {
                        origField.alternates.push(subField);
                    }
                    field.alternates = undefined;
                }
            }
            else {
                fields.push(field);
                if (Utilities_1.default.isUsableAsObjectKey(field.id)) {
                    fieldsByName[field.id] = field;
                }
            }
        }
        form.fields = fields;
        for (const field of fields) {
            if (field.subForm) {
                DataFormUtilities.mergeFields(field.subForm);
            }
            if (field.alternates) {
                for (let addField of field.alternates) {
                    if (addField.subForm) {
                        DataFormUtilities.mergeFields(addField.subForm);
                    }
                }
            }
        }
        DataFormUtilities.sortAndCleanAlternateFields(form);
    }
    static isObjectFieldType(fieldDataType) {
        return (fieldDataType === IField_1.FieldDataType.object ||
            fieldDataType === IField_1.FieldDataType.minecraftFilter ||
            fieldDataType === IField_1.FieldDataType.minecraftEventTrigger);
    }
    static isScalarFieldType(fieldDataType) {
        return (fieldDataType === IField_1.FieldDataType.boolean ||
            fieldDataType === IField_1.FieldDataType.float ||
            fieldDataType === IField_1.FieldDataType.int ||
            fieldDataType === IField_1.FieldDataType.intBoolean ||
            fieldDataType === IField_1.FieldDataType.intEnum ||
            fieldDataType === IField_1.FieldDataType.string ||
            fieldDataType === IField_1.FieldDataType.molang);
    }
    static sortFieldsBySignificance(fieldA, fieldB) {
        if (fieldA.subForm && !fieldB.subForm) {
            return -1;
        }
        if (!fieldA.subForm && fieldB.subForm) {
            return 1;
        }
        const isAComplex = !DataFormUtilities.isScalarFieldType(fieldA.dataType);
        const isBComplex = !DataFormUtilities.isScalarFieldType(fieldB.dataType);
        if (isAComplex && !isBComplex) {
            return -1;
        }
        if (!isAComplex && isBComplex) {
            return 1;
        }
        return fieldA.dataType - fieldB.dataType;
    }
    static sortFieldsByPriority(fieldA, fieldB) {
        if (fieldA.isDeprecated && !fieldB.isDeprecated) {
            return 1;
        }
        if (!fieldA.isDeprecated && fieldB.isDeprecated) {
            return -1;
        }
        if (fieldA.priority && !fieldB.priority) {
            return -1;
        }
        if (fieldB.priority && !fieldA.priority) {
            return 1;
        }
        if (fieldA.priority && fieldB.priority) {
            return fieldA.priority - fieldB.priority;
        }
        if (fieldA.title && fieldB.title) {
            return fieldA.title.localeCompare(fieldB.title);
        }
        if (fieldA.id && fieldB.id) {
            return Utilities_1.default.staticCompare(fieldA.id, fieldB.id);
        }
        return 0;
    }
    static async loadSubForms(form, loadedForms) {
        if (!loadedForms) {
            loadedForms = "";
        }
        if (form && form.fields) {
            for (const field of form.fields) {
                let subForm = undefined;
                if (field.subForm) {
                    subForm = field.subForm;
                }
                else if (field.subFormId) {
                    if (loadedForms.indexOf("|" + field.subFormId + "|") < 0) {
                        subForm = await Database_1.default.ensureFormLoadedByPath(field.subFormId);
                        loadedForms += "|" + field.subFormId + "|";
                    }
                }
                if (subForm) {
                    await this.loadSubForms(subForm, loadedForms);
                }
            }
        }
        if (loadedForms === "") {
            return undefined;
        }
        return loadedForms;
    }
    static sortAndCleanAlternateFields(form) {
        let fields = [];
        for (const field of form.fields) {
            if (field.alternates) {
                const allFields = [];
                allFields.push(field);
                allFields.push(...field.alternates);
                field.alternates = undefined;
                allFields.sort(DataFormUtilities.sortFieldsBySignificance);
                allFields[0].alternates = [];
                fields.push(allFields[0]);
                for (let i = 1; i < allFields.length; i++) {
                    if (allFields[i].title === allFields[0].title) {
                        allFields[i].title = undefined;
                    }
                    allFields[0].alternates.push(allFields[i]);
                }
            }
            else {
                fields.push(field);
            }
        }
        form.fields = fields;
        for (const field of fields) {
            if (field.subForm) {
                DataFormUtilities.sortAndCleanAlternateFields(field.subForm);
            }
            if (field.alternates) {
                for (let addField of field.alternates) {
                    if (addField.subForm) {
                        DataFormUtilities.sortAndCleanAlternateFields(addField.subForm);
                    }
                }
            }
        }
    }
    static fixupFields(form, parentField) {
        let fields = [];
        for (const field of form.fields) {
            if ((field.dataType === IField_1.FieldDataType.stringArray || field.dataType === IField_1.FieldDataType.numberArray) &&
                field.subForm &&
                field.subForm.fields &&
                field.subForm.fields.length >= 1) {
                const subField = field.subForm.fields[0];
                if (subField.id.indexOf("<") >= 0) {
                    if (subField.dataType === IField_1.FieldDataType.molang) {
                        field.dataType = IField_1.FieldDataType.molangArray;
                    }
                    field.subForm = undefined;
                }
                fields.push(field);
            }
            else if (field.id.startsWith("<") && parentField) {
                if (!parentField.alternates) {
                    parentField.alternates = [];
                }
                field.keyDescription = field.id;
                field.id = parentField.id;
                if (field.dataType === IField_1.FieldDataType.molangArray || field.dataType === IField_1.FieldDataType.stringArray) {
                    field.dataType = IField_1.FieldDataType.keyedStringCollection;
                }
                parentField.alternates.push(field);
            }
            else {
                fields.push(field);
            }
        }
        form.fields = fields;
        for (const field of fields) {
            if (field.subForm) {
                DataFormUtilities.fixupFields(field.subForm, field);
            }
            if (field.alternates) {
                for (let addField of field.alternates) {
                    if (addField.subForm) {
                        DataFormUtilities.fixupFields(addField.subForm, field);
                    }
                }
            }
        }
    }
    static generateFormFromObject(id, obj, exampleSourcePath) {
        let fields = [];
        for (const fieldName in obj) {
            const fieldData = obj[fieldName];
            let fieldType = IField_1.FieldDataType.string;
            if (typeof fieldData === "number") {
                fieldType = IField_1.FieldDataType.number;
            }
            const samples = {};
            samples[exampleSourcePath ? exampleSourcePath : "generated_doNotEdit"] = [
                {
                    path: fieldName,
                    content: fieldData,
                },
            ];
            fields.push({
                id: fieldName,
                title: Utilities_1.default.humanifyJsName(fieldName),
                dataType: fieldType,
                samples: samples,
            });
        }
        return {
            id: id,
            title: Utilities_1.default.humanifyJsName(id),
            fields: fields,
        };
    }
    static getFieldAndAlternates(fieldDefinition) {
        const fields = [fieldDefinition];
        if (fieldDefinition.alternates) {
            for (const altField of fieldDefinition.alternates) {
                fields.push(...DataFormUtilities.getFieldAndAlternates(altField));
            }
        }
        return fields;
    }
    static getScalarField(formDefinition) {
        if (formDefinition.scalarField) {
            return formDefinition.scalarField;
        }
        if (formDefinition.scalarFieldUpgradeName && formDefinition.fields) {
            for (const field of formDefinition.fields) {
                if (field.id === formDefinition.scalarFieldUpgradeName) {
                    return field;
                }
            }
        }
        return undefined;
    }
    static isString(fieldType) {
        return (fieldType === IField_1.FieldDataType.string ||
            fieldType === IField_1.FieldDataType.molang ||
            fieldType === IField_1.FieldDataType.longFormString ||
            fieldType === IField_1.FieldDataType.stringLookup ||
            fieldType === IField_1.FieldDataType.stringEnum ||
            fieldType === IField_1.FieldDataType.localizableString);
    }
    static getFieldById(formDefinition, fieldId) {
        if (!formDefinition.fields) {
            return undefined;
        }
        for (const field of formDefinition.fields) {
            if (field.id === fieldId) {
                return field;
            }
        }
        return undefined;
    }
    static getFieldTypeDescription(fieldType) {
        switch (fieldType) {
            case IField_1.FieldDataType.int:
                return "Integer number";
            case IField_1.FieldDataType.boolean:
                return "Boolean true/false";
            case IField_1.FieldDataType.float:
                return "Decimal number";
            case IField_1.FieldDataType.stringEnum:
                return "String from a list of choices";
            case IField_1.FieldDataType.intEnum:
                return "Integer number from a list of choices";
            case IField_1.FieldDataType.intBoolean:
                return "Boolean 0/1";
            case IField_1.FieldDataType.number:
                return "Decimal number";
            case IField_1.FieldDataType.long:
                return "Large number";
            case IField_1.FieldDataType.stringLookup:
                return "String from a list of choices";
            case IField_1.FieldDataType.intValueLookup:
                return "Integer number from a list of choices";
            case IField_1.FieldDataType.point3:
                return "x, y, z coordinate array";
            case IField_1.FieldDataType.intPoint3:
                return "integer x, y, z coordinate array";
            case IField_1.FieldDataType.longFormString:
                return "Longer descriptive text";
            case IField_1.FieldDataType.keyedObjectCollection:
                return "Named set of objects";
            case IField_1.FieldDataType.objectArray:
                return "Array of objects";
            case IField_1.FieldDataType.object:
                return "Object";
            case IField_1.FieldDataType.stringArray:
                return "Array of strings";
            case IField_1.FieldDataType.intRange:
                return "Range of integers";
            case IField_1.FieldDataType.floatRange:
                return "Range of floats";
            case IField_1.FieldDataType.minecraftFilter:
                return "Minecraft filter";
            case IField_1.FieldDataType.minecraftEventTriggerArray:
                return "Array of Minecraft Event Triggers";
            case IField_1.FieldDataType.percentRange:
                return "Percent Range";
            case IField_1.FieldDataType.minecraftEventTrigger:
                return "Minecraft Event Trigger";
            case IField_1.FieldDataType.minecraftEventReference:
                return "Minecraft Event Reference";
            case IField_1.FieldDataType.longFormStringArray:
                return "Array of longer descriptive text";
            case IField_1.FieldDataType.keyedStringCollection:
                return "Keyed set of strings";
            case IField_1.FieldDataType.version:
                return "Version";
            case IField_1.FieldDataType.uuid:
                return "Unique Id";
            case IField_1.FieldDataType.keyedBooleanCollection:
                return "Keyed collection of boolean values";
            case IField_1.FieldDataType.keyedStringArrayCollection:
                return "Keyed collection of string arrays";
            case IField_1.FieldDataType.arrayOfKeyedStringCollection:
                return "Array of keyed string sets";
            case IField_1.FieldDataType.keyedKeyedStringArrayCollection:
                return "Keyed set of keyed string sets";
            case IField_1.FieldDataType.keyedNumberCollection:
                return "Keyed set of numbers";
            case IField_1.FieldDataType.numberArray:
                return "Array of numbers";
            case IField_1.FieldDataType.point2:
                return "a, b coordinate array";
            case IField_1.FieldDataType.localizableString:
                return "Localizable String";
            case IField_1.FieldDataType.string:
                return "String";
            case IField_1.FieldDataType.molang:
                return "Molang";
            case IField_1.FieldDataType.molangArray:
                return "Molang array";
            default:
                return "String";
        }
    }
}
exports.default = DataFormUtilities;

//# sourceMappingURL=../maps/dataform/DataFormUtilities.js.map
