"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable frontApplet/enforce-jsdoc */
const Validate_1 = require("./Validate");
const AppletResourcesError_1 = __importDefault(require("../Error/AppletResourcesError"));
const ErrorCodesMessages_1 = __importDefault(require("../Error/ErrorCodesMessages"));
class ValidateObjectInterface {
    error = undefined;
    validate(objectInterface, subject, interfaceItemNameFromRecursion) {
        if (typeof objectInterface !== 'object') {
            throw new Error('invalid object interface, needs to be object');
        }
        let outcome = true;
        for (const interfaceItemName in objectInterface) {
            if (!Object.prototype.hasOwnProperty.call(objectInterface, interfaceItemName)) {
                continue;
            }
            const interfaceItemType = objectInterface[interfaceItemName];
            if (typeof interfaceItemType === 'object') {
                const validation = this.validateTypingObject(interfaceItemType, interfaceItemName, subject);
                if (validation !== true) {
                    outcome = outcome === true ? validation : outcome + '\n' + validation;
                }
            }
            else {
                const validation = this.validateType(interfaceItemType, interfaceItemName, subject);
                if (validation !== true) {
                    outcome = outcome === true ? validation : outcome + '\n' + validation;
                }
            }
        }
        if (typeof interfaceItemNameFromRecursion === 'undefined' && typeof this.error !== 'undefined' && outcome !== true) {
            this.throwError(this.error, outcome);
        }
        return (outcome === true ||
            `${typeof interfaceItemNameFromRecursion !== 'undefined' ? `${interfaceItemNameFromRecursion}:\n` : ''} {\n${outcome}\n}`);
    }
    validateType(interfaceItemType, interfaceItemName, subject) {
        const isRequired = !interfaceItemType.startsWith('?');
        interfaceItemType = !isRequired ? interfaceItemType.substring(1) : interfaceItemType;
        if (!isRequired && !Object.prototype.hasOwnProperty.call(subject, interfaceItemName)) {
            return true;
        }
        else if (isRequired && !Object.prototype.hasOwnProperty.call(subject, interfaceItemName)) {
            return `${interfaceItemName}: is required`;
        }
        if (typeof subject[interfaceItemName] !== interfaceItemType) {
            return `${interfaceItemName}: needs to be type ${interfaceItemType}. Got ${typeof subject[interfaceItemName]}`;
        }
        return true;
    }
    validateTypingObject(interfaceItemType, interfaceItemName, subject) {
        const error = typeof interfaceItemType.error !== 'undefined' ? interfaceItemType.error : undefined;
        for (let type in interfaceItemType) {
            if (!Object.prototype.hasOwnProperty.call(interfaceItemType, type) ||
                type === 'error' ||
                !(Validate_1.validatableType.includes(type) || Validate_1.validatableType.includes(type.substr(1)))) {
                continue;
            }
            const typeAttributes = interfaceItemType[type];
            const isRequired = !type.startsWith('?');
            type = !isRequired ? type.substring(1) : type;
            if (!Object.prototype.hasOwnProperty.call(subject, interfaceItemName)) {
                if (!isRequired) {
                    return true;
                }
                else {
                    const message = `${interfaceItemName}: is required`;
                    if (typeof this.error === 'undefined' && typeof error !== 'undefined') {
                        this.error = error;
                    }
                    return message;
                }
            }
            const subjectByInterfaceName = subject[interfaceItemName];
            if (typeof subjectByInterfaceName !== (type === 'array' ? 'object' : type)) {
                const message = `${interfaceItemName}: needs to be type ${type}. Got ${typeof subjectByInterfaceName}`;
                if (typeof this.error === 'undefined' && typeof error !== 'undefined') {
                    this.error = error;
                }
                return message;
            }
            if ((type === 'string' || type === 'number') && Array.isArray(typeAttributes) && !typeAttributes.includes(subjectByInterfaceName)) {
                const message = `${interfaceItemName}: has to be one of ${JSON.stringify(typeAttributes)}`;
                if (typeof this.error === 'undefined' && typeof error !== 'undefined') {
                    this.error = error;
                }
                return message;
            }
            if (type === 'array') {
                const validation = this.validateArray(typeAttributes, interfaceItemName, subjectByInterfaceName);
                if (validation !== true) {
                    if (typeof this.error === 'undefined' && typeof error !== 'undefined') {
                        this.error = error;
                    }
                    return validation;
                }
            }
            if (type === 'object') {
                return this.validate(typeAttributes, subjectByInterfaceName, interfaceItemName);
            }
        }
        return true;
    }
    validateArray(typingObject, interfaceItemName, subject) {
        let validTypes;
        if (typeof typingObject === 'string') {
            validTypes = [typingObject];
        }
        else if (Array.isArray(typingObject)) {
            validTypes = typingObject;
        }
        else {
            validTypes = Object.keys(typingObject).filter((i) => i !== 'error');
        }
        for (const content of subject) {
            const valid = Validate_1.Validate.validateType(validTypes, content);
            if (valid !== true) {
                return `has to be array of types: ${JSON.stringify(validTypes)}. ${JSON.stringify(content)} is ${valid} instead`;
            }
            if (typeof content === 'object' && typeof typingObject.object !== 'undefined') {
                const validate = this.validate(typingObject.object, content, interfaceItemName);
                if (validate !== true) {
                    return validate;
                }
            }
        }
        return true;
    }
    throwError(error, message) {
        throw new AppletResourcesError_1.default({
            kind: 'appletResourcesError',
            message: `${ErrorCodesMessages_1.default[error.code]}\n\nValidation info:\n${message}\n`,
            code: error.code,
        });
    }
}
exports.default = ValidateObjectInterface;
//# sourceMappingURL=ValidateObjectInterface.js.map