"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
const ProjectInfoItem_1 = require("./ProjectInfoItem");
const IInfoItemData_1 = require("./IInfoItemData");
const Database_1 = require("../minecraft/Database");
const CartoApp_1 = require("../app/CartoApp");
const ajv_1 = require("ajv");
const axios_1 = require("axios");
const Utilities_1 = require("../core/Utilities");
const MinecraftDefinitions_1 = require("../minecraft/MinecraftDefinitions");
const ProjectItemUtilities_1 = require("../app/ProjectItemUtilities");
class SchemaItemInfoGenerator {
    constructor() {
        this.id = "JSON";
        this.title = "JSON Schema Validation";
        this._validatorsByPath = {};
        this._schemaContentByPath = {};
        this.uuidRegex = new RegExp("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}");
        this.loadSchema = this.loadSchema.bind(this);
        this.testUuid = this.testUuid.bind(this);
        this.testUri = this.testUri.bind(this);
    }
    getTopicData(topicId) {
        return {
            title: topicId.toString(),
        };
    }
    summarize(info, infoSet) { }
    async loadSchema(uri) {
        console.log("Retrieving " + uri);
        const res = await axios_1.default.get(CartoApp_1.default.contentRoot + uri);
        console.log("Loading error: " + JSON.stringify(res.data));
        return res.data;
    }
    async generate(projectItem, contentIndex) {
        const items = [];
        if (projectItem.file && projectItem.file.content && typeof projectItem.file.content === "string") {
            const schemaPath = projectItem.getSchemaPath();
            if (schemaPath) {
                let val = this._validatorsByPath[schemaPath];
                let verIsCurrent = await MinecraftDefinitions_1.default.formatVersionIsCurrent(projectItem);
                if (verIsCurrent) {
                    if (!val) {
                        const schemaContents = await Database_1.default.getSchema(schemaPath);
                        if (schemaContents) {
                            const ajv = new ajv_1.default({
                                allErrors: true,
                                loadSchema: this.loadSchema,
                                strict: false,
                                unicodeRegExp: false,
                                verbose: true,
                            });
                            ajv.addFormat("uuid", this.testUuid);
                            ajv.addFormat("uri", this.testUri);
                            ajv.addFormat("color-hex", this.testUnknownFormat);
                            ajv.addFormat("colox-hex", this.testUnknownFormat);
                            ajv.addFormat("molang", this.testUnknownFormat);
                            val = ajv.compile(schemaContents);
                            this._validatorsByPath[schemaPath] = val;
                            this._schemaContentByPath[schemaPath] = schemaContents;
                        }
                    }
                    if (val) {
                        let content = projectItem.file.content;
                        let contentObj = undefined;
                        content = Utilities_1.default.fixJsonContent(content);
                        try {
                            contentObj = JSON.parse(content);
                        }
                        catch (e) {
                            let errorMess = e;
                            if (e.message) {
                                errorMess = e.message;
                            }
                            items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.error, this.id, 1, "Could not parse JSON - " + errorMess, projectItem));
                        }
                        if (contentObj) {
                            const result = val(contentObj);
                            if (!result && val.errors) {
                                for (let i = 0; i < val.errors.length; i++) {
                                    const err = val.errors[i];
                                    this.addError(items, projectItem, err);
                                }
                            }
                        }
                    }
                }
                else {
                    let fvStr = "";
                    const fv = await MinecraftDefinitions_1.default.getFormatVersion(projectItem);
                    if (fv) {
                        fvStr = " (is at " + fv.join(".") + ")";
                    }
                    items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.info, this.id, 1100 + projectItem.itemType, ProjectItemUtilities_1.default.getDescriptionForType(projectItem.itemType) +
                        " is not at a current format version" +
                        fvStr, projectItem));
                }
            }
        }
        return items;
    }
    addError(items, projectItem, error) {
        var message = "";
        switch (error.keyword) {
            case "required":
                message = 'Property "' + error.params.missingProperty + '" missing';
                break;
            case "type":
                message = "Wrong type: " + error.instancePath + " " + error.keyword + " " + error.message;
                break;
            default:
                message = error.keyword + " " + error.instancePath + " " + error.message;
                break;
        }
        let errorContent = undefined;
        if (typeof error.data === "string") {
            errorContent = error.data;
        }
        else if (typeof error.data === "object") {
            let serial = undefined;
            try {
                serial = JSON.stringify(error.data, null, 2);
            }
            catch (e) { }
            errorContent = serial;
        }
        let data = undefined;
        if (error.params) {
            for (const key in error.params) {
                let val = error.params[key];
                if (typeof val === "string" &&
                    key !== "type" &&
                    key !== "pattern" &&
                    key !== "missingProperty" &&
                    key !== "comparison" &&
                    key !== "failingKeyword") {
                    // force line breaks in long strings
                    if (val.length > 80 && val.indexOf(" ") < 0) {
                        val = val.replace(/,/gi, ", ");
                    }
                    if (data === undefined) {
                        data = "";
                    }
                    else {
                        data += " ";
                    }
                    data += "(" + key + ": " + val + ")";
                }
            }
        }
        items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.warning, this.id, 100 + projectItem.itemType, message, projectItem, data, undefined, errorContent));
    }
    testUuid(uuidString) {
        return this.uuidRegex.test(uuidString);
    }
    testUnknownFormat(formatString) {
        return true;
    }
    testUri(uriString) {
        // could get much more sophisticated here...
        return uriString.indexOf("://") >= 0;
    }
}
exports.default = SchemaItemInfoGenerator;

//# sourceMappingURL=../maps/info/SchemaItemInfoGenerator.js.map
