"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataFormIssueType = void 0;
const Utilities_1 = require("../core/Utilities");
const DataFormUtilities_1 = require("./DataFormUtilities");
const FieldUtilities_1 = require("./FieldUtilities");
const IField_1 = require("./IField");
var DataFormIssueType;
(function (DataFormIssueType) {
    DataFormIssueType[DataFormIssueType["unexpectedStringUsedWhenObjectExpected"] = 101] = "unexpectedStringUsedWhenObjectExpected";
    DataFormIssueType[DataFormIssueType["unexpectedBooleanUsedWhenObjectExpected"] = 102] = "unexpectedBooleanUsedWhenObjectExpected";
    DataFormIssueType[DataFormIssueType["unexpectedNumberUsedWhenObjectExpected"] = 103] = "unexpectedNumberUsedWhenObjectExpected";
    DataFormIssueType[DataFormIssueType["dataTypeMismatch"] = 110] = "dataTypeMismatch";
})(DataFormIssueType = exports.DataFormIssueType || (exports.DataFormIssueType = {}));
class DataFormValidator {
    static async validate(data, form, issues, path) {
        if (path === undefined) {
            path = "";
        }
        else {
            path = path + ".";
        }
        if (!issues) {
            issues = [];
        }
        if (typeof data === "string" || typeof data === "number" || typeof data === "boolean") {
            const scalarField = DataFormUtilities_1.default.getScalarField(form);
            if (!scalarField) {
                if (typeof data === "string") {
                    issues.push(DataFormValidator.getValidationIssue(DataFormIssueType.unexpectedStringUsedWhenObjectExpected));
                }
                else if (typeof data === "number") {
                    issues.push(DataFormValidator.getValidationIssue(DataFormIssueType.unexpectedNumberUsedWhenObjectExpected));
                }
                else if (typeof data === "boolean") {
                    issues.push(DataFormValidator.getValidationIssue(DataFormIssueType.unexpectedBooleanUsedWhenObjectExpected));
                }
                return issues;
            }
            await this.validateField(data, scalarField, issues, path + "<default value>");
        }
        const fields = form.fields;
        for (const field of fields) {
            if (field.id) {
                const fieldData = data[field.id];
                await this.validateField(fieldData, field, issues, path + FieldUtilities_1.default.getFieldId(field));
            }
        }
        return issues;
    }
    static async validateField(data, field, issues, path) {
        const allFields = DataFormUtilities_1.default.getFieldAndAlternates(field);
        let dataMismatchErrors = "";
        let hasOneMatch = false;
        let isRequired = false;
        for (const field of allFields) {
            if (data !== undefined && data !== null) {
                const mismatchError = DataFormValidator.getDataMismatchError(data, field.dataType);
                if (!mismatchError) {
                    hasOneMatch = true;
                }
                else {
                    dataMismatchErrors += mismatchError;
                }
                if (field.isRequired) {
                    isRequired = true;
                }
            }
        }
        if (data === undefined || data === null) {
            if (isRequired) {
                issues.push({
                    message: "At " + path + ", data is missing required field '" + field.id + "'.",
                    type: DataFormIssueType.dataTypeMismatch,
                });
            }
            return;
        }
        if (!hasOneMatch) {
            if (allFields.length > 1) {
                issues.push({
                    message: "At " + path + ", data does not match any one of the expected types: " + dataMismatchErrors,
                    type: DataFormIssueType.dataTypeMismatch,
                });
            }
            else {
                issues.push({
                    message: "At " + path + ", data does not match expected type. " + dataMismatchErrors,
                    type: DataFormIssueType.dataTypeMismatch,
                });
            }
        }
        if (typeof data === "object" && data === null && field.id && Utilities_1.default.isUsableAsObjectKey(field.id)) {
            const fieldData = data[field.id];
            const subForm = await FieldUtilities_1.default.getSubForm(field);
            if (subForm && fieldData !== undefined && fieldData !== null) {
                await this.validate(fieldData, subForm, issues, path);
            }
        }
    }
    static getDataMismatchError(data, type) {
        if (Array.isArray(data)) {
            if (typeof data === "string") {
                if (type === IField_1.FieldDataType.stringArray ||
                    type === IField_1.FieldDataType.checkboxListAsStringArray ||
                    type === IField_1.FieldDataType.longFormStringArray) {
                    return undefined;
                }
                return ("Data '" +
                    data +
                    "' is of type string array, which does not match type '" +
                    DataFormUtilities_1.default.getFieldTypeDescription(type) +
                    "'.");
            }
            else if (typeof data === "number") {
                if (type === IField_1.FieldDataType.numberArray || type === IField_1.FieldDataType.floatRange) {
                    return undefined;
                }
                return ("Data '" +
                    data +
                    "' is of type number array, which does not match type '" +
                    DataFormUtilities_1.default.getFieldTypeDescription(type) +
                    "'.");
            }
        }
        else if (typeof data === "string") {
            if (type === IField_1.FieldDataType.localizableString ||
                type === IField_1.FieldDataType.longFormString ||
                type === IField_1.FieldDataType.version ||
                type === IField_1.FieldDataType.stringLookup ||
                type === IField_1.FieldDataType.string) {
                return undefined;
            }
            return ("Data '" +
                data +
                "' is of type string, which does not match type '" +
                DataFormUtilities_1.default.getFieldTypeDescription(type) +
                "'.");
        }
        else if (typeof data === "number") {
            if (type === IField_1.FieldDataType.float ||
                type === IField_1.FieldDataType.intBoolean ||
                type === IField_1.FieldDataType.int ||
                type === IField_1.FieldDataType.intEnum ||
                type === IField_1.FieldDataType.intValueLookup) {
                return undefined;
            }
            return ("Data '" +
                data +
                "' is of type number, which does not match type '" +
                DataFormUtilities_1.default.getFieldTypeDescription(type) +
                "'.");
        }
        else if (typeof data === "boolean") {
            if (type === IField_1.FieldDataType.boolean) {
                return undefined;
            }
            return ("Data '" +
                data +
                "' is of type boolean, which does not match type '" +
                DataFormUtilities_1.default.getFieldTypeDescription(type) +
                "'.");
        }
        else if (typeof data === "object") {
            if (type === IField_1.FieldDataType.object ||
                type === IField_1.FieldDataType.keyedBooleanCollection ||
                type === IField_1.FieldDataType.keyedKeyedStringArrayCollection ||
                type === IField_1.FieldDataType.keyedNumberArrayCollection ||
                type === IField_1.FieldDataType.keyedNumberCollection ||
                type === IField_1.FieldDataType.keyedObjectCollection ||
                type === IField_1.FieldDataType.keyedStringArrayCollection ||
                type === IField_1.FieldDataType.keyedStringCollection) {
                return undefined;
            }
            let dataStr = JSON.stringify(data);
            if (dataStr.length > 60) {
                dataStr = dataStr.substring(0, 60) + "...";
            }
            return ("Data '" +
                dataStr +
                "' is an object, which does not match type '" +
                DataFormUtilities_1.default.getFieldTypeDescription(type) +
                "'.");
        }
        return undefined;
    }
    static getValidationIssue(type) {
        return {
            message: Utilities_1.default.getTitleFromEnum(DataFormIssueType, type),
            type: type,
        };
    }
}
exports.default = DataFormValidator;

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