"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ts = require("./typesystem");
var bignumber_js_1 = require("bignumber.js");
var messageRegistry = ts.messageRegistry;
var su = require("./schemaUtil");
var _ = require("underscore");
var typesystem_1 = require("./typesystem");
var typesystem_2 = require("./typesystem");
var metainfo_1 = require("./metainfo");
var metainfo_2 = require("./metainfo");
var metainfo_3 = require("./metainfo");
/**
 * this class is an abstract super type for every constraint that can select properties from objects
 */
var MatchesProperty = /** @class */ (function (_super) {
    __extends(MatchesProperty, _super);
    function MatchesProperty(_type, optional) {
        if (optional === void 0) { optional = false; }
        var _this = _super.call(this) || this;
        _this._type = _type;
        _this.optional = optional;
        return _this;
    }
    MatchesProperty.prototype.matches = function (s) {
        return false;
    };
    MatchesProperty.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(MatchesProperty.CLASS_IDENTIFIER_MatchesProperty);
    };
    MatchesProperty.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), MatchesProperty.CLASS_IDENTIFIER_MatchesProperty);
    };
    MatchesProperty.prototype.check = function (i, p) {
        throw new Error(messageRegistry.SHOULD_BE_NEVER_CALLED.message);
    };
    MatchesProperty.prototype.patchPath = function (p, name) {
        if (!p) {
            return { name: name };
        }
        else {
            var c = p;
            var r = null;
            var cp = null;
            while (c) {
                if (!r) {
                    r = { name: c.name };
                    cp = r;
                }
                else {
                    var news = { name: c.name };
                    cp.child = news;
                    c = c.child;
                    cp = news;
                }
            }
            r.child = { name: name };
            return r;
        }
    };
    MatchesProperty.prototype.validateProp = function (i, n, t, q) {
        var vl = i[n];
        var st = t.validate(vl, false, false);
        if (!st.isOk()) {
            if (t.isUnknown() || t.isRecurrent()) {
                var s = ts.error(messageRegistry.VALIDATING_AGAINST_UNKNOWN, this, { typeName: t.name() });
                ts.setValidationPath(s, this.patchPath(q, n));
                return s;
            }
            var s = new typesystem_2.Status(typesystem_2.Status.OK, "", "", this);
            st.getErrors().forEach(function (x) { return s.addSubStatus(x); });
            ts.setValidationPath(s, this.patchPath(q, n));
            return s;
        }
        return ts.ok();
    };
    MatchesProperty.prototype.validateSelfIndividual = function (st, registry) {
        return validatePropertyType(this._type, this.propId(), registry, this, false);
    };
    MatchesProperty.prototype.range = function () {
        return this._type;
    };
    MatchesProperty.prototype.isOptional = function () {
        return this.optional;
    };
    MatchesProperty.CLASS_IDENTIFIER_MatchesProperty = "restrictions.MatchesProperty";
    return MatchesProperty;
}(ts.Constraint));
exports.MatchesProperty = MatchesProperty;
var MatchToSchema = /** @class */ (function (_super) {
    __extends(MatchToSchema, _super);
    function MatchToSchema(_value, provider) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        _this.provider = provider;
        return _this;
    }
    MatchToSchema.prototype.value = function () {
        return this._value;
    };
    MatchToSchema.prototype.check = function (i) {
        var so = null;
        var strVal = this.value();
        if (strVal.charAt(0) == "{") {
            try {
                so = su.getJSONSchema(strVal, this.provider);
            }
            catch (e) {
                if (ts.ValidationError.isInstance(e)) {
                    var ve = e;
                    var severity = ve.isWarning ? ts.Status.WARNING : ts.Status.ERROR;
                    var err = ts.error(ve.messageEntry, this, ve.parameters, severity, ve.parameters);
                    //err.setRange(ve.range); the range belongs to schema node, not to example
                    return err;
                }
                return ts.error(messageRegistry.INCORRECT_SCHEMA, this, { msg: e.message });
            }
        }
        if (strVal.charAt(0) == "<") {
            try {
                so = su.getXMLSchema(strVal, this.provider);
            }
            catch (e) {
                return ts.ok();
            }
        }
        if (so) {
            try {
                if (typeof i == "string") {
                    so.validate(i);
                }
                else {
                    so.validateObject(i);
                }
            }
            catch (e) {
                if (ts.ValidationError.isInstance(e)) {
                    var ve = e;
                    var status_1 = ts.Status.ERROR;
                    if (ve.isWarning) {
                        status_1 = ts.Status.WARNING;
                    }
                    var st = ts.error(ve.messageEntry, this, ve.parameters, status_1);
                    st.setInternalRange(ve.internalRange);
                    st.setInternalPath(ts.toValidationPath(ve.internalPath));
                    st.setFilePath(ve.filePath);
                    if (!ve.additionalErrors || ve.additionalErrors.length == 0) {
                        return st;
                    }
                    var result = ts.ok();
                    result.addSubStatus(st);
                    for (var _i = 0, _a = ve.additionalErrors; _i < _a.length; _i++) {
                        var ae = _a[_i];
                        var st1 = ts.error(ae.messageEntry, this, ae.parameters, status_1);
                        st1.setInternalRange(ae.internalRange);
                        st1.setInternalPath(ts.toValidationPath(ae.internalPath));
                        st1.setFilePath(ae.filePath);
                        result.addSubStatus(st1);
                    }
                    return result;
                }
                if (e.message == "!_PERF_!") {
                    return ts.error(messageRegistry.UNABLE_TO_VALIDATE_XML, this, {}, ts.Status.WARNING);
                }
                if (e.message == "Maximum call stack size exceeded") {
                    return ts.error(messageRegistry.CIRCULAR_REFS_IN_JSON_SCHEMA, this);
                }
                return ts.error(messageRegistry.EXAMPLE_SCHEMA_FAILURE, this, { msg: e.message });
            }
            //validate using classical schema;
        }
        return ts.ok();
    };
    MatchToSchema.prototype.facetName = function () {
        return "schema";
    };
    MatchToSchema.prototype.requiredType = function () {
        return ts.EXTERNAL;
    };
    return MatchToSchema;
}(ts.Constraint));
exports.MatchToSchema = MatchToSchema;
/**
 * this is a constraint which checks that object has no unknown properties if at has not additional properties
 */
var KnownPropertyRestriction = /** @class */ (function (_super) {
    __extends(KnownPropertyRestriction, _super);
    function KnownPropertyRestriction(_value) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        return _this;
    }
    KnownPropertyRestriction.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(KnownPropertyRestriction.CLASS_IDENTIFIER_KnownPropertyRestriction);
    };
    KnownPropertyRestriction.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), KnownPropertyRestriction.CLASS_IDENTIFIER_KnownPropertyRestriction);
    };
    KnownPropertyRestriction.prototype.facetName = function () {
        return "closed";
    };
    KnownPropertyRestriction.prototype.requiredType = function () {
        return ts.OBJECT;
    };
    KnownPropertyRestriction.prototype.value = function () {
        return this._value;
    };
    KnownPropertyRestriction.prototype.patchOwner = function (t) {
        this._owner = t;
    };
    KnownPropertyRestriction.prototype.check = function (i) {
        var _this = this;
        if (this._value === false) {
            if (i && typeof i == 'object' && !Array.isArray(i)) {
                var nm = {};
                Object.getOwnPropertyNames(i).forEach(function (n) { return nm[n] = true; });
                var mp = this.owner().knownProperties();
                Object.getOwnPropertyNames(i).forEach(function (p) {
                    mp.forEach(function (v) {
                        if (v.matches(p)) {
                            delete nm[p];
                        }
                    });
                });
                var unknownPropertyNames = Object.keys(nm);
                if ((this.owner().hasPropertiesFacet() || mp.length > 0) && unknownPropertyNames.length > 0) {
                    var s = new ts.Status(ts.Status.OK, "", "", this);
                    unknownPropertyNames.forEach(function (x) {
                        var err = ts.error(messageRegistry.UNKNOWN_PROPERTY, _this, { propName: x });
                        ts.setValidationPath(err, { name: x });
                        s.addSubStatus(err);
                    });
                    return s;
                }
            }
        }
        return ts.ok();
    };
    KnownPropertyRestriction.prototype.composeWith = function (restriction) {
        if (!this._value) {
            return null;
        }
        if (restriction instanceof KnownPropertyRestriction) {
            var mm = restriction;
            if (_.isEqual(this.owner().propertySet(), mm.owner().propertySet())) {
                return mm;
            }
        }
        if (restriction instanceof HasProperty) {
            var ps = restriction;
            var name = ps.value();
            var allowedPropertySet = this.owner().propertySet();
            if (allowedPropertySet.indexOf(name) == -1) {
                return this.nothing(ps);
            }
        }
    };
    KnownPropertyRestriction.CLASS_IDENTIFIER_KnownPropertyRestriction = "typesystem.KnownPropertyRestriction";
    return KnownPropertyRestriction;
}(ts.Constraint));
exports.KnownPropertyRestriction = KnownPropertyRestriction;
/**
 * this constaint checks that object has a particular property
 */
var HasProperty = /** @class */ (function (_super) {
    __extends(HasProperty, _super);
    function HasProperty(name) {
        var _this = _super.call(this) || this;
        _this.name = name;
        return _this;
    }
    HasProperty.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(HasProperty.CLASS_IDENTIFIER_HasProperty);
    };
    HasProperty.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), HasProperty.CLASS_IDENTIFIER_HasProperty);
    };
    HasProperty.prototype.check = function (i) {
        if (i && typeof i == 'object' && !Array.isArray(i)) {
            if (i.hasOwnProperty(this.name)) {
                return ts.ok();
            }
            return ts.error(messageRegistry.REQUIRED_PROPERTY_MISSING, this, { propName: this.name });
        }
        return ts.ok();
    };
    HasProperty.prototype.requiredType = function () {
        return ts.OBJECT;
    };
    HasProperty.prototype.facetName = function () {
        return "hasProperty";
    };
    HasProperty.prototype.value = function () {
        return this.name;
    };
    HasProperty.prototype.composeWith = function (r) {
        if (r instanceof HasProperty) {
            var hp = r;
            if (hp.name === this.name) {
                return this;
            }
        }
        return null;
    };
    HasProperty.CLASS_IDENTIFIER_HasProperty = "restrictions.HasProperty";
    return HasProperty;
}(ts.Constraint));
exports.HasProperty = HasProperty;
/**
 * this constraint checks that property has a particular tyoe if exists
 */
var PropertyIs = /** @class */ (function (_super) {
    __extends(PropertyIs, _super);
    function PropertyIs(name, type, optional) {
        if (optional === void 0) { optional = false; }
        var _this = _super.call(this, type, optional) || this;
        _this.name = name;
        _this.type = type;
        return _this;
    }
    PropertyIs.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(PropertyIs.CLASS_IDENTIFIER_PropertyIs);
    };
    PropertyIs.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), PropertyIs.CLASS_IDENTIFIER_PropertyIs);
    };
    PropertyIs.prototype.matches = function (s) {
        return s === this.name;
    };
    PropertyIs.prototype.path = function () {
        return this.name;
    };
    PropertyIs.prototype.check = function (i, p) {
        if (i && typeof i === "object") {
            if (i.hasOwnProperty(this.name)) {
                var st = this.validateProp(i, this.name, this.type, p);
                return st;
            }
        }
        return ts.ok();
    };
    PropertyIs.prototype.requiredType = function () {
        return ts.OBJECT;
    };
    PropertyIs.prototype.propId = function () {
        return this.name;
    };
    PropertyIs.prototype.propertyName = function () {
        return this.name;
    };
    PropertyIs.prototype.facetName = function () {
        return "propertyIs";
    };
    PropertyIs.prototype.value = function () {
        return this.type;
    };
    PropertyIs.prototype.composeWith = function (t) {
        if (t instanceof PropertyIs) {
            var pi = t;
            if (pi.name === this.name) {
                if (this.type.typeFamily().indexOf(pi.type) != -1) {
                    return pi;
                }
                if (pi.type.typeFamily().indexOf(this.type) != -1) {
                    return this;
                }
                setAnotherRestrictionComponent(t);
                var intersectionType = this.intersect(this.type, pi.type);
                try {
                    var is = intersectionType.checkConfluent();
                    if (!is.isOk()) {
                        var rc = is;
                        return rc.toRestriction();
                    }
                    return new PropertyIs(this.name, intersectionType);
                }
                finally {
                    this.release(intersectionType);
                }
            }
        }
        return null;
    };
    PropertyIs.CLASS_IDENTIFIER_PropertyIs = "restrictions.PropertyIs";
    return PropertyIs;
}(MatchesProperty));
exports.PropertyIs = PropertyIs;
var anotherSource = [];
function anotherRestrictionComponent() {
    return anotherSource.length > 0 ? anotherSource[anotherSource.length - 1] : null;
}
exports.anotherRestrictionComponent = anotherRestrictionComponent;
function setAnotherRestrictionComponent(src) {
    var owner;
    while (src) {
        owner = src.owner();
        if (owner instanceof ts.InheritedType) {
            src = owner.contextMeta();
        }
        else {
            src = null;
        }
    }
    anotherSource.push(owner);
}
function releaseAnotherRestrictionComponent(l) {
    if (l === void 0) { l = 0; }
    while (anotherSource.length > l) {
        anotherSource.pop();
    }
}
exports.releaseAnotherRestrictionComponent = releaseAnotherRestrictionComponent;
function anotherRestrictionComponentsCount() {
    return anotherSource.length;
}
exports.anotherRestrictionComponentsCount = anotherRestrictionComponentsCount;
/**
 * this cosnstraint checks that map property values passes to particular type if exists
 */
var MapPropertyIs = /** @class */ (function (_super) {
    __extends(MapPropertyIs, _super);
    function MapPropertyIs(regexp, type, optional) {
        if (optional === void 0) { optional = false; }
        var _this = _super.call(this, type, optional) || this;
        _this.regexp = regexp;
        _this.type = type;
        return _this;
    }
    MapPropertyIs.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(MapPropertyIs.CLASS_IDENTIFIER_MapPropertyIs);
    };
    MapPropertyIs.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), MapPropertyIs.CLASS_IDENTIFIER_MapPropertyIs);
    };
    MapPropertyIs.prototype.path = function () {
        return "/" + this.regexp + "/";
    };
    MapPropertyIs.prototype.matches = function (s) {
        if (s.match(this.regexp)) {
            return true;
        }
        return false;
    };
    MapPropertyIs.prototype.requiredType = function () {
        return ts.OBJECT;
    };
    MapPropertyIs.prototype.propId = function () {
        return '[' + this.regexp + ']';
    };
    MapPropertyIs.prototype.facetName = function () {
        return "mapPropertyIs";
    };
    MapPropertyIs.prototype.value = function () {
        return this.type;
    };
    MapPropertyIs.prototype.regexpValue = function () {
        return this.regexp;
    };
    MapPropertyIs.prototype.validateSelfIndividual = function (st, t) {
        var m = this.checkValue();
        if (m) {
            return ts.error(messageRegistry.INVALID_REGEXP, this, { msg: m });
        }
        return _super.prototype.validateSelfIndividual.call(this, st, t);
    };
    MapPropertyIs.prototype.checkValue = function () {
        try {
            new RegExp(this.regexp);
        }
        catch (e) {
            return e.message;
        }
        return null;
    };
    MapPropertyIs.prototype.composeWith = function (t) {
        if (t instanceof MapPropertyIs) {
            var pi = t;
            if (pi.regexp === this.regexp) {
                if (this.type.typeFamily().indexOf(pi.type) != -1) {
                    return pi;
                }
                if (pi.type.typeFamily().indexOf(this.type) != -1) {
                    return this;
                }
                var intersectionType = this.intersect(this.type, pi.type);
                try {
                    var is = intersectionType.checkConfluent();
                    if (!is.isOk()) {
                        var rc = is;
                        return rc.toRestriction();
                    }
                    return new MapPropertyIs(this.regexp, intersectionType);
                }
                finally {
                    this.release(intersectionType);
                }
            }
        }
        return null;
    };
    MapPropertyIs.prototype.check = function (i, p) {
        if (i) {
            if (typeof i == 'object') {
                var fixedProperties = {};
                if (this._owner != null) {
                    this._owner.meta().filter(function (x) { return x instanceof PropertyIs; }).forEach(function (x) {
                        fixedProperties[x.propertyName()] = true;
                    });
                }
                var rs = new ts.Status(ts.Status.OK, "", "", this);
                for (var _i = 0, _a = Object.getOwnPropertyNames(i); _i < _a.length; _i++) {
                    var n = _a[_i];
                    if (fixedProperties[n]) {
                        continue;
                    }
                    if (n.match(this.regexp)) {
                        var stat = this.validateProp(i, n, this.type, p);
                        if (!stat.isOk()) {
                            rs.addSubStatus(stat);
                        }
                    }
                }
                return rs;
            }
        }
        return ts.ok();
    };
    MapPropertyIs.CLASS_IDENTIFIER_MapPropertyIs = "restrictions.MapPropertyIs";
    return MapPropertyIs;
}(MatchesProperty));
exports.MapPropertyIs = MapPropertyIs;
/**
 * this constraint tests that additional property
 */
var AdditionalPropertyIs = /** @class */ (function (_super) {
    __extends(AdditionalPropertyIs, _super);
    function AdditionalPropertyIs(type, optional) {
        if (optional === void 0) { optional = false; }
        var _this = _super.call(this, type, optional) || this;
        _this.type = type;
        return _this;
    }
    AdditionalPropertyIs.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(AdditionalPropertyIs.CLASS_IDENTIFIER_AdditionalPropertyIs);
    };
    AdditionalPropertyIs.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), AdditionalPropertyIs.CLASS_IDENTIFIER_AdditionalPropertyIs);
    };
    AdditionalPropertyIs.prototype.path = function () {
        return "/.*/";
    };
    AdditionalPropertyIs.prototype.matches = function (s) {
        return true;
    };
    AdditionalPropertyIs.prototype.requiredType = function () {
        return ts.OBJECT;
    };
    AdditionalPropertyIs.prototype.propId = function () {
        return '[]';
    };
    AdditionalPropertyIs.prototype.facetName = function () {
        return "additionalProperties";
    };
    AdditionalPropertyIs.prototype.value = function () {
        return this.type;
    };
    AdditionalPropertyIs.prototype.match = function (n) {
        var all = this.owner().metaOfType(PropertyIs);
        var map = this.owner().metaOfType(MapPropertyIs);
        for (var i = 0; i < all.length; i++) {
            if (all[i].matches(n)) {
                return true;
            }
        }
        for (var i = 0; i < map.length; i++) {
            if (map[i].matches(n)) {
                return true;
            }
        }
        return false;
    };
    AdditionalPropertyIs.prototype.composeWith = function (t) {
        if (t instanceof AdditionalPropertyIs) {
            var pi = t;
            if (this.type.typeFamily().indexOf(pi.type) != -1) {
                return pi;
            }
            if (pi.type.typeFamily().indexOf(this.type) != -1) {
                return this;
            }
            var intersectionType = this.intersect(this.type, pi.type);
            try {
                var is = intersectionType.checkConfluent();
                if (!is.isOk()) {
                    var rc = is;
                    return rc.toRestriction();
                }
                return new AdditionalPropertyIs(intersectionType);
            }
            finally {
                this.release(intersectionType);
            }
        }
        return null;
    };
    AdditionalPropertyIs.prototype.check = function (i, p) {
        var _this = this;
        var t = this.type;
        var res = new ts.Status(ts.Status.OK, "", "", this);
        if (i && typeof i === "object") {
            Object.getOwnPropertyNames(i).forEach(function (n) {
                if (!_this.match(n)) {
                    var stat = _this.validateProp(i, n, t, p);
                    if (!stat.isOk()) {
                        res.addSubStatus(stat);
                    }
                }
            });
        }
        return res;
    };
    AdditionalPropertyIs.CLASS_IDENTIFIER_AdditionalPropertyIs = "restrictions.AdditionalPropertyIs";
    return AdditionalPropertyIs;
}(MatchesProperty));
exports.AdditionalPropertyIs = AdditionalPropertyIs;
/**
 * common super type for a simple restrictions
 */
var FacetRestriction = /** @class */ (function (_super) {
    __extends(FacetRestriction, _super);
    function FacetRestriction() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    /**
     * Extension of requiredType() method for the case when there are more than a single type
     * hierarchy roots to cover.
     * requiredType() should return the common superclass for the list.
     *
     * @returns {Array} of types or empty list of there is only a single type set by requiredType() method
     */
    FacetRestriction.prototype.requiredTypes = function () {
        return [];
    };
    FacetRestriction.prototype.checkOwner = function (requiredType) {
        if (this.owner().oneMeta(metainfo_2.SkipValidation)) {
            return true;
        }
        var ownerIsCorrect = false;
        if (requiredType.isUnion()) {
            var family = requiredType.typeFamily();
            for (var _i = 0, family_1 = family; _i < family_1.length; _i++) {
                var tp = family_1[_i];
                if (this.owner().isSubTypeOf(tp)) {
                    ownerIsCorrect = true;
                    break;
                }
            }
        }
        else {
            ownerIsCorrect = this.owner().isSubTypeOf(requiredType);
        }
        return ownerIsCorrect;
    };
    FacetRestriction.prototype.validateSelfIndividual = function (superStatus, registry) {
        var _this = this;
        var ownerIsCorrect = false;
        if (this.checkOwner(this.requiredType())) {
            if (this.requiredTypes() && this.requiredTypes().length > 0) {
                var owner = this.owner();
                var correctRequiredSuperType = _.find(this.requiredTypes(), function (requiredType) { return _this.checkOwner(requiredType); });
                if (correctRequiredSuperType) {
                    ownerIsCorrect = true;
                }
            }
            else {
                ownerIsCorrect = true;
            }
        }
        var rs;
        if (!ownerIsCorrect) {
            var typeNames = this.requiredType().name();
            if (this.requiredTypes() && this.requiredTypes().length > 0) {
                typeNames = "[" + this.requiredTypes().map(function (requiredType) { return requiredType.name(); }).join() + "]";
            }
            var rs = ts.error(messageRegistry.FACET_USAGE_RESTRICTION, this, {
                facetName: this.facetName(),
                typeNames: typeNames
            });
        }
        else {
            rs = this.checkValue();
        }
        if (rs && !rs.isOk()) {
            ts.setValidationPath(rs, { name: this.facetName() });
            return rs;
        }
        var statuses = [superStatus, rs].filter(function (x) { return x && !x.isOk(); });
        if (statuses.length == 0) {
            return ts.ok();
        }
        else if (statuses.length == 1) {
            return statuses[0];
        }
        else {
            var result = ts.ok();
            for (var _i = 0, statuses_1 = statuses; _i < statuses_1.length; _i++) {
                var status = statuses_1[_i];
                result.addSubStatus(status);
            }
            return result;
        }
    };
    return FacetRestriction;
}(ts.Constraint));
exports.FacetRestriction = FacetRestriction;
/**
 * abstract super type for every min max restriction
 */
var MinMaxRestriction = /** @class */ (function (_super) {
    __extends(MinMaxRestriction, _super);
    function MinMaxRestriction(_facetName, _value, _max, _opposite, _requiredType, _isInt) {
        var _this = _super.call(this) || this;
        _this._facetName = _facetName;
        _this._value = _value;
        _this._max = _max;
        _this._opposite = _opposite;
        _this._requiredType = _requiredType;
        _this._isInt = _isInt;
        return _this;
    }
    MinMaxRestriction.prototype.facetName = function () {
        return this._facetName;
    };
    MinMaxRestriction.prototype.isIntConstraint = function () {
        return this._isInt;
    };
    MinMaxRestriction.prototype.isMax = function () {
        return this._max;
    };
    MinMaxRestriction.prototype.value = function () {
        return this._value;
    };
    MinMaxRestriction.prototype.check = function (i) {
        var o = this.extractValue(i);
        if (typeof o == 'number') {
            if (this.isMax()) {
                if (this.value() < o) {
                    return this.createError();
                }
            }
            else {
                if (this.value() > o) {
                    return this.createError();
                }
            }
        }
        return ts.ok();
    };
    MinMaxRestriction.prototype.createError = function () {
        return new typesystem_2.Status(typesystem_2.Status.ERROR, messageRegistry.MINMAX_RESTRICTION_VIOLATION.code, this.toString(), this);
    };
    MinMaxRestriction.prototype.minValue = function () {
        if (this._isInt) {
            return 0;
        }
        return Number.NEGATIVE_INFINITY;
    };
    MinMaxRestriction.prototype.requiredType = function () {
        return this._requiredType;
    };
    MinMaxRestriction.prototype.checkValue = function () {
        if (typeof this._value != "number") {
            return ts.error(messageRegistry.FACET_REQUIRE_NUMBER, this, { facetName: this.facetName() }, ts.Status.ERROR, true);
        }
        if (this.isIntConstraint()) {
            if (!new bignumber_js_1.BigNumber(this.value().toString()).isInteger()) {
                return ts.error(messageRegistry.FACET_REQUIRE_INTEGER, this, { facetName: this.facetName() }, ts.Status.ERROR, true);
            }
        }
        if (this.value() < this.minValue()) {
            return ts.error(messageRegistry.MIN_VALUE, this, {
                facetName: this.facetName(),
                minValue: this.minValue()
            }, ts.Status.ERROR, true);
        }
    };
    MinMaxRestriction.prototype.composeWith = function (t) {
        if (t instanceof MinMaxRestriction) {
            var mx = t;
            if (mx.facetName() == this.facetName()) {
                if (mx.isMax() == this.isMax()) {
                    if (this.isMax()) {
                        if (this.value() > mx.value()) {
                            return mx;
                        }
                        else {
                            return this;
                        }
                    }
                    else {
                        if (this.value() < mx.value()) {
                            return mx;
                        }
                        else {
                            return this;
                        }
                    }
                }
            }
            if (mx.facetName() === this._opposite) {
                if (this.isMax()) {
                    if (mx.value() > this.value()) {
                        return this.nothing(t);
                    }
                }
                else {
                    if (mx.value() < this.value()) {
                        return this.nothing(t);
                    }
                }
            }
        }
        return null;
    };
    MinMaxRestriction.prototype.facetPath = function () {
        var arr = [this.facetName()];
        var owner = this._owner;
        if (owner != null) {
            if (owner instanceof ts.InheritedType) {
                var it = owner;
                arr = ts.typePath(it).concat(arr);
            }
        }
        return arr.join(".");
    };
    MinMaxRestriction.prototype.toString = function () {
        return "'" + this.facetPath() + "=" + this.value() + "' i.e. " + this.textMessagePart() + " " + this.value();
    };
    MinMaxRestriction.prototype.conflictMessage = function (otherPath, otherValue) {
        var arr = this.isMax() ? ["less", "higher"] : ["higher", "less"];
        return "['" + this.facetPath() + "=" + this.value() + "' is " + arr[0] + " than '" + otherPath + "=" + otherValue + "'. The " + this._opposite + " cannot be " + arr[1] + " than the " + this.facetName() + ".]";
    };
    return MinMaxRestriction;
}(FacetRestriction));
exports.MinMaxRestriction = MinMaxRestriction;
var MultipleOf = /** @class */ (function (_super) {
    __extends(MultipleOf, _super);
    function MultipleOf(_value) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        return _this;
    }
    MultipleOf.prototype.value = function () {
        return this._value;
    };
    MultipleOf.prototype.check = function (o) {
        if (typeof o == 'number') {
            var devided = new bignumber_js_1.BigNumber(o.toString());
            var devisor = new bignumber_js_1.BigNumber(this.value().toString());
            var quotient = devided.dividedBy(devisor);
            if (!quotient.isInteger()) {
                return ts.error(messageRegistry.EVEN_RATIO, this, { val1: o, val2: this.value() });
            }
        }
        return ts.ok();
    };
    MultipleOf.prototype.composeWith = function (t) {
        return null;
    };
    MultipleOf.prototype.facetName = function () {
        return "multipleOf";
    };
    MultipleOf.prototype.checkValue = function () {
        if (typeof this._value != "number") {
            return ts.error(messageRegistry.FACET_REQUIRE_NUMBER, this, { facetName: this.facetName() }, ts.Status.ERROR, true);
        }
        else {
            if (this._value <= 0) {
                return ts.error(messageRegistry.VALUE_SHOULD_BE_POSITIVE, this, { facetName: this.facetName() }, ts.Status.ERROR, true);
            }
        }
        return null;
    };
    MultipleOf.prototype.requiredType = function () {
        return ts.NUMBER;
    };
    return MultipleOf;
}(FacetRestriction));
exports.MultipleOf = MultipleOf;
/**
 * maximum  constraint
 */
var Maximum = /** @class */ (function (_super) {
    __extends(Maximum, _super);
    function Maximum(val) {
        return _super.call(this, "maximum", val, true, "minimum", ts.NUMBER, false) || this;
    }
    Maximum.prototype.extractValue = function (i) {
        return i;
    };
    Maximum.prototype.textMessagePart = function () {
        return messageRegistry.VALUE_SHOULD_NOT_BE_MORE.message;
    };
    return Maximum;
}(MinMaxRestriction));
exports.Maximum = Maximum;
/**
 * minimum constraint
 */
var Minimum = /** @class */ (function (_super) {
    __extends(Minimum, _super);
    function Minimum(val) {
        return _super.call(this, "minimum", val, false, "maximum", ts.NUMBER, false) || this;
    }
    Minimum.prototype.extractValue = function (i) {
        return i;
    };
    Minimum.prototype.textMessagePart = function () {
        return messageRegistry.VALUE_SHOULD_NOT_BE_LESS.message;
    };
    return Minimum;
}(MinMaxRestriction));
exports.Minimum = Minimum;
/**
 * max items cosntraint
 */
var MaxItems = /** @class */ (function (_super) {
    __extends(MaxItems, _super);
    function MaxItems(val) {
        return _super.call(this, "maxItems", val, true, "minItems", ts.ARRAY, true) || this;
    }
    MaxItems.prototype.extractValue = function (i) {
        if (Array.isArray(i)) {
            return i.length;
        }
    };
    MaxItems.prototype.textMessagePart = function () {
        return messageRegistry.ARRAY_ITEMS_COUNT_SHOULD_NOT_BE_MORE.message;
    };
    return MaxItems;
}(MinMaxRestriction));
exports.MaxItems = MaxItems;
/**
 * min items cosntraint
 */
var MinItems = /** @class */ (function (_super) {
    __extends(MinItems, _super);
    function MinItems(val) {
        return _super.call(this, "minItems", val, false, "maxItems", ts.ARRAY, true) || this;
    }
    MinItems.prototype.extractValue = function (i) {
        if (Array.isArray(i)) {
            return i.length;
        }
    };
    MinItems.prototype.textMessagePart = function () {
        return messageRegistry.ARRAY_ITEMS_COUNT_SHOULD_NOT_BE_LESS.message;
    };
    return MinItems;
}(MinMaxRestriction));
exports.MinItems = MinItems;
/**
 * max length
 */
var MaxLength = /** @class */ (function (_super) {
    __extends(MaxLength, _super);
    function MaxLength(val) {
        return _super.call(this, "maxLength", val, true, "minLength", new ts.UnionType("string and file", [ts.STRING, ts.FILE]), true) || this;
    }
    MaxLength.prototype.extractValue = function (i) {
        if (typeof i == 'string') {
            return i.length;
        }
        return 0;
    };
    MaxLength.prototype.textMessagePart = function () {
        return messageRegistry.STRING_SHOULD_NOT_BE_MORE.message;
    };
    return MaxLength;
}(MinMaxRestriction));
exports.MaxLength = MaxLength;
/**
 * min length
 */
var MinLength = /** @class */ (function (_super) {
    __extends(MinLength, _super);
    function MinLength(val) {
        return _super.call(this, "minLength", val, false, "maxLength", new ts.UnionType("string and file", [ts.STRING, ts.FILE]), true) || this;
    }
    MinLength.prototype.extractValue = function (i) {
        if (typeof i == 'string') {
            return i.length;
        }
        return 0;
    };
    MinLength.prototype.textMessagePart = function () {
        return messageRegistry.STRING_SHOULD_NOT_BE_LESS.message;
    };
    return MinLength;
}(MinMaxRestriction));
exports.MinLength = MinLength;
/**
 * max properties constraint
 */
var MaxProperties = /** @class */ (function (_super) {
    __extends(MaxProperties, _super);
    function MaxProperties(val) {
        return _super.call(this, "maxProperties", val, true, "minProperties", ts.OBJECT, true) || this;
    }
    MaxProperties.prototype.extractValue = function (i) {
        return Object.keys(i).length;
    };
    MaxProperties.prototype.textMessagePart = function () {
        return messageRegistry.OBJECT_PROPERTIES_SHOULD_NOT_BE_MORE.message;
    };
    return MaxProperties;
}(MinMaxRestriction));
exports.MaxProperties = MaxProperties;
/**
 * min properties constraint
 */
var MinProperties = /** @class */ (function (_super) {
    __extends(MinProperties, _super);
    function MinProperties(val) {
        return _super.call(this, "minProperties", val, false, "maxProperties", ts.OBJECT, true) || this;
    }
    MinProperties.prototype.extractValue = function (i) {
        return Object.keys(i).length;
    };
    MinProperties.prototype.textMessagePart = function () {
        return messageRegistry.OBJECT_PROPERTIES_SHOULD_NOT_BE_LESS.message;
    };
    return MinProperties;
}(MinMaxRestriction));
exports.MinProperties = MinProperties;
/**
 * unique items constraint
 */
var UniqueItems = /** @class */ (function (_super) {
    __extends(UniqueItems, _super);
    function UniqueItems(_value) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        return _this;
    }
    UniqueItems.prototype.facetName = function () { return "uniqueItems"; };
    UniqueItems.prototype.requiredType = function () { return ts.ARRAY; };
    UniqueItems.prototype.check = function (i) {
        if (!this._value) {
            return ts.ok();
        }
        if (Array.isArray(i)) {
            var r = i;
            if (_.unique(r).length != r.length) {
                return ts.error(messageRegistry.MUST_BE_UNIQUE, this);
            }
        }
        return ts.ok();
    };
    UniqueItems.prototype.composeWith = function (r) {
        if (r instanceof UniqueItems) {
            var mm = r;
            if (mm._value == this._value) {
                return this;
            }
        }
        return null;
    };
    UniqueItems.prototype.value = function () {
        return this._value;
    };
    UniqueItems.prototype.checkValue = function () {
        if (typeof (this._value) != "boolean") {
            return ts.error(messageRegistry.UNIQUE_ITEMS_BOOLEAN, this);
        }
        return null;
    };
    UniqueItems.prototype.toString = function () {
        return messageRegistry.MUST_BE_UNIQUE.message;
    };
    return UniqueItems;
}(FacetRestriction));
exports.UniqueItems = UniqueItems;
/**
 * components of array should be of type
 */
var ComponentShouldBeOfType = /** @class */ (function (_super) {
    __extends(ComponentShouldBeOfType, _super);
    function ComponentShouldBeOfType(type) {
        var _this = _super.call(this) || this;
        _this.type = type;
        return _this;
    }
    ComponentShouldBeOfType.prototype.facetName = function () { return "items"; };
    ComponentShouldBeOfType.prototype.requiredType = function () { return ts.ARRAY; };
    ComponentShouldBeOfType.prototype.toString = function () {
        var typeName = this.type && this.type.name();
        return ts.error(messageRegistry.ITEMS_SHOULD_BE_OF_TYPE, this, { type: typeName }).getMessage();
    };
    ComponentShouldBeOfType.prototype.check = function (i) {
        var rs = new ts.Status(ts.Status.OK, "", "", this);
        if (Array.isArray(i)) {
            var ar = i;
            for (var j = 0; j < ar.length; j++) {
                var ss = this.type.validate(ar[j], false, false);
                if (!ss.isOk()) {
                    var t = this.type;
                    if (t.isUnknown() || t.isRecurrent()) {
                        var s = ts.error(messageRegistry.ARRAY_AGAINST_UNKNOWN, this, { typeName: t.name() });
                        return s;
                    }
                }
                ts.setValidationPath(ss, { name: "" + j });
                rs.addSubStatus(ss);
            }
        }
        return rs;
    };
    ComponentShouldBeOfType.prototype.validateSelfIndividual = function (st, registry) {
        var _this = this;
        if (this.type.isAnonymous()) {
            var typeStatus = this.type.validateType(registry);
            if (!typeStatus.isOk()) {
                st.addSubStatus(ts.error(messageRegistry.INVALID_COMPONENT_TYPE, this, { msg: st.getMessage() }));
            }
            return st;
        }
        var chained = this.type.metaOfType(metainfo_1.ImportedByChain);
        if (chained.length > 0) {
            chained.forEach(function (x) {
                var componentTypeName = _this.type.name();
                var typeName = null;
                var messageEntry = messageRegistry.ARRAY_COMPONENT_TYPE_IMPORTED_THROUGH_LIBRARY_CHAIN;
                if (x.value() != typeName) {
                    messageEntry = messageRegistry.ARRAY_COMPONENT_TYPE_DEPENDES_ON_TYPE_IMPORTED_THROUGH_LIBRARY_CHAIN;
                    typeName = x.value();
                }
                st.addSubStatus(ts.error(messageEntry, _this, { componentTypeName: componentTypeName, typeName: typeName }));
            });
        }
        else if (this.type.isExternal()) {
            var itemsErr = ts.error(messageRegistry.EXTERNAL_AS_COMPONENT, this);
            itemsErr.setValidationPath({ name: "items" });
            st.addSubStatus(itemsErr);
        }
        else if (ts.isUnknown(this.type) || this.type.isSubTypeOf(ts.RECURRENT)) {
            st.addSubStatus(ts.error(messageRegistry.UNKNOWN_ARRAY_COMPONENT_TYPE, this, { componentTypeName: this.type.name() }));
        }
        else if (this.type.isUnion()) {
            var ui = _.find(this.type.typeFamily(), function (x) { return ts.isUnknown(x); });
            if (ui) {
                st.addSubStatus(ts.error(messageRegistry.UNKNOWN_ARRAY_COMPONENT_TYPE, this, { componentTypeName: ui.name() }));
            }
        }
        return st;
    };
    ComponentShouldBeOfType.prototype.composeWith = function (t) {
        if (t instanceof ComponentShouldBeOfType) {
            var pi = t;
            if (this.type.typeFamily().indexOf(pi.type) != -1) {
                return pi;
            }
            if (pi.type.typeFamily().indexOf(this.type) != -1) {
                return this;
            }
            var intersectionType = this.intersect(this.type, pi.type);
            try {
                var is = intersectionType.checkConfluent();
                if (!is.isOk()) {
                    var rc = is;
                    return rc.toRestriction();
                }
                return new ComponentShouldBeOfType(intersectionType);
            }
            finally {
                this.release(intersectionType);
            }
        }
        return null;
    };
    ComponentShouldBeOfType.prototype.checkValue = function () {
        return null;
    };
    ComponentShouldBeOfType.prototype.value = function () {
        return this.type;
    };
    return ComponentShouldBeOfType;
}(FacetRestriction));
exports.ComponentShouldBeOfType = ComponentShouldBeOfType;
/**
 * regular expression (pattern) constraint
 */
var Pattern = /** @class */ (function (_super) {
    __extends(Pattern, _super);
    function Pattern(_value) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        return _this;
    }
    Pattern.prototype.facetName = function () { return "pattern"; };
    Pattern.prototype.requiredType = function () { return ts.STRING; };
    Pattern.prototype.check = function (i) {
        if (typeof i == 'string') {
            var st = i;
            try {
                var matches = st.match(this._value);
                var gotMatch = false;
                if (matches) {
                    for (var _i = 0, matches_1 = matches; _i < matches_1.length; _i++) {
                        var m = matches_1[_i];
                        if (m.length == st.length) {
                            gotMatch = true;
                            break;
                        }
                    }
                }
                if (!gotMatch) {
                    return ts.error(messageRegistry.PATTERN_VIOLATION, this, { value: this.value() });
                }
            }
            catch (e) {
            }
        }
        return ts.ok();
    };
    Pattern.prototype.composeWith = function (r) {
        if (r instanceof Pattern) {
            var v = r;
            if (v._value === this._value) {
                return this;
            }
            return this.nothing(r, ts.error(messageRegistry.SHOULD_PASS_REXEXP, this, { name: "pattern restrictions" }).getMessage());
        }
        return null;
    };
    Pattern.prototype.value = function () {
        return this._value;
    };
    Pattern.prototype.checkValue = function () {
        try {
            new RegExp(this._value);
        }
        catch (e) {
            return ts.error(messageRegistry.INVALID_REGEXP, this, { msg: e.message }, ts.Status.ERROR, true);
        }
        return null;
    };
    Pattern.prototype.toString = function () {
        return ts.error(messageRegistry.SHOULD_PASS_REXEXP, this, { rexexp: this.value }).getMessage();
    };
    return Pattern;
}(FacetRestriction));
exports.Pattern = Pattern;
var FileTypes = /** @class */ (function (_super) {
    __extends(FileTypes, _super);
    function FileTypes(_value) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        return _this;
    }
    FileTypes.prototype.facetName = function () { return "fileTypes"; };
    FileTypes.prototype.requiredType = function () { return ts.FILE; };
    FileTypes.prototype.check = function (i) {
        return ts.ok();
    };
    FileTypes.prototype.composeWith = function (r) {
        if (r instanceof FileTypes) {
            var v = r;
            var arr = _.intersection(this._value, v._value);
            if (arr.length > 0) {
                return new FileTypes(arr);
            }
            return this.nothing(r, messageRegistry.NO_COMMON_FILE_TYPES.message);
        }
        return null;
    };
    FileTypes.prototype.value = function () {
        return this._value;
    };
    FileTypes.prototype.checkValue = function () {
        if (!Array.isArray(this._value)) {
            return ts.error(messageRegistry.FILE_TYPES_SHOULD_BE_AN_ARRAY, this);
        }
        for (var _i = 0, _a = this._value; _i < _a.length; _i++) {
            var s = _a[_i];
            if (typeof (s) != "string") {
                return ts.error(messageRegistry.FILE_TYPES_SHOULD_BE_AN_ARRAY, this);
            }
        }
        return ts.ok();
    };
    FileTypes.prototype.toString = function () {
        if (!this.checkValue().isOk()) {
            return messageRegistry.INVALID_FILETYPES_FACET_VALUE.message;
        }
        return ts.error(messageRegistry.SUPPORTED_FILE_TYPES, this, { types: this._value.join(", ") }).getMessage();
    };
    return FileTypes;
}(FacetRestriction));
exports.FileTypes = FileTypes;
/**
 * regular expression (pattern) constraint
 */
var Format = /** @class */ (function (_super) {
    __extends(Format, _super);
    function Format(_value) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        return _this;
    }
    Format.prototype.facetName = function () { return "format"; };
    Format.prototype.requiredType = function () {
        return ts.SCALAR;
    };
    Format.prototype.requiredTypes = function () {
        return [ts.NUMBER, ts.INTEGER, ts.DATETIME];
    };
    Format.prototype.check = function (i) {
        return ts.ok();
    };
    Format.prototype.composeWith = function (r) {
        if (r instanceof Format) {
            var v = r;
            if (v._value === this._value) {
                return this;
            }
            return this.nothing(r, ts.error(messageRegistry.SHOULD_PASS_REXEXP, this, { name: "Format" }).getMessage());
        }
        return null;
    };
    Format.prototype.value = function () {
        return this._value;
    };
    Format.prototype.checkValue = function () {
        var _this = this;
        try {
            var allowedValues = [];
            if (this.owner().isSubTypeOf(ts.INTEGER)) {
                allowedValues = ["int32", "int64", "int", "long", "int16", "int8"];
            }
            else if (this.owner().isSubTypeOf(ts.NUMBER)) {
                allowedValues = ["int32", "int64", "int", "long", "float", "double", "int16", "int8"];
            }
            else if (this.owner().isSubTypeOf(ts.DATETIME)) {
                allowedValues = ["rfc3339", "rfc2616"];
            }
            else
                return null;
            var found = _.find(allowedValues, function (allowedValue) { return allowedValue == _this.value(); });
            if (!found) {
                return ts.error(messageRegistry.ALLOWED_FORMAT_VALUES, this, {
                    allowedValues: allowedValues.map(function (x) { return "'" + x + "'"; }).join(", ")
                }, ts.Status.ERROR, true);
            }
        }
        catch (e) {
            return new typesystem_2.Status(typesystem_2.Status.ERROR, "", e.message, this);
        }
        return null;
    };
    Format.prototype.toString = function () {
        return "should have format:" + this.value;
    };
    return Format;
}(FacetRestriction));
exports.Format = Format;
/**
 * enum constraint
 */
var Enum = /** @class */ (function (_super) {
    __extends(Enum, _super);
    function Enum(_value) {
        var _this = _super.call(this) || this;
        _this._value = _value;
        return _this;
    }
    Enum.prototype.facetName = function () { return "enum"; };
    Enum.prototype.requiredType = function () { return ts.ANY; };
    Enum.prototype.check = function (i) {
        if (!this.checkStatus) {
            var opts = this.value();
            if (this.owner().oneMeta(metainfo_3.AcceptAllScalarsAsStrings) && i != null) {
                opts = opts.concat(opts.map(function (x) { return "" + x; }));
            }
            if (!Array.isArray(opts)) {
                opts = [opts];
            }
            if (!opts.some(function (x) { return x == i; })) {
                var valStr = Array.isArray(this._value) ? this._value.map(function (x) {
                    if (x && typeof x === "object") {
                        return JSON.stringify(x, null, 2);
                    }
                    return "'" + x + "'";
                }).join(", ") : "'" + this._value + "'";
                return ts.error(messageRegistry.ENUM_RESTRICTION, this, { values: valStr });
            }
        }
        return ts.ok();
    };
    Enum.prototype.composeWith = function (r) {
        if (r instanceof Enum) {
            var v = r;
            var sss = _.intersection(this._value, v._value);
            if (sss.length == 0) {
                return this.nothing(r);
            }
            return new Enum(sss);
        }
        return null;
    };
    Enum.prototype.value = function () {
        return this._value;
    };
    Enum.prototype.checkValue = function () {
        var _this = this;
        if (!this.owner().isSubTypeOf(this.requiredType())) {
            return ts.error(messageRegistry.ENUM_OWNER_TYPES, this, {
                typeNames: this.requiredType().name()
            }, ts.Status.ERROR, true);
        }
        if (this.requiredTypes() && this.requiredTypes().length > 0) {
            var owner = this.owner();
            var requiredSuperType = _.find(this.requiredTypes(), function (requiredType) { return owner.isSubTypeOf(requiredType); });
            if (!requiredSuperType) {
                var typeNames = "[" + this.requiredTypes().map(function (requiredType) { return "'" + requiredType.name() + "'"; }).join(", ") + "]";
                return ts.error(messageRegistry.ENUM_OWNER_TYPES, this, {
                    typeNames: typeNames
                }, ts.Status.ERROR, true);
            }
        }
        if (!Array.isArray(this._value)) {
            return ts.error(messageRegistry.ENUM_ARRAY, this, {}, ts.Status.ERROR, true);
        }
        // if (_.uniq(this._value).length<this._value.length){
        //     return "enum facet can only contain unique items";
        // }
        var result = ts.ok();
        this.checkStatus = true;
        try {
            this._value.forEach(function (x, i) {
                var res = _this.owner().validate(x);
                if (!res.isOk()) {
                    ts.setValidationPath(res, { name: i });
                    result.addSubStatus(res);
                }
            });
        }
        finally {
            this.checkStatus = false;
        }
        return result;
    };
    Enum.prototype.toString = function () {
        var valStr = Array.isArray(this._value) ? this._value.map(function (x) { return "'" + x + "'"; }).join(", ") : "'" + this._value + "'";
        return "value should be one of: " + valStr;
    };
    return Enum;
}(FacetRestriction));
exports.Enum = Enum;
/**
 * this function attempts to optimize to set of restrictions
 * @param r
 * @returns {ts.Constraint[]}
 */
function optimize(r) {
    r = r.map(function (x) { return x.preoptimize(); });
    var optimized = [];
    r.forEach(function (x) {
        if (x instanceof typesystem_1.AndRestriction) {
            var ar = x;
            ar.options().forEach(function (y) { optimized.push(y); });
        }
        else {
            optimized.push(x);
        }
    });
    var transformed = true;
    while (transformed) {
        transformed = false;
        for (var i = 0; i < optimized.length; i++) {
            for (var j = 0; j < optimized.length; j++) {
                var rs0 = optimized[i];
                var rs1 = optimized[j];
                if (rs0 !== rs1) {
                    var compose = rs0.tryCompose(rs1);
                    if (compose) {
                        var newOptimized = optimized.filter(function (x) { return x !== rs0 && x !== rs1; });
                        newOptimized.push(compose);
                        transformed = true;
                        optimized = newOptimized;
                        break;
                    }
                }
            }
            if (transformed) {
                break;
            }
        }
    }
    return optimized;
}
exports.optimize = optimize;
function actualUnknownType(t) {
    if (!ts.isUnknown(t)) {
        return null;
    }
    if (t.name() != null) {
        return t;
    }
    for (var _i = 0, _a = t.superTypes(); _i < _a.length; _i++) {
        var st = _a[_i];
        var ust = actualUnknownType(st);
        if (ust != null) {
            return ust;
        }
    }
    return t;
}
function validatePropertyType(_type, propName, registry, source, isFacet) {
    if (isFacet === void 0) { isFacet = false; }
    if (_type.isExternal()) {
        var p = void 0;
        if (isFacet) {
            p = ts.error(messageRegistry.EXTERNAL_IN_FACET_DEFINITION, source);
        }
        else {
            p = ts.error(messageRegistry.EXTERNAL_IN_PROPERTY_DEFINITION, source);
        }
        ts.setValidationPath(p, { name: propName });
        return p;
    }
    if (ts.isUnknown(_type)) {
        var actualUnknown = actualUnknownType(_type);
        var p = void 0;
        var messageEntries = [];
        var chained = _type.metaOfType(metainfo_1.ImportedByChain);
        var issues_1 = [];
        if (isFacet) {
            if (chained.length > 0) {
                chained.forEach(function (x) {
                    var messageEntry = messageRegistry.LIBRARY_CHAINIG_IN_FACET_TYPE;
                    var typeName = actualUnknown.name();
                    if (x.value() != typeName) {
                        messageEntry = messageRegistry.LIBRARY_CHAINIG_IN_FACET_TYPE_SUPERTYPE;
                        typeName = x.value();
                    }
                    var st = ts.error(messageEntry, source, {
                        propName: propName,
                        typeName: typeName
                    });
                    issues_1.push(st);
                });
            }
            else {
                st = ts.error(messageRegistry.UNKNOWN_IN_FACET_DEFINITION, source, {
                    facetName: propName,
                    msg: actualUnknown.name()
                });
                issues_1.push(st);
            }
        }
        else {
            if (chained.length > 0) {
                chained.forEach(function (x) {
                    var messageEntry = messageRegistry.LIBRARY_CHAINIG_IN_PROPERTY_TYPE;
                    var typeName = actualUnknown.name();
                    if (x.value() != typeName) {
                        messageEntry = messageRegistry.LIBRARY_CHAINIG_IN_PROPERTY_TYPE_SUPERTYPE;
                        typeName = x.value();
                    }
                    var st = ts.error(messageEntry, source, {
                        propName: propName,
                        typeName: typeName
                    });
                    issues_1.push(st);
                });
            }
            else {
                st = ts.error(messageRegistry.UNKNOWN_IN_PROPERTY_DEFINITION, source, {
                    propName: propName,
                    typeName: actualUnknown.name()
                });
                issues_1.push(st);
            }
        }
        issues_1.forEach(function (p) { return ts.setValidationPath(p, { name: propName, child: { name: "type" } }); });
        if (issues_1.length == 1) {
            return issues_1[0];
        }
        else {
            var result_1 = ts.ok();
            issues_1.forEach(function (x) { return result_1.addSubStatus(x); });
            return result_1;
        }
    }
    else if (_type.isSubTypeOf(ts.RECURRENT)) {
        st = ts.error(messageRegistry.CYCLIC_DEPENDENCY, source, {
            typeName: _type.name()
        });
        return st;
    }
    if (_type.isAnonymous()) {
        var st = _type.validateType(registry);
        if (!st.isOk()) {
            var p_1;
            if (isFacet) {
                p_1 = ts.error(messageRegistry.ERROR_IN_FACET_RANGE, source, {
                    facetName: propName,
                    msg: st.getMessage()
                });
            }
            else {
                p_1 = ts.error(messageRegistry.ERROR_IN_RANGE, source, {
                    propName: propName,
                    msg: st.getMessage()
                });
            }
            st.getErrors().forEach(function (y) { p_1.addSubStatus(y); });
            ts.setValidationPath(p_1, { name: propName });
            return p_1;
        }
        return st;
    }
    if (_type.isUnion()) {
        var ui = _.find(_type.typeFamily(), function (x) { return ts.isUnknown(x); });
        if (ui) {
            var p = void 0;
            if (isFacet) {
                p = ts.error(messageRegistry.UNKNOWN_IN_FACET_DEFINITION, source, {
                    facetName: propName,
                    msg: ui.name()
                });
            }
            else {
                p = ts.error(messageRegistry.UNKNOWN_IN_PROPERTY_DEFINITION, source, {
                    propName: propName,
                    typeName: ui.name()
                });
            }
            ts.setValidationPath(p, { name: propName });
            return p;
        }
    }
    return ts.ok();
}
exports.validatePropertyType = validatePropertyType;
//# sourceMappingURL=restrictions.js.map