"use strict";
/// <reference path="../../typings/main.d.ts" />
Object.defineProperty(exports, "__esModule", { value: true });
var _toString = Object.prototype.toString;
function isDateType(check) {
    return _toString.call(check) === '[object Date]' && !isNaN(check.getTime());
}
function isBooleanType(check) {
    return typeof check === 'boolean';
}
function isStringType(check) {
    return typeof check === 'string';
}
function isIntegerType(check) {
    return typeof check === 'number' && check % 1 === 0;
}
function isNumberType(check) {
    return typeof check === 'number' && isFinite(check);
}
function isMinimum(min) {
    return function (check) {
        return check >= min;
    };
}
function isMaximum(max) {
    return function (check) {
        return check <= max;
    };
}
function isMinimumLength(min) {
    return function (check) {
        return Buffer.byteLength(check) >= min;
    };
}
function isMaximumLength(max) {
    return function (check) {
        return Buffer.byteLength(check) <= max;
    };
}
function isEnum(values) {
    if (values && values.length != 0) {
        return function (check) {
            return values.indexOf(check) > -1;
        };
    }
    else {
        return function (check) {
            return true;
        };
    }
}
function isPattern(pattern) {
    var regexp = (typeof pattern === 'string') ? new RegExp(pattern) : pattern;
    return regexp.test.bind(regexp);
}
function toValidationResult(valid, key, value, rule, attr) {
    return {
        valid: valid,
        rule: rule,
        attr: attr,
        value: value,
        key: key
    };
}
function toValidationFunction(parameter, rules) {
    var validations = [];
    Object.keys(parameter).forEach(function (name) {
        var rule = rules[name];
        if (!rule) {
            return;
        }
        var value = parameter[name];
        validations.push([name, rule(value, name), value]);
    });
    return function (value, key, src) {
        for (var i = 0; i < validations.length; i++) {
            var validation = validations[i];
            var name = validation[0];
            var fn = validation[1];
            var attr = validation[2];
            var valid = fn(value, key, src);
            if (!valid) {
                return toValidationResult(false, key, value, name, attr);
            }
        }
        return toValidationResult(true, key, value);
    };
}
function toValidation(parameter, rules, types) {
    var parameters = Array.isArray(parameter) ? parameter : [parameter];
    var isOptional = !parameters.length;
    var simpleValidations = [];
    var repeatValidations = [];
    parameters.forEach(function (parameter) {
        var validation = [parameter.type || 'string', toValidationFunction(parameter, rules)];
        if (!parameter.required) {
            isOptional = true;
        }
        if (parameter.repeat) {
            repeatValidations.push(validation);
        }
        else {
            simpleValidations.push(validation);
        }
    });
    return function (value, key, src) {
        if (value == null) {
            return toValidationResult(isOptional, key, value, 'required', !isOptional);
        }
        var isArray = Array.isArray(value);
        var values = isArray ? value : [value];
        var validations = isArray ? repeatValidations : simpleValidations;
        if (!validations.length) {
            return toValidationResult(false, key, value, 'repeat', !isArray);
        }
        var response = null;
        var originalValue = value;
        validations.some(function (validation) {
            var isValidType = values.every(function (value) {
                var paramType = validation[0];
                var isValidType = types[paramType] && types[paramType](value, key, src);
                if (!isValidType) {
                    response = toValidationResult(false, key, originalValue, 'type', paramType);
                }
                return isValidType;
            });
            if (!isValidType) {
                return false;
            }
            values.every(function (value) {
                var fn = validation[1];
                response = fn(value, key);
                return response.valid;
            });
            return true;
        });
        return response;
    };
}
function validate() {
    var TYPES = {
        date: isDateType,
        number: isNumberType,
        integer: isIntegerType,
        boolean: isBooleanType,
        string: isStringType
    };
    var RULES = {
        minimum: isMinimum,
        maximum: isMaximum,
        minLength: isMinimumLength,
        maxLength: isMaximumLength,
        'enum': isEnum,
        pattern: isPattern
    };
    function rule(parameter) {
        return toValidation(parameter, RULES, TYPES);
    }
    var v;
    var validate = function (parameterMap) {
        if (!parameterMap) {
            return function (check) {
                return { valid: true, errors: [] };
            };
        }
        var validations = {};
        Object.keys(parameterMap).forEach(function (key) {
            validations[key] = rule(parameterMap[key]);
        });
        return function (src) {
            src = src || {};
            var errors = Object.keys(validations)
                .map(function (param) {
                var value = src[param];
                var fn = validations[param];
                return fn(value, param, src);
            })
                .filter(function (result) {
                return !result.valid;
            });
            return {
                valid: errors.length === 0,
                errors: errors
            };
        };
    };
    v = validate;
    v.rule = rule;
    v.TYPES = TYPES;
    v.RULES = RULES;
    return v;
}
exports.validate = validate;
// export = validate
//# sourceMappingURL=raml-validate.js.map