"use strict";
exports.__esModule = true;
var constants_1 = require("./constants");
var errors = require("./errors");
// Required for markdown generation with JSDoc
/**
 * @module validators
 */
/* Type guards */
/**
 * Checks if input is an `Int8Array` of trit values; `-1, 0, 1`.
 *
 * @method isTrits
 *
 * @param {any} input
 *
 * @return {boolean}
 */
exports.isTrits = function (input) {
    if (input instanceof Int8Array) {
        for (var i = 0; i < input.length; i++) {
            if (!(input[i] === 0 || input[i] === -1 || input[i] === 1)) {
                return false;
            }
        }
        return true;
    }
    return false;
};
/**
 * Checks if trits are NULL.
 *
 * @method isNullTrits
 *
 * @param {Int8Array} trits
 *
 * @return {boolean}
 */
exports.isNullTrits = function (input) {
    if (input instanceof Int8Array) {
        if (input.length === 0) {
            return true;
        }
        for (var i = 0; i < input.length; i++) {
            if (input[i] !== 0) {
                return false;
            }
        }
        return true;
    }
    return false;
};
/**
 * Checks if input is correct trytes consisting of [9A-Z]; optionally validate length
 * @method isTrytes
 *
 * @param {string} trytes
 * @param {string | number} [length='1,']
 *
 * @return {boolean}
 */
exports.isTrytes = function (trytes, length) {
    if (length === void 0) { length = '1,'; }
    return typeof trytes === 'string' && new RegExp("^[9A-Z]{" + length + "}$").test(trytes);
};
/**
 * @method isTrytesOfExactLength
 *
 * @param {string} trytes
 * @param {number} length
 *
 * @return {boolean}
 */
exports.isTrytesOfExactLength = function (trytes, length) {
    return typeof trytes === 'string' && new RegExp("^[9A-Z]{" + length + "}$").test(trytes);
};
/**
 * @method isTrytesOfMaxLength
 *
 * @param {string} trytes
 * @param {number} length
 *
 * @return {boolean}
 */
exports.isTrytesOfMaxLength = function (trytes, length) {
    return typeof trytes === 'string' && new RegExp("^[9A-Z]{1," + length + "}$").test(trytes);
};
/**
 * Checks if input contains `9`s only.
 * @method isEmpty
 *
 * @param {string} hash
 *
 * @return {boolean}
 */
exports.isEmpty = function (trytes) { return typeof trytes === 'string' && /^[9]+$/.test(trytes); };
exports.isNinesTrytes = exports.isEmpty;
/**
 * Checks if input is correct hash (81 trytes) or address with checksum (90 trytes)
 *
 * @method isHash
 *
 * @param {string} hash
 *
 * @return {boolean}
 */
exports.isHash = function (hash) {
    return exports.isTrytesOfExactLength(hash, constants_1.HASH_TRYTE_SIZE) || exports.isTrytesOfExactLength(hash, constants_1.HASH_TRYTE_SIZE + 9);
}; // address w/ checksum is valid hash
/* Check if security level is valid positive integer */
exports.isSecurityLevel = function (security) {
    return Number.isInteger(security) && security > 0 && security < 4;
};
/**
 * Checks if input is valid input object. Address can be passed with or without checksum.
 * It does not validate the checksum.
 *
 * @method isInput
 *
 * @param {string} address
 *
 * @return {boolean}
 */
exports.isInput = function (input) {
    return exports.isHash(input.address) &&
        exports.isSecurityLevel(input.security) &&
        (typeof input.balance === 'undefined' || (Number.isInteger(input.balance) && input.balance > 0)) &&
        Number.isInteger(input.keyIndex) &&
        input.keyIndex >= 0;
};
/**
 * Checks that input is valid tag trytes.
 *
 * @method isTag
 *
 * @param {string} tag
 *
 * @return {boolean}
 */
exports.isTag = function (tag) { return exports.isTrytesOfMaxLength(tag, constants_1.TAG_TRYTE_SIZE); };
/**
 * Checks if input is valid `transfer` object.
 *
 * @method isTransfer
 *
 * @param {Transfer} transfer
 *
 * @return {boolean}
 */
exports.isTransfer = function (transfer) {
    return exports.isHash(transfer.address) &&
        Number.isInteger(transfer.value) &&
        transfer.value >= 0 &&
        (!transfer.message || exports.isTrytes(transfer.message, '0,')) &&
        (!transfer.tag || exports.isTag(transfer.tag));
};
/**
 * Checks that a given `URI` is valid
 *
 * Valid Examples:
 * - `udp://[2001:db8:a0b:12f0::1]:14265`
 * - `udp://[2001:db8:a0b:12f0::1]`
 * - `udp://8.8.8.8:14265`
 * - `udp://domain.com`
 * - `udp://domain2.com:14265`
 *
 * @method isUri
 *
 * @param {string} uri
 *
 * @return {boolean}
 */
exports.isUri = function (uri) {
    if (typeof uri !== 'string') {
        return false;
    }
    var getInside = /^(udp|tcp):\/\/([\[][^\]\.]*[\]]|[^\[\]:]*)[:]{0,1}([0-9]{1,}$|$)/i;
    var stripBrackets = /[\[]{0,1}([^\[\]]*)[\]]{0,1}/;
    var uriTest = /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))|(^\s*((?=.{1,255}$)(?=.*[A-Za-z].*)[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?)*)\s*$)/;
    return getInside.test(uri) && uriTest.test(stripBrackets.exec(getInside.exec(uri)[1])[1]);
};
/* Check if start & end options are valid */
exports.isStartEndOptions = function (_a) {
    var start = _a.start, end = _a.end;
    return !end || (start <= end && end < start + constants_1.MAX_INDEX_DIFF);
};
/* Checks all array items */
exports.isArray = function (f) { return function (x) {
    return Array.isArray(x) && x.length > 0 && x.every(function (y) { return f(y); });
}; };
/**
 * Runs each validator in sequence, and throws on the first occurence of invalid data.
 * Validators are passed as arguments and executed in given order.
 * You might want place `validate()` in promise chains before operations that require valid inputs,
 * taking advantage of built-in promise branching.
 *
 * @example
 *
 * ```js
 * try {
 *   validate([
 *     value, // Given value
 *     isTrytes, // Validator function
 *     'Invalid trytes' // Error message
 *   ])
 * } catch (err) {
 *   console.log(err.message) // 'Invalid trytes'
 * }
 * ```
 *
 * @method validate
 *
 * @throws {Error} error
 * @return {boolean}
 */
exports.validate = function () {
    var validators = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        validators[_i] = arguments[_i];
    }
    validators.forEach(function (validator) {
        if (Array.isArray(validator)) {
            var value = validator[0], isValid = validator[1], msg = validator[2];
            if (!isValid(value)) {
                throw new Error(msg + ": " + JSON.stringify(value, null, 1));
            }
        }
    });
    return true;
};
exports.arrayValidator = function (validator) { return function (arr, customMsg) {
    var _a = validator(arr[0]), _ = _a[0], // tslint:disable-line no-unused-variable
    isValid = _a[1], msg = _a[2];
    return [
        arr,
        function (x) { return Array.isArray(x) && x.every(function (value) { return isValid(value); }); },
        customMsg || msg,
    ];
}; };
exports.depthValidator = function (depth) { return [
    depth,
    function (n) { return Number.isInteger(n) && n > 0; },
    errors.INVALID_DEPTH,
]; };
exports.minWeightMagnitudeValidator = function (minWeightMagnitude) { return [
    minWeightMagnitude,
    Number.isInteger,
    errors.INVALID_MIN_WEIGHT_MAGNITUDE,
]; };
exports.seedValidator = function (seed) { return [seed, exports.isTrytes, errors.INVALID_SEED]; };
exports.securityLevelValidator = function (security) { return [
    security,
    exports.isSecurityLevel,
    errors.INVALID_SECURITY_LEVEL,
]; };
exports.inputValidator = function (input) { return [input, exports.isInput, errors.INVALID_INPUT]; };
exports.remainderAddressValidator = function (input) { return [input, exports.isHash, errors.INVALID_REMAINDER_ADDRESS]; };
exports.tagValidator = function (tag) { return [tag, exports.isTag, errors.INVALID_TAG]; };
exports.transferValidator = function (transfer) { return [transfer, exports.isTransfer, errors.INVALID_TRANSFER]; };
exports.hashValidator = function (hash, errorMessage) { return [
    hash,
    exports.isHash,
    errorMessage || errors.INVALID_HASH,
]; };
exports.trytesValidator = function (trytes, msg) { return [
    trytes,
    function (t) { return (length ? exports.isTrytesOfExactLength(t, length) : exports.isTrytes(t)); },
    msg || errors.INVALID_TRYTES,
]; };
exports.uriValidator = function (uri) { return [uri, exports.isUri, errors.INVALID_URI]; };
exports.integerValidator = function (integer, msg) { return [
    integer,
    Number.isInteger,
    msg || errors.NOT_INT,
]; };
exports.indexValidator = function (index) { return [index, Number.isInteger, errors.INVALID_INDEX]; };
exports.startOptionValidator = function (start) { return [
    start,
    function (s) { return Number.isInteger(s) && s >= 0; },
    errors.INVALID_START_OPTION,
]; };
exports.startEndOptionsValidator = function (options) { return [
    options,
    exports.isStartEndOptions,
    errors.INVALID_START_END_OPTIONS,
]; };
exports.getInputsThresholdValidator = function (threshold) { return [
    threshold,
    function (s) { return Number.isInteger(s) && s >= 0; },
    errors.INVALID_THRESHOLD,
]; };
exports.stringify = function (value) {
    return JSON.stringify(value, null, 1);
};
//# sourceMappingURL=guards.js.map