"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var defs = require("raml-definition-system");
var hl = require("../highLevelAST");
var linter = require("./linter");
var yaml = require("yaml-ast-parser");
var _ = require("underscore");
var def = defs;
var hlimpl = require("../highLevelImpl");
var proxy = require("./LowLevelASTProxy");
var search = require("../../search/search-interface");
var universes = require("../tools/universe");
var universeHelpers = require("../tools/universeHelpers");
var services = defs;
var ramlTypes = defs.rt;
var referencePatcher = require("./referencePatcher");
var tsInterfaces = defs.tsInterfaces;
var messageRegistry = require("../../../resources/errorMessages");
var mediaTypeParser = require("media-typer");
var KeyMatcher = /** @class */ (function () {
    function KeyMatcher(_props) {
        this._props = _props;
        for (var _i = 0, _a = _props.filter(function (x) { return defs.Property.isInstance(x); }); _i < _a.length; _i++) {
            var p = _a[_i];
            if (p.isFromParentValue()) {
                this.parentValue = this.parentValue || p;
            }
            if (p.isFromParentKey()) {
                this.parentKey = this.parentKey || p;
            }
            if (p.canBeValue()) {
                this.canBeValue = this.canBeValue || p;
            }
        }
    }
    KeyMatcher.prototype.add = function (p) {
        this._props.push(p);
    };
    KeyMatcher.prototype.match = function (key) {
        var _this = this;
        var _res = null;
        var lastPref = "";
        this._props.forEach(function (p) {
            if (p.getAdapter(services.RAMLPropertyService).isSystem()) {
                return;
            }
            if (p != _this.parentValue && p != _this.parentKey && p.matchKey(key)) {
                if (p.keyPrefix() != null) {
                    if (p.keyPrefix().length >= lastPref.length) {
                        lastPref = p.keyPrefix();
                        _res = p;
                    }
                }
                else {
                    _res = p;
                    lastPref = p.nameId();
                }
            }
        });
        return _res;
    };
    return KeyMatcher;
}());
function getAllOptions(c, deep) {
    if (deep === void 0) { deep = 0; }
    if (deep > 20) {
        return [];
    }
    try {
        var result = [];
        var tp = c.leftType();
        if (tp) {
            result.push(tp);
        }
        var r = c.rightType();
        if (r) {
            if (r.hasUnionInHierarchy()) {
                var options = getAllOptions(r.unionInHierarchy(), deep + 1);
                result = result.concat(options);
            }
            else {
                result.push(r);
            }
        }
        return result;
    }
    finally {
    }
}
var ad = 0;
/**
 * Checks if a node is type declaration by a type shortcut having multiple inheritance TE as a value
 * @param node
 */
function isMultipleInheritanceTypeExpressionTypeDeclaration(node) {
    var definition = node.definition();
    if (!definition || !universeHelpers.isTypeDeclarationDescendant(definition))
        return false;
    var lowLevel = node.lowLevel();
    if (lowLevel.valueKind() !== yaml.Kind.SEQ)
        return false;
    var children = lowLevel.children();
    if (children == null)
        return false;
    for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
        var child = children_1[_i];
        if (child.kind() !== yaml.Kind.SCALAR)
            return false;
    }
    return true;
}
var BasicNodeBuilder = /** @class */ (function () {
    function BasicNodeBuilder() {
        this.shouldDescriminate = false;
    }
    BasicNodeBuilder.prototype.process = function (node, childrenToAdopt) {
        var _this = this;
        var nn = node.lowLevel();
        var cv = node;
        cv._mergedChildren = null;
        var cha = nn._node ? nn._node : nn;
        try {
            if (cha['currentChildren']) {
                return cha['currentChildren'];
            }
            if (!node.definition()) {
                return;
            }
            if (node.parent() == null && (!this.shouldDescriminate)) {
                this.shouldDescriminate = true;
                try {
                    var children = this.process(node, childrenToAdopt);
                    var ts = node;
                    ts._children = children;
                    ts._mergedChildren = null;
                    var t = doDescrimination(node);
                    if (t) {
                        ts.patchType(t);
                    }
                    var children = this.process(node, childrenToAdopt);
                    ts._children = children;
                    ts._mergedChildren = null;
                }
                finally {
                    this.shouldDescriminate = false;
                }
            }
            if (node.definition().hasUnionInHierarchy()) {
                if (true &&
                    (node.parent() && node.property().nameId() == universes.Universe10.LibraryBase.properties.annotations.name)) {
                    var optins = getAllOptions(node.definition().unionInHierarchy());
                    var actualResult = null;
                    var bestResult = null;
                    var bestType = null;
                    var bestCount = 1000;
                    var llnode = node;
                    optins.forEach(function (x) {
                        if (!actualResult) {
                            //TODO ADD UNION + Descriminator
                            if (!(x).hasUnionInHierarchy()) {
                                var tp = llnode.patchType(x);
                                if (ad == 0) {
                                    ad++;
                                    try {
                                        var result = _this.process(node, childrenToAdopt);
                                        var uc = 0;
                                        for (var i = 0; i < result.length; i++) {
                                            if (result[i].isUnknown()) {
                                                uc++;
                                            }
                                        }
                                        if (uc == 0) {
                                            actualResult = result;
                                        }
                                        if (bestCount > uc) {
                                            bestCount = uc;
                                            bestResult = result;
                                            bestType = x;
                                        }
                                    }
                                    finally {
                                        ad--;
                                    }
                                }
                            }
                        }
                    });
                    if (actualResult) {
                        llnode.patchType(bestType);
                        return actualResult;
                    }
                    if (bestResult) {
                        llnode.patchType(bestType);
                    }
                }
            }
            var km = new KeyMatcher(node.definition().allProperties());
            if (node.parent() == null || node.lowLevel().includePath()) {
                var u = node.definition().universe();
                if (u.version() == "RAML10") {
                    if (!node.definition().property("uses")) {
                        u.type("FragmentDeclaration").allProperties().forEach(function (x) { return km.add(x); });
                    }
                }
            }
            var aNode = node;
            var allowsQuestion = aNode._allowQuestion || node.definition().getAdapter(services.RAMLService).getAllowQuestion();
            var res = [];
            //cha['currentChildren']=res;
            if (km.parentKey) {
                if (node.lowLevel().key()) {
                    var keyAttr = new hlimpl.ASTPropImpl(node.lowLevel(), node, km.parentKey.range(), km.parentKey, true);
                    res.push(keyAttr);
                    var isDefaultMediaType = node.property()
                        && universeHelpers.isBodyProperty(node.property())
                        && node.lowLevel().key() == node.property().nameId();
                    if (isDefaultMediaType) {
                        var isInsideTraitOrResourceType = isInTtraitOrResourceType(aNode);
                        //if (!isInsideTraitOrResourceType&&aNode._computedKey) {
                        keyAttr.overrideValue(aNode._computedKey);
                        //}
                    }
                }
                if (node.lowLevel().valueKind() === yaml.Kind.SEQ
                    && !isMultipleInheritanceTypeExpressionTypeDeclaration(node)) {
                    var error = new hlimpl.BasicASTNode(node.lowLevel(), aNode);
                    error.errorMessage = {
                        entry: messageRegistry.DEFINITION_SHOULD_BE_A_MAP,
                        parameters: { typeName: node.definition().nameId() }
                    };
                    res.push(error);
                    return res;
                }
            }
            if (node.lowLevel().value(true) != null) {
                if (km.parentValue) {
                    res.push(new hlimpl.ASTPropImpl(node.lowLevel(), node, km.parentValue.range(), km.parentValue));
                }
                else if (km.canBeValue) {
                    var s = node.lowLevel().value();
                    if (s == null) {
                        s = node.lowLevel().value(true);
                    }
                    if (typeof s == 'string' && s.trim().length > 0) {
                        //if (km.canBeValue.nameId()==universes.Universe10.Resource.properties.signature.name){
                        //      if (s.trim().charAt(0)=='('){
                        //          //TODO BETTER DECITION current one prevents completion from working correctly
                        //          //in few other cases
                        //          res.push(new hlimpl.ASTPropImpl(node.lowLevel(), node, km.canBeValue.range(), km.canBeValue));
                        //      }
                        //}
                        //else {
                        res.push(new hlimpl.ASTPropImpl(node.lowLevel(), node, km.canBeValue.range(), km.canBeValue));
                        //}
                    }
                    // else if (node.definition().isAssignableFrom(universes.Universe10.Annotation.name) &&
                    //     node.definition().property("value")) {
                    //     //"value" is a magic property name we do not have reflected in serialized def. system, so have to use plain string
                    //
                    //     var lowLevelNode = node.lowLevel();
                    //
                    //     var valueAttribute = _.find(lowLevelNode.children(), child=>{
                    //
                    //         return child.kind() == yaml.Kind.MAPPING && child.key() && child.key() == "value";
                    //     });
                    //
                    //     if (!valueAttribute) {
                    //         //annotation reference is not a scalar and does not have value attribute, but has value defined in the annotation declaration
                    //         //that means user wants to use a shortcut and specify value object directly under annotation
                    //
                    //         var valueProperty = node.definition().property("value")
                    //
                    //         //creating "value" high-level node referencing the same low-level node so the children can be collected
                    //         var valueNode = new hlimpl.ASTNodeImpl(node.lowLevel(), node, valueProperty.range(), valueProperty);
                    //         return [valueNode];
                    //     }
                    // }
                }
            }
            else {
                // if (km.canBeValue && (km.canBeValue.range() instanceof def.NodeClass || (
                //         km.canBeValue.range().hasUnionInHierarchy() && node.definition().isAssignableFrom(universes.Universe10.Annotation.name)))) {
                //
                //     //check check for annotation is just for safety, generally, imho, we should go inside for any unions
                //     var ch = new hlimpl.ASTNodeImpl(node.lowLevel(), aNode, <hl.INodeDefinition>km.canBeValue.range(), km.canBeValue);
                //     return [ch];
                // }
            }
            aNode._children = res;
            aNode._mergedChildren = null;
            if (!aNode.definition().getAdapter(services.RAMLService).isUserDefined()) {
                if (aNode.definition().key() == universes.Universe08.Api || aNode.definition().key() == universes.Universe10.Api) {
                    var uses = childrenToAdopt.filter(function (x) { return x.key() == "uses"; });
                    res = this.processChildren(uses, aNode, res, allowsQuestion, km);
                    var types = childrenToAdopt.filter(function (x) { return x.key() == "types"; });
                    res = this.processChildren(types, aNode, res, allowsQuestion, km);
                    var other = childrenToAdopt.filter(function (x) { return (x.key() != "types" && x.key() != "uses"); });
                    res = this.processChildren(other, aNode, res, allowsQuestion, km);
                }
                else {
                    res = this.processChildren(childrenToAdopt, aNode, res, allowsQuestion, km);
                }
            }
            else {
                res = this.processChildren(childrenToAdopt, aNode, res, allowsQuestion, km);
            }
            aNode._children = res;
            aNode._mergedChildren = null;
            return res;
        }
        finally {
        }
    };
    BasicNodeBuilder.prototype.isTypeDeclarationShortcut = function (node, property) {
        var isTypeDeclarationType = universeHelpers.isTypeOrSchemaProperty(property);
        var isTypeDeclaration = node.definition() && universeHelpers.isTypeDeclarationTypeOrDescendant(node.definition());
        if (isTypeDeclaration && isTypeDeclarationType && node.lowLevel() && node.lowLevel().valueKind() === yaml.Kind.SEQ) {
            return true;
        }
        return false;
    };
    BasicNodeBuilder.prototype.processChildren = function (childrenToAdopt, aNode, res, allowsQuestion, km) {
        var _this = this;
        var typeDeclarationName = universes.Universe10.TypeDeclaration.name;
        var typePropertyName = universes.Universe10.TypeDeclaration.properties.type.name;
        var itemsPropertyName = universes.Universe10.ArrayTypeDeclaration.properties.items.name;
        if (aNode.definition() && aNode.definition().isAssignableFrom(typeDeclarationName) && aNode.lowLevel() && (km.canBeValue && (km.canBeValue.nameId() === typePropertyName || km.canBeValue.nameId() === itemsPropertyName)) && aNode.lowLevel()._node && aNode.lowLevel()._node.value && aNode.lowLevel()._node.value.kind === yaml.Kind.SEQ) {
            childrenToAdopt.forEach(function (child) {
                var property = new hlimpl.ASTPropImpl(child, aNode, km.canBeValue.range(), km.canBeValue);
                res.push(property);
            });
            return res;
        }
        var rootUnit = aNode.root().lowLevel().unit();
        childrenToAdopt.forEach(function (x) {
            if (km.canBeValue && _this.isTypeDeclarationShortcut(aNode, km.canBeValue)) {
                res.push(new hlimpl.ASTPropImpl(x, aNode, km.canBeValue.range(), km.canBeValue));
                return;
            }
            var key = x.key();
            //if (x.optional()&&!allowsQuestion) {
            //    return;
            //}
            var p = key != null ? km.match(key) : null;
            if (p != null) {
                var range = p.range();
                if (p.isAnnotation() && key != "annotations") {
                    var pi = new hlimpl.ASTPropImpl(x, aNode, range, p);
                    res.push(pi);
                    return;
                }
                var um = false;
                var multyValue = p.isMultiValue();
                if (range.isArray()) {
                    multyValue = true;
                    range = range.array().componentType();
                    um = true;
                }
                else if (range.hasArrayInHierarchy()) {
                    multyValue = true;
                    um = true;
                }
                var xChildren;
                var gotReuse = false;
                if (aNode.reuseMode() && x.valueKind() != yaml.Kind.SEQ) {
                    var rNode = aNode.reusedNode();
                    if (rNode) {
                        var arr = [x];
                        var llParent = aNode.lowLevel();
                        if (!p.isMerged() && multyValue) {
                            xChildren = [];
                            arr = x.children();
                            llParent = x;
                        }
                        for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) {
                            var ch1 = arr_1[_i];
                            var cUnit = ch1.containingUnit();
                            if (cUnit && cUnit.absolutePath() != rootUnit.absolutePath()) {
                                var rChild = _.find(rNode.children(), function (ch2) { return ch2.lowLevel().key() == ch1.key(); });
                                if (rChild && rChild.lowLevel().unit().absolutePath() == cUnit.absolutePath()) {
                                    gotReuse = true;
                                    res.push(rChild);
                                    rChild.setReused(true);
                                    rChild.setParent(aNode);
                                    if (rChild.isElement()) {
                                        rChild.resetRuntimeTypes();
                                    }
                                    if (aNode.isExpanded()) {
                                        llParent
                                            .replaceChild(ch1, rChild.lowLevel());
                                        if (proxy.LowLevelCompositeNode.isInstance(rChild.lowLevel())) {
                                            rChild.lowLevel().setTransformer(llParent.transformer());
                                        }
                                    }
                                    continue;
                                }
                            }
                            if (xChildren) {
                                xChildren.push(ch1);
                            }
                        }
                    }
                }
                if (!xChildren) {
                    if (gotReuse) {
                        return;
                    }
                    xChildren = x.children();
                }
                //TODO DESCRIMINATORS
                if (range.hasValueTypeInHierarchy()) {
                    var ch = xChildren;
                    var seq = (x.valueKind() == yaml.Kind.SEQ);
                    if ((seq && ch.length > 0 || ch.length > 1) && multyValue) {
                        if (ch.length > 1 && universeHelpers.isTypeDeclarationDescendant(aNode.definition())
                            && (universeHelpers.isTypeOrSchemaProperty(p) || universeHelpers.isItemsProperty(p)) && x.valueKind() != yaml.Kind.SEQ) {
                            var pi = new hlimpl.ASTPropImpl(x, aNode, range, p);
                            res.push(pi);
                            aNode.setComputed(p.nameId(), pi);
                        }
                        else {
                            var values = [];
                            ch.forEach(function (y) {
                                var pi = new hlimpl.ASTPropImpl(y, aNode, range, p);
                                res.push(pi);
                                values.push(y.value());
                            });
                            if (p.isInherited()) {
                                aNode.setComputed(p.nameId(), values);
                            }
                        }
                    }
                    else {
                        if (p.isInherited()) {
                            aNode.setComputed(p.nameId(), x.value());
                        }
                        var attrNode = new hlimpl.ASTPropImpl(x, aNode, range, p);
                        var actualValueNode = x;
                        if (x.isAnnotatedScalar()) {
                            actualValueNode = _.find(x.children(), function (c) { return c.key() == "value"; });
                        }
                        if ((actualValueNode.valueKind() == yaml.Kind.SEQ
                            || actualValueNode.valueKind() == yaml.Kind.MAP)) {
                            var rng = p.range().nameId();
                            if (!p.getAdapter(services.RAMLPropertyService).isExampleProperty()) {
                                if (rng == 'MarkdownString') {
                                    rng = "string";
                                }
                                else if (rng == 'StringType') {
                                    rng = "string";
                                }
                                else if (rng == 'NumberType') {
                                    rng = "number";
                                }
                                else if (rng == 'BooleanType') {
                                    rng = "boolean";
                                }
                                if (rng == "string" || rng == "number" || rng == "boolean") {
                                    attrNode.errorMessage = {
                                        entry: messageRegistry.INVALID_PROPERTY_RANGE,
                                        parameters: {
                                            propName: p.groupName(),
                                            range: rng
                                        }
                                    };
                                    if (xChildren.length == 0 && p.groupName() == "enum") {
                                        attrNode.errorMessage = {
                                            entry: messageRegistry.ENUM_IS_EMPTY,
                                            parameters: {}
                                        };
                                        if (x.valueKind() == yaml.Kind.MAP) {
                                            attrNode.errorMessage = {
                                                entry: messageRegistry.ENUM_MUST_BE_AN_ARRAY,
                                                parameters: {}
                                            };
                                        }
                                    }
                                }
                            }
                        }
                        res.push(attrNode);
                    }
                    //}
                    return;
                }
                else {
                    var rs = [];
                    //now we need determine actual type
                    aNode._children = res;
                    aNode._mergedChildren = null;
                    if (x.value() != null && (typeof x.value() == 'string' || typeof x.value() == 'boolean' || typeof x.value() == 'number')) {
                        if (("" + x.value()).trim().length > 0) {
                            var c = p.range();
                            if (!c.allProperties().some(function (x) {
                                var srv = x;
                                if (srv) {
                                    return srv.canBeValue() && srv.isFromParentValue();
                                }
                                return false;
                            })) {
                                var bnode = new hlimpl.BasicASTNode(x, aNode);
                                bnode.getLowLevelEnd = function () {
                                    return -1;
                                };
                                bnode.getLowLevelStart = function () {
                                    return -1;
                                };
                                bnode.knownProperty = p;
                                res.push(bnode);
                            }
                            //return res;
                        }
                    }
                    if (!p.isMerged()) {
                        if (multyValue) {
                            if (p.getAdapter(services.RAMLPropertyService).isEmbedMap()) {
                                var chld = xChildren;
                                var newChld = [];
                                var hasSequenceComposition = false;
                                chld.forEach(function (n) {
                                    if (n.kind() == yaml.Kind.INCLUDE_REF) {
                                        if (aNode.universe().version() == "RAML08") {
                                            n.children().forEach(function (y) {
                                                var node = new hlimpl.ASTNodeImpl(y, aNode, range, p);
                                                node._allowQuestion = allowsQuestion;
                                                rs.push(node);
                                                hasSequenceComposition = true;
                                            });
                                        }
                                        else {
                                            newChld.push(n);
                                        }
                                    }
                                    else {
                                        newChld.push(n);
                                    }
                                });
                                chld = newChld;
                                if (chld.length == 0) {
                                    if (p.range().key() == universes.Universe08.ResourceType) {
                                        if (!hasSequenceComposition) {
                                            var error = new hlimpl.BasicASTNode(x, aNode);
                                            error.errorMessage = {
                                                entry: messageRegistry.PROPERTY_MUST_BE_A_MAP,
                                                parameters: { propName: p.nameId() }
                                            };
                                            res.push(error);
                                        }
                                    }
                                    if (x.valueKind() == yaml.Kind.SCALAR) {
                                        if (p.range().key() == universes.Universe08.AbstractSecurityScheme) {
                                            var error = new hlimpl.BasicASTNode(x.parent(), aNode);
                                            error.errorMessage = {
                                                entry: messageRegistry.PROPERTY_MUST_BE_A_MAP,
                                                parameters: { propName: p.nameId() }
                                            };
                                            res.push(error);
                                        }
                                    }
                                }
                                chld.forEach(function (y) {
                                    //TODO TRACK GROUP KEY
                                    var cld = y.children();
                                    if (cld.length > 0 && aNode.universe().version() == "RAML08"
                                        && universeHelpers.isSchemasProperty(p)) {
                                        for (var _i = 0, cld_1 = cld; _i < cld_1.length; _i++) {
                                            var c_1 = cld_1[_i];
                                            var node_1 = new hlimpl.ASTNodeImpl(c_1, aNode, range, p);
                                            node_1._allowQuestion = allowsQuestion;
                                            rs.push(node_1);
                                        }
                                    }
                                    else if (!y.key() && cld.length == 1) {
                                        if (aNode.universe().version() != "RAML10" || aNode.parent()) {
                                            var node = new hlimpl.ASTNodeImpl(cld[0], aNode, range, p);
                                            node._allowQuestion = allowsQuestion;
                                            rs.push(node);
                                        }
                                    }
                                    else {
                                        if (aNode.universe().version() == "RAML10") {
                                            var node = new hlimpl.ASTNodeImpl(y, aNode, range, p);
                                            node._allowQuestion = allowsQuestion;
                                            rs.push(node);
                                        }
                                        else {
                                            var bnode = new hlimpl.BasicASTNode(y, aNode);
                                            res.push(bnode);
                                            if (y.key()) {
                                                bnode.needSequence = true;
                                            }
                                        }
                                    }
                                });
                                if (aNode.universe().version() == "RAML10" && x.valueKind() == yaml.Kind.SEQ) {
                                    var bnode = new hlimpl.BasicASTNode(x, aNode);
                                    res.push(bnode);
                                    bnode.needMap = true;
                                    bnode.knownProperty = p;
                                }
                            }
                            else {
                                var filter = {};
                                var inherited = [];
                                if (defs.NodeClass.isInstance(range)) {
                                    var nc = range;
                                    if (nc.getAdapter(services.RAMLService).getCanInherit().length > 0) {
                                        nc.getAdapter(services.RAMLService).getCanInherit().forEach(function (v) {
                                            var originalValue = aNode.computedValue(v);
                                            var actualValue = Array.isArray(originalValue) ? originalValue : [originalValue];
                                            for (var pos = 0; pos < actualValue.length; pos++) {
                                                var vl = actualValue[pos];
                                                if (vl && p.nameId() == universes.Universe10.Response.properties.body.name) {
                                                    var exists = _.find(xChildren, function (x) { return x.key() == vl; });
                                                    var originalParent = x;
                                                    while (originalParent.originalNode) {
                                                        originalParent = originalParent.originalNode();
                                                    }
                                                    var mediaTypeSibling = _.find(originalParent.children(), function (sibling) {
                                                        try {
                                                            mediaTypeParser.parse(sibling.key());
                                                            return true;
                                                        }
                                                        catch (exception) {
                                                            return false;
                                                        }
                                                    });
                                                    if (!mediaTypeSibling) {
                                                        //we can create inherited node;
                                                        var pc = aNode.parent().definition().key();
                                                        var node = new hlimpl.ASTNodeImpl(x, aNode, range, p);
                                                        node._computedKey = vl;
                                                        if (pc == universes.Universe10.MethodBase || pc == universes.Universe08.MethodBase) {
                                                            node.setComputed("form", "true"); //FIXME
                                                        }
                                                        var isInsideTraitOrResourceType = isInTtraitOrResourceType(aNode);
                                                        var t = descriminate(p, aNode, node);
                                                        if (t) {
                                                            if (!isInsideTraitOrResourceType) {
                                                                t.setName(vl);
                                                            }
                                                            node.patchType(t);
                                                        }
                                                        var ch = node.children();
                                                        //this are false unknowns actual unknowns will be reported by parent node
                                                        node._children = ch.filter(function (x) { return !x.isUnknown(); });
                                                        node._mergedChildren = null;
                                                        node._allowQuestion = allowsQuestion;
                                                        if (!exists) {
                                                            inherited.push(node);
                                                        }
                                                        node.children().forEach(function (x) {
                                                            var p = x.property();
                                                            if (p && p.getAdapter(services.RAMLPropertyService).isKey()) {
                                                                var atr = x;
                                                                atr._computed = true;
                                                                return;
                                                            }
                                                            if (x.isElement()) {
                                                                if (!x.property().getAdapter(services.RAMLPropertyService).isMerged()) {
                                                                    filter[x.property().nameId()] = true;
                                                                }
                                                            }
                                                            if (x.property().isAnnotation()) {
                                                                var atr = x;
                                                                var vl = atr.value();
                                                                var strVal = "";
                                                                if (hlimpl.StructuredValue.isInstance(vl)) {
                                                                    strVal = vl.valueName();
                                                                }
                                                                else {
                                                                    strVal = "" + vl;
                                                                }
                                                                filter["(" + strVal + ")"] = true;
                                                            }
                                                            else {
                                                                filter[x.name()] = true;
                                                            }
                                                        });
                                                        var ap = node.definition().allProperties();
                                                        if (node.localType().isAssignableFrom("unknown")) {
                                                            for (var _i = 0, _a = node.definition().allSuperTypes().filter(function (x) { return !x.isUserDefined(); }); _i < _a.length; _i++) {
                                                                var sut = _a[_i];
                                                                for (var _b = 0, _c = sut.allSubTypes(); _b < _c.length; _b++) {
                                                                    var st = _c[_b];
                                                                    st.properties().forEach(function (x) { return ap.push(x); });
                                                                }
                                                            }
                                                        }
                                                        ap.forEach(function (p) {
                                                            if (p.getAdapter(services.RAMLPropertyService).isKey()) {
                                                                return;
                                                            }
                                                            if (p.getAdapter(services.RAMLPropertyService).isSystem()) {
                                                                return;
                                                            }
                                                            if (node.lowLevel().children().some(function (x) { return x.key() == p.nameId(); })) {
                                                                filter[p.nameId()] = true;
                                                            }
                                                        });
                                                        node._computed = true;
                                                    }
                                                }
                                            }
                                        });
                                    }
                                }
                                var parsed = [];
                                if (xChildren.length == 0) {
                                    if (x.valueKind() == yaml.Kind.SEQ) {
                                        if (p.range().key() == universes.Universe08.Parameter) {
                                            var error = new hlimpl.BasicASTNode(x, aNode);
                                            error.errorMessage = {
                                                entry: messageRegistry.PROPERTY_MUST_BE_A_MAP,
                                                parameters: { propName: p.nameId() }
                                            };
                                            res.push(error);
                                        }
                                    }
                                }
                                if (p.nameId() === "documentation" && x.resolvedValueKind() !== yaml.Kind.SEQ) {
                                    if (!aNode.definition().getAdapter(services.RAMLService).isUserDefined()) {
                                        var error = new hlimpl.BasicASTNode(x, aNode);
                                        error.errorMessage = {
                                            entry: messageRegistry.PROPERTY_MUST_BE_A_SEQUENCE,
                                            parameters: { propName: p.nameId() }
                                        };
                                        res.push(error);
                                    }
                                }
                                else {
                                    xChildren.forEach(function (y) {
                                        if (filter[y.key()]) {
                                            return;
                                        }
                                        if (y.valueKind() == yaml.Kind.SEQ) {
                                            var isRaml1 = aNode.definition().universe().version() == "RAML10";
                                            y.children().forEach(function (z) {
                                                var node = new hlimpl.ASTNodeImpl(z, aNode, range, p);
                                                node._allowQuestion = allowsQuestion;
                                                node.setNamePatch(y.key());
                                                if (isRaml1) {
                                                    node.invalidSequence = true;
                                                }
                                                parsed.push(node);
                                            });
                                            if (y.children().length == 0) {
                                                var error = new hlimpl.BasicASTNode(y, aNode);
                                                if (p.range().key() == universes.Universe08.Parameter) {
                                                    error.errorMessage = {
                                                        entry: messageRegistry.NAMED_PARAMETER_NEEDS_TYPE,
                                                        parameters: {}
                                                    };
                                                }
                                                else {
                                                    error.errorMessage = {
                                                        entry: messageRegistry.NODE_SHOULD_HAVE_VALUE,
                                                        parameters: {}
                                                    };
                                                }
                                                res.push(error);
                                            }
                                        }
                                        else {
                                            var node = new hlimpl.ASTNodeImpl(y, aNode, range, p);
                                            var dc = p.domain().key();
                                            if (p.nameId() == "body" && (dc == universes.Universe08.MethodBase || dc == universes.Universe10.MethodBase)) {
                                                node.setComputed("form", "true"); //FIXME
                                            }
                                            node._allowQuestion = allowsQuestion;
                                            parsed.push(node);
                                        }
                                    });
                                }
                                if (parsed.length > 0) {
                                    parsed.forEach(function (x) { return rs.push(x); });
                                }
                                else {
                                    inherited.forEach(function (x) { return rs.push(x); });
                                }
                            }
                        }
                        else {
                            //var y=xChildren[0];
                            rs.push(new hlimpl.ASTNodeImpl(x, aNode, range, p));
                        }
                    }
                    else {
                        var node = new hlimpl.ASTNodeImpl(x, aNode, range, p);
                        node._allowQuestion = allowsQuestion;
                        rs.push(node);
                    }
                    aNode._children = aNode._children.concat(rs);
                    aNode._mergedChildren = null;
                    res = res.concat(rs);
                    rs.forEach(function (x) {
                        var rt = descriminate(p, aNode, x);
                        if (rt && rt != x.definition()) {
                            x.patchType(rt);
                        }
                        x._associatedDef = null;
                        p.childRestrictions().forEach(function (y) {
                            x.setComputed(y.name, y.value);
                        });
                        var def = x.definition();
                    });
                }
            }
            else {
                var unknownNode = new hlimpl.BasicASTNode(x, aNode);
                var addUnknownNode = !proxy.LowLevelCompositeNode.isInstance(x)
                    || x.primaryNode() != null;
                if (!addUnknownNode) {
                    var tType = linter.typeOfContainingTemplate(unknownNode);
                    var i0 = key ? key.indexOf("<<") : -1;
                    var hasParams = i0 >= 0 && key.indexOf(">>", i0) >= 0;
                    if (tType) {
                        if (!hasParams) {
                            addUnknownNode = true;
                        }
                    }
                    else {
                        addUnknownNode = true;
                        if (universeHelpers.isMethodType(aNode.definition())) {
                            tType = aNode.definition().universe().type(def.universesInfo.Universe10.Trait.name);
                        }
                        else if (universeHelpers.isResourceType(aNode.definition())) {
                            tType = aNode.definition().universe().type(def.universesInfo.Universe10.ResourceType.name);
                        }
                        if (tType) {
                            if (tType.property(key) != null) {
                                addUnknownNode = false;
                            }
                        }
                        if (addUnknownNode && hasParams) {
                            addUnknownNode = !definedInTemplate(aNode);
                        }
                    }
                }
                if (addUnknownNode) {
                    res.push(unknownNode);
                }
            }
        });
        var rNode = aNode.reusedNode();
        if (rNode && aNode.lowLevel().valueKind() != yaml.Kind.SEQ) {
            var cObj = {};
            rNode.elements().forEach(function (x) { return cObj[x.property().nameId() + "_" + x.lowLevel().key()] = x; });
            rNode.attrs().forEach(function (x) { return cObj[x.property().nameId() + "_" + x.lowLevel().key()] = x; });
            res.filter(function (ch) { return ch.isElement() || ch.isAttr(); }).forEach(function (ch) {
                var rChild = cObj[ch.property().nameId() + "_" + ch.lowLevel().key()];
                if (rChild && rChild != ch) {
                    if (ch.isElement() && ch.lowLevel().parent().valueKind() != yaml.Kind.SEQ) {
                        ch.setReusedNode(rChild);
                        ch.setReuseMode(aNode.reuseMode());
                    }
                }
            });
        }
        return res;
    };
    return BasicNodeBuilder;
}());
exports.BasicNodeBuilder = BasicNodeBuilder;
function getBaseTypes(node, expression) {
    var universe = node.definition().universe();
    if (!expression) {
        return [universe.type(universes.Universe10.StringTypeDeclaration.name)];
    }
    var pt = node.parsedType();
    var result = mapType(pt, universe);
    return result;
}
function mapType(pt, universe) {
    if (universe === void 0) { universe = def.getUniverse("RAML10"); }
    var result = [];
    if (pt.isString()) {
        result.push(universe.type(universes.Universe10.StringTypeDeclaration.name));
    }
    else if (pt.isNumber()) {
        if (pt.isInteger()) {
            result.push(universe.type(universes.Universe10.IntegerTypeDeclaration.name));
        }
        result.push(universe.type(universes.Universe10.NumberTypeDeclaration.name));
    }
    else if (pt.isBoolean()) {
        result.push(universe.type(universes.Universe10.BooleanTypeDeclaration.name));
    }
    else if (pt.isObject()) {
        result.push(universe.type(universes.Universe10.ObjectTypeDeclaration.name));
    }
    else if (pt.isArray()) {
        result.push(universe.type(universes.Universe10.ArrayTypeDeclaration.name));
    }
    else if (pt.isFile()) {
        result.push(universe.type(universes.Universe10.FileTypeDeclaration.name));
    }
    else if (pt.isDateTime()) {
        result.push(universe.type(universes.Universe10.DateTimeTypeDeclaration.name));
    }
    else if (pt.isDateTimeOnly()) {
        result.push(universe.type(universes.Universe10.DateTimeOnlyTypeDeclaration.name));
    }
    else if (pt.isDateOnly()) {
        result.push(universe.type(universes.Universe10.DateOnlyTypeDeclaration.name));
    }
    else if (pt.isTimeOnly()) {
        result.push(universe.type(universes.Universe10.TimeOnlyTypeDeclaration.name));
    }
    if (pt.isUnion()) {
        result.push(universe.type(universes.Universe10.UnionTypeDeclaration.name));
    }
    if (result.length == 0) {
        result.push(universe.type(universes.Universe10.TypeDeclaration.name));
    }
    return result;
}
exports.mapType = mapType;
function transform(u) {
    return function (x) {
        var m = u.type(x);
        if (!m) {
            var ut = new defs.UserDefinedClass("", u, null, "", "");
        }
        return m;
    };
}
function findFacetInTypeNode(typeNode, facetName) {
    var typeNodeElement = typeNode.asElement();
    if (typeNodeElement == null)
        return null;
    var facets = typeNodeElement.elementsOfKind(universes.Universe10.TypeDeclaration.properties.facets.name);
    if (facets == null || facets.length == 0)
        return null;
    return _.find(facets, function (facet) {
        return facetName == facet.attrValue(universes.Universe10.TypeDeclaration.properties.name.name);
    });
}
function findFacetDeclaration(facet) {
    var owner = facet.owner();
    if (owner == null)
        return null;
    var facetName = facet.facetName();
    if (!facetName)
        return null;
    var ownerSource = owner.getExtra(ramlTypes.SOURCE_EXTRA);
    if (ownerSource == null)
        return null;
    if (!def.isSourceProvider(ownerSource) && !hl.isParseResult(ownerSource)) {
        return null;
    }
    return {
        getSource: function () {
            if (def.isSourceProvider(ownerSource)) {
                var resolvedSource = ownerSource.getSource();
                if (resolvedSource && hl.isParseResult(resolvedSource)) {
                    return findFacetInTypeNode(resolvedSource, facetName);
                }
            }
            else if (hl.isParseResult(ownerSource)) {
                return findFacetInTypeNode(ownerSource, facetName);
            }
            return null;
        },
        getClassIdentifier: function () {
            return [defs.SourceProvider.CLASS_IDENTIFIER];
        }
    };
}
function patchTypeWithFacets(originalTypes, nodeReferencingType, parentOfReferencingNode) {
    var patchedType;
    for (var _i = 0, originalTypes_1 = originalTypes; _i < originalTypes_1.length; _i++) {
        var originalType = originalTypes_1[_i];
        if (originalType == null) {
            continue;
        }
        var parsedRType = nodeReferencingType.parsedType();
        if (!patchedType) {
            patchedType = new defs.NodeClass(nodeReferencingType.name(), nodeReferencingType.definition().universe(), "", "");
            patchedType.addAdapter(parsedRType);
            var prop = nodeReferencingType.property();
            if (universeHelpers.isPropertiesProperty(prop) || universeHelpers.isItemsProperty(prop) || universeHelpers.isFacetsProperty(prop)) {
                patchedType.putExtra(tsInterfaces.USER_DEFINED_EXTRA, true);
            }
        }
        patchedType._superTypes.push(originalType);
        doPatchTypeWithFacets(patchedType, nodeReferencingType, parentOfReferencingNode);
    }
    return patchedType;
}
function doPatchTypeWithFacets(patchedType, nodeReferencingType, parentOfReferencingNode) {
    var parsedRType = nodeReferencingType.parsedType();
    parsedRType.allFacets().forEach(function (facet) {
        if (facet.kind() == defs.tsInterfaces.MetaInformationKind.FacetDeclaration) {
            var propertySource = findFacetDeclaration(facet);
            var facetBasedProperty = null;
            if (propertySource != null) {
                facetBasedProperty = new defs.UserDefinedProp(facet.facetName(), null);
                facetBasedProperty.setSourceProvider(propertySource);
            }
            else {
                facetBasedProperty = new defs.Property(facet.facetName(), "");
            }
            var currentUniverse = null;
            if (parentOfReferencingNode) {
                currentUniverse = parentOfReferencingNode.definition().universe();
            }
            else {
                currentUniverse = nodeReferencingType.definition().universe();
            }
            facetBasedProperty.withRange(currentUniverse.type("StringType"));
            facetBasedProperty.withDomain(patchedType);
            facetBasedProperty.withGroupName(facet.facetName());
            facetBasedProperty.withRequired(false);
            facet.value();
            ramlTypes.setPropertyConstructor(function (x) {
                var v = new defs.Property(x, "");
                v.unmerge();
                return v;
            });
            facetBasedProperty.withRange(ramlTypes.toNominal(facet.value(), transform(nodeReferencingType.definition().universe())));
        }
    });
}
function desc1(p, parent, x) {
    var tp = x.attr("type");
    var value = "";
    if (tp) {
        var baseTypes = getBaseTypes(x, tp.value());
        var patchedType = patchTypeWithFacets(baseTypes, x, parent);
        if (patchedType) {
            if (patchedType.superTypes().length == 0) {
                patchedType._superTypes.push(x.definition().universe().type(universes.Universe10.TypeDeclaration.name));
            }
        }
        return patchedType;
    }
    else {
        var propertiesName = universes.Universe10.ObjectTypeDeclaration.properties.properties.name;
        if (p) {
            if (p.nameId() == "body" || _.find(x.lowLevel().children(), function (x) { return x.key() === propertiesName; })) {
                return x.definition().universe().type(universes.Universe10.ObjectTypeDeclaration.name);
            }
        }
        else {
            if (!parent && x.lowLevel() && _.find(x.lowLevel().children(), function (x) { return x.key() === propertiesName; })) {
                return x.definition().universe().type(universes.Universe10.ObjectTypeDeclaration.name);
            }
        }
        return x.definition().universe().type(universes.Universe10.StringTypeDeclaration.name);
    }
}
function doDescrimination(node) {
    try {
        var nodeDefenitionName = node.definition().nameId();
        var isApi = nodeDefenitionName === universes.Universe10.Api.name || nodeDefenitionName === universes.Universe08.Api.name;
        if (!isApi && !node.property() && !node.parent() && node.definition().nameId() === hlimpl.getFragmentDefenitionName(node)) {
            if (node.property() && node.property().nameId() === universes.Universe10.LibraryBase.properties.annotationTypes.name) {
                return descriminate(null, null, node);
            }
            if (universeHelpers.isTypeDeclarationDescendant(node.definition())) {
                return descriminate(null, null, node);
            }
            var result = null;
            var subTypes = node.definition().allSubTypes();
            subTypes.forEach(function (subType) {
                if (!result && match(subType, node, null)) {
                    result = subType;
                }
            });
            return result;
        }
    }
    catch (exception) {
    }
    return descriminate(node.property(), node.parent(), node);
}
exports.doDescrimination = doDescrimination;
function descriminate(p, parent, x) {
    var n = x.lowLevel();
    if (p) {
        if (p.nameId() == universes.Universe10.FragmentDeclaration.properties.uses.name &&
            p.range().nameId() == universes.Universe10.Library.name) {
            //return null;
        }
    }
    var range = p ? p.range().nameId() : x.definition().nameId();
    if (n._node && n._node['descriminate']) {
        return null;
    }
    if (n._node) {
        n._node['descriminate'] = 1;
    }
    try {
        if (range == universes.Universe10.TypeDeclaration.name || universeHelpers.isItemsProperty(p) || universeHelpers.isTypeProperty(p) || universeHelpers.isSchemaProperty(p)) {
            var res = desc1(p, parent, x);
            if (p || (!p && !parent && x.lowLevel())) {
                if (p && res != null && ((p.nameId() == universes.Universe10.MethodBase.properties.body.name
                    || p.nameId() == universes.Universe10.ArrayTypeDeclaration.properties.items.name
                    || p.nameId() == universes.Universe10.Response.properties.headers.name) ||
                    p.nameId() == universes.Universe10.MethodBase.properties.queryParameters.name)) {
                    var ares = new defs.UserDefinedClass(x.lowLevel().key(), res.universe(), x, x.lowLevel().unit() ? x.lowLevel().unit().path() : "", "");
                    ares._superTypes.push(res);
                    return ares;
                }
                if (res != null && universeHelpers.isAnnotationTypeType(x.definition())) {
                    var annotationType = descriminateAnnotationType(res);
                    var ares = new defs.UserDefinedClass(x.lowLevel().key(), res.universe(), x, x.lowLevel().unit() ? x.lowLevel().unit().path() : "", "");
                    ares._superTypes.push(annotationType);
                    ares._superTypes.push(res);
                    return ares;
                }
            }
            if (res) {
                return res;
            }
        }
        //generic case;
        var rt = null;
        if (p && parent) {
            var types = search.findAllSubTypes(p, parent);
            if (types.length > 0) {
                types.forEach(function (y) {
                    if (!rt) {
                        if (match(y, x, rt)) {
                            rt = y;
                        }
                    }
                });
            }
            return rt;
        }
    }
    finally {
        if (n._node) {
            delete n._node['descriminate'];
        }
    }
}
;
function descriminateAnnotationType(type) {
    var arr = [type].concat(type.allSuperTypes());
    var candidate;
    for (var i = 0; i < arr.length; i++) {
        var t = arr[i];
        if (t.isUserDefined()) {
            continue;
        }
        if (t.isUnion()) {
            var ut = t;
            var lt = ut.leftType();
            var rt = ut.leftType();
            var lat = descriminateAnnotationType(lt);
            var rat = descriminateAnnotationType(lt);
            if (lat.isAssignableFrom(rat.nameId()) && (candidate == null || lat.isAssignableFrom(candidate.nameId()))) {
                candidate = lat;
                continue;
            }
            if (rat.isAssignableFrom(lat.nameId()) && (candidate == null || rat.isAssignableFrom(candidate.nameId()))) {
                candidate = rat;
                continue;
            }
            candidate = type.universe().type(universes.Universe10.UnionTypeDeclaration.name);
            break;
        }
        if (t.isArray()) {
            candidate = type.universe().type(universes.Universe10.ArrayTypeDeclaration.name);
            break;
        }
        var subTypes = t.subTypes();
        for (var j = 0; j < subTypes.length; j++) {
            var st = subTypes[j];
            if (st.isAssignableFrom(universes.Universe10.TypeDeclaration.name)) {
                if (candidate == null) {
                    candidate = st;
                }
                else if (st.isAssignableFrom(candidate.nameId())) {
                    candidate = st;
                }
            }
        }
    }
    return candidate != null ? candidate : type.universe().type(universes.Universe10.TypeDeclaration.name);
}
var isInTtraitOrResourceType = function (aNode) {
    var isInsideTraitOrResourceType = false;
    var parent_ = aNode;
    while (parent_) {
        var pDef = parent_.definition();
        if (universeHelpers.isTraitType(pDef)
            || universeHelpers.isResourceTypeType(pDef)) {
            isInsideTraitOrResourceType = true;
            break;
        }
        parent_ = parent_.parent();
    }
    return isInsideTraitOrResourceType;
};
function match(t, r, alreadyFound) {
    //this.vReqInitied=true;
    if (r.isAttr() || r.isUnknown()) {
        return false;
    }
    var el = r;
    var hasSuperType = _.find(t.superTypes(), function (x) {
        var dp = _.find(x.allProperties(), function (x) { return (x).isDescriminator(); });
        if (dp) {
            var a = el.attr(dp.nameId());
            if (a) {
                if (a.value() == t.nameId()) {
                    return true;
                }
            }
        }
        return false;
    });
    if (hasSuperType) {
        return true;
    }
    if (t.valueRequirements().length == 0) {
        return false;
    }
    var matches = true;
    //descriminating constraint
    t.valueRequirements().forEach(function (x) {
        var a = el.attr(x.name);
        if (a) {
            if (a.value() == x.value) {
                //do nothing
            }
            else {
                if (t.getAdapter(services.RAMLService).getConsumesRefs()) {
                    var vl = a.value();
                    var allSubs = [];
                    t.superTypes().forEach(function (x) { return x.allSubTypes().forEach(function (y) {
                        allSubs.push(y);
                    }); });
                    var allSubNames = [];
                    _.unique(allSubs).forEach(function (x) {
                        allSubNames.push(x.nameId());
                        x.valueRequirements().forEach(function (y) {
                            allSubNames.push(y.value);
                        });
                        x.getAdapter(services.RAMLService).getAliases().forEach(function (y) { return allSubNames.push(y); });
                    });
                    if (_.find(allSubNames, function (x) { return x == vl; })) {
                        matches = false;
                    }
                }
                else {
                    matches = false;
                }
            }
        }
        else {
            var m = t.getAdapter(services.RAMLService).getDefining();
            var ms = false;
            m.forEach(function (x) {
                el.lowLevel().children().forEach(function (y) {
                    if (y.key() == x) {
                        ms = true;
                    }
                });
            });
            if (ms) {
                matches = true;
                return;
            }
            if (!alreadyFound) {
                var pr = t.property(x.name);
                if (pr && pr.defaultValue() == x.value) {
                    //do nothing
                }
                else {
                    matches = false;
                }
            }
            else {
                matches = false;
            }
        }
    });
    return matches;
}
function definedInTemplate(n) {
    var rootDef = n.root().definition();
    if (universeHelpers.isTraitType(rootDef) || universeHelpers.isResourceTypeType(rootDef)) {
        return true;
    }
    if (!rootDef || !(universeHelpers.isLibraryBaseSibling(rootDef)
        || universeHelpers.isApiType(rootDef))) {
        return false;
    }
    var llNode = n.lowLevel();
    if (proxy.LowLevelProxyNode.isInstance(llNode)) {
        llNode = referencePatcher.toOriginal(llNode);
    }
    var collectionNode;
    while (llNode.parent()) {
        collectionNode = llNode;
        llNode = llNode.parent();
    }
    var cKey = collectionNode && collectionNode.key();
    if (cKey == def.universesInfo.Universe10.LibraryBase.properties.traits.name
        || cKey == def.universesInfo.Universe10.LibraryBase.properties.resourceTypes.name) {
        return true;
    }
    return false;
}
//# sourceMappingURL=builder.js.map