"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Validate = exports.validatableType = void 0;
exports.default = validate;
/* eslint-disable frontApplet/enforce-jsdoc */
//send {variable} into the object so we can output its name in warning
const AppletResourcesError_1 = __importDefault(require("../Error/AppletResourcesError"));
const ErrorCodesMessages_1 = __importDefault(require("../Error/ErrorCodesMessages"));
const ValidateObjectInterface_1 = __importDefault(require("./ValidateObjectInterface"));
exports.validatableType = ['string', 'number', 'boolean', 'function', 'object', 'undefined', 'null', 'array'];
class Validate {
    validationSubject;
    error = undefined;
    _canBeNull = false;
    constructor(validationSubject) {
        this.validationSubject = this.getSubjectFromOutside(validationSubject);
    }
    static oneOfPossibleTypesIsType(types, type) {
        if (!Array.isArray(types)) {
            types = [types];
        }
        for (const t of types) {
            if (t === type) {
                return true;
            }
        }
        return false;
    }
    static validateType(types, subject) {
        if (!Array.isArray(types)) {
            types = [types];
        }
        let outputType = '';
        for (const t of types) {
            const valid = this.validateSingleType(t, subject);
            if (valid === true) {
                return true;
            }
            else {
                outputType = valid;
            }
        }
        return outputType;
    }
    static validateSingleType(type, subject) {
        return typeof subject === type ? true : typeof subject;
    }
    canBeNull() {
        this._canBeNull = true;
        return this;
    }
    setError(error) {
        this.error = error;
        return this;
    }
    required(errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject === 'undefined') {
            this.throwError('is required', errorCode);
        }
        return this;
    }
    boolean(errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && typeof this.validationSubject.subject !== 'boolean') {
            this.throwError(`has to be boolean. Got ${typeof this.validationSubject.subject} instead`, errorCode);
        }
        return this;
    }
    number(errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && typeof this.validationSubject.subject !== 'number') {
            this.throwError(`has to be number. Got ${typeof this.validationSubject.subject} instead`, errorCode);
        }
        return this;
    }
    min(value, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && typeof this.validationSubject.subject === 'number') {
            if (this.validationSubject.subject < value) {
                this.throwError(`has to be at least ${value}. Got ${this.validationSubject.subject}`, errorCode);
            }
        }
        return this;
    }
    max(value, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && typeof this.validationSubject.subject === 'number') {
            if (this.validationSubject.subject > value) {
                this.throwError(`has to be at least ${value}. Got ${this.validationSubject.subject}`, errorCode);
            }
        }
        return this;
    }
    string(equals, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && typeof this.validationSubject.subject !== 'string') {
            this.throwError(`has to be string. Got ${typeof this.validationSubject.subject} instead`, errorCode);
        }
        else if (Array.isArray(equals) && !equals.includes(this.validationSubject.subject)) {
            this.throwError(`has to be one of ${equals}. Got ${this.validationSubject.subject} instead`, errorCode);
        }
        return this;
    }
    lengthMin(value, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && this.validationSubject.subject?.length < value) {
            this.throwError(`can't be shorter than ${value}`, errorCode);
        }
        return this;
    }
    lengthMax(value, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && this.validationSubject.subject?.length > value) {
            this.throwError(`can't be longer than ${value}`, errorCode);
        }
        return this;
    }
    object(objectInterface, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' &&
            (typeof this.validationSubject.subject !== 'object' || this.validationSubject.subject === null)) {
            this.throwError(`has to be object. Got ${typeof this.validationSubject.subject} instead`, errorCode);
        }
        else if (typeof objectInterface !== 'undefined') {
            this.checkObjectInterface(objectInterface, this.validationSubject.subject);
        }
        return this;
    }
    array(types, objectInterface, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && !Array.isArray(this.validationSubject.subject)) {
            this.throwError(`has to be array. Got ${typeof this.validationSubject.subject} instead`, errorCode);
        }
        else {
            for (const content of this.validationSubject.subject ?? []) {
                const valid = Validate.validateType(types, content);
                if (valid !== true) {
                    this.throwError(`has to be array of types: ${JSON.stringify(types)}. ${JSON.stringify(content)} is ${valid} instead`, errorCode);
                }
                if (typeof objectInterface !== 'undefined') {
                    if (Validate.oneOfPossibleTypesIsType(types, 'object')) {
                        this.checkObjectInterface(objectInterface, content);
                    }
                }
            }
        }
        return this;
    }
    function(errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && typeof this.validationSubject.subject !== 'function') {
            this.throwError(`has to be function. Got ${typeof this.validationSubject.subject} instead`, errorCode);
        }
        return this;
    }
    date(errorCode) {
        function isValidDate(date) {
            return date && Object.prototype.toString.call(date) === '[object Date]';
        }
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && !isValidDate(this.validationSubject.subject)) {
            this.throwError(`has to be instance of Date and be valid`, errorCode);
        }
        return this;
    }
    uri(errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        //regex found here https://stackoverflow.com/questions/30847/regex-to-validate-uris
        const regex = new RegExp("^([a-z0-9+.-]+):(?://(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%" +
            "[0-9A-F]{2})*)(?::(\\d*))?(/(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?|(/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+" +
            "(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?)(?:\\?((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?" +
            "(?:#((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?$", 'i');
        if (typeof this.validationSubject.subject !== 'string') {
            this.throwError(`has to be string. Got ${typeof this.validationSubject.subject} instead`, errorCode);
            return this;
        }
        if (!this.validationSubject.subject.match(regex)) {
            this.throwError(`has to be valid URI.`, errorCode);
        }
        return this;
    }
    matchRegExp(regexp, errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject !== 'undefined' && !regexp.test(this.validationSubject.subject)) {
            this.throwError(`contains invalid characters. Valid pattern: ${regexp.toString()}`, errorCode);
        }
        return this;
    }
    timerTime(errorCode) {
        if (this.canBeNullAndIs()) {
            return this;
        }
        else if (typeof this.validationSubject.subject === 'string') {
            const timeArray = this.validationSubject.subject.split(':');
            let max = 23;
            for (const time of timeArray) {
                if (parseInt(time) < 0 || parseInt(time) > max) {
                    this.throwError(`invalid time`, errorCode);
                }
                max = 60;
            }
        }
        else if (typeof this.validationSubject.subject !== 'string') {
            this.throwError(`invalid time`, errorCode);
        }
        return this;
    }
    own(callback, errorCode) {
        const validationMessage = callback(this.validationSubject);
        if (validationMessage !== true) {
            this.throwError(validationMessage, errorCode);
        }
        return this;
    }
    throwError(message, errorCode) {
        if (typeof this.error !== 'undefined') {
            throw this.error;
        }
        else if (errorCode) {
            throw new AppletResourcesError_1.default({
                kind: 'appletResourcesError',
                message: `${ErrorCodesMessages_1.default[errorCode]} - Validation info: ${message}`,
                code: errorCode,
            });
        }
        else {
            console.warn(`'${this.validationSubject.name}' parameter validation warning: ${message}`);
        }
    }
    canBeNullAndIs() {
        return this._canBeNull && this.validationSubject.subject === null;
    }
    getSubjectFromOutside(validationSubject) {
        if (Object.keys(validationSubject).length !== 1) {
            this.throwError('has to have exactly one key validated');
        }
        for (const key in validationSubject) {
            if (Object.prototype.hasOwnProperty.call(validationSubject, key)) {
                return {
                    name: key,
                    subject: validationSubject[key],
                };
            }
        }
        return { name: '', subject: undefined };
    }
    checkObjectInterface(objectInterface, subject) {
        const objectValidator = new ValidateObjectInterface_1.default();
        const validation = objectValidator.validate(objectInterface, subject);
        if (validation !== true) {
            this.throwError(validation);
        }
    }
}
exports.Validate = Validate;
function validate(validationSubject) {
    return new Validate(validationSubject);
}
//# sourceMappingURL=Validate.js.map