"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var hl = require("../highLevelAST");
var hlimpl = require("../highLevelImpl");
var stubs = require("../stubs");
var _ = require("underscore");
var universeDef = require("../tools/universe");
var universes = require("../tools/universe");
var util = require("../../util/index");
var expander = require("../ast.core/expanderLL");
var proxy = require("../ast.core/LowLevelASTProxy");
var referencePatcher = require("../ast.core/referencePatcherLL");
var search = require("../../search/search-interface");
var universeHelpers = require("../tools/universeHelpers");
/**
 * __$helperMethod__
 * Retrieve an ordered list of all uri parameters including those which are not described in the `uriParameters` node.
 * Consider a fragment of RAML specification:
 * ```yaml
 * /resource/{objectId}/{propertyId}:
 *   uriParameters:
 *     objectId:
 * ```
 * Here `propertyId` uri parameter is not described in the `uriParameters` node,
 * but it is among Resource.allUriParameters().
 * __$meta__={"name":"allUriParameters","deprecated":true}
 */
function uriParameters(resource, serializeMetadata) {
    if (serializeMetadata === void 0) { serializeMetadata = false; }
    var propName = universes.Universe10.ResourceBase.properties.uriParameters.name;
    var params = resource.elementsOfKind(propName);
    if (!universeHelpers.isResourceType(resource.definition())) {
        return params;
    }
    var uriAttr = resource.attr(universes.Universe10.Resource.properties.relativeUri.name);
    var uri = uriAttr.value();
    return extractParams(params, uri, resource, propName, serializeMetadata, uriAttr);
}
exports.uriParameters = uriParameters;
/**
 * __$helperMethod__
 * Retrieve an ordered list of all base uri parameters regardless of whether they are described in `baseUriParameters` or not
 * Consider a fragment of RAML specification:
 * ```yaml
 * version: v1
 * baseUri: https://{organization}.example.com/{version}/{service}
 * baseUriParameters:
 *   service:
 * ```
 * Here `version` and `organization` are base uri parameters which are not described in the `baseUriParameters` node,
 * but they are among `Api.allBaseUriParameters()`.
 * __$meta__={"name":"allBaseUriParameters","deprecated":true}
 */
function baseUriParameters(api, serializeMetadata) {
    if (serializeMetadata === void 0) { serializeMetadata = true; }
    var buriAttr = api.attr(universes.Universe10.Api.properties.baseUri.name);
    var uri = buriAttr ? buriAttr.value() : '';
    var propName = universes.Universe10.Api.properties.baseUriParameters.name;
    var params = api.elementsOfKind(propName);
    return extractParams(params, uri, api, propName, serializeMetadata, buriAttr);
}
exports.baseUriParameters = baseUriParameters;
function extractParams(params, uri, ownerHl, propName, serializeMetadata, propAttr) {
    if (typeof (uri) != 'string') {
        return [];
    }
    var definition = ownerHl.definition();
    var prop = definition.property(propName);
    if (!uri) {
        return [];
    }
    var describedParams = {};
    params.forEach(function (x) {
        var arr = describedParams[x.name()];
        if (!arr) {
            arr = [];
            describedParams[x.name()] = arr;
        }
        arr.push(x);
    });
    var allParams = [];
    var prev = 0;
    var mentionedParams = {};
    for (var i = uri.indexOf('{'); i >= 0; i = uri.indexOf('{', prev)) {
        prev = uri.indexOf('}', ++i);
        if (prev < 0) {
            break;
        }
        var paramName = uri.substring(i, prev);
        mentionedParams[paramName] = true;
        if (describedParams[paramName]) {
            describedParams[paramName].forEach(function (x) { return allParams.push(x); });
        }
        else {
            var propUnit = hlimpl.actualUnit(propAttr.lowLevel());
            var universe = definition.universe();
            var nc = universe.type(universeDef.Universe10.StringTypeDeclaration.name);
            var hlNode = stubs.createStubNode(nc, null, paramName, propUnit);
            hlNode.setParent(ownerHl);
            if (serializeMetadata) {
                hlNode.wrapperNode().meta().setCalculated();
            }
            hlNode.attrOrCreate("name").setValue(paramName);
            hlNode.patchProp(prop);
            allParams.push(hlNode);
        }
    }
    Object.keys(describedParams).filter(function (x) { return !mentionedParams[x]; })
        .forEach(function (x) { return describedParams[x].forEach(function (y) { return allParams.push(y); }); });
    return allParams;
}
;
//__$helperMethod__ Path relative to API root
function completeRelativeUri(res) {
    var uri = '';
    var parent = res;
    do {
        res = parent; //(parent instanceof RamlWrapper.ResourceImpl) ? <RamlWrapper.Resource>parent : null;
        uri = res.attr(universeDef.Universe10.Resource.properties.relativeUri.name).value() + uri;
        parent = res.parent();
    } while (universeHelpers.isResourceType(parent.definition()));
    return uri;
}
exports.completeRelativeUri = completeRelativeUri;
//__$helperMethod__ baseUri of owning Api concatenated with completeRelativeUri
function absoluteUri(res) {
    if (!universeHelpers.isResourceType(res.definition())) {
        return null;
    }
    var uri = '';
    var parent = res;
    do {
        res = parent; //(parent instanceof RamlWrapper.ResourceImpl) ? <RamlWrapper.Resource>parent : null;
        uri = res.attr(universeDef.Universe10.Resource.properties.relativeUri.name).value() + uri;
        parent = res.parent();
    } while (universeHelpers.isResourceType(parent.definition()));
    var base = "";
    parent = parent.getSlaveCounterPart() || parent;
    var buriAttr = parent.attr(universeDef.Universe10.Api.properties.baseUri.name);
    if (buriAttr) {
        base = buriAttr ? buriAttr.value() : "";
    }
    base = base ? base : '';
    if (res) {
        base = base.replace(/\/+$/, "");
    }
    uri = base + uri;
    return uri;
}
exports.absoluteUri = absoluteUri;
/**
 * __$helperMethod__
 * __$meta__={"name":"example","primary":true}
 */
function typeExample(node, dumpXMLRepresentationOfExamples) {
    if (dumpXMLRepresentationOfExamples === void 0) { dumpXMLRepresentationOfExamples = false; }
    var examples = exampleObjects(node, true, dumpXMLRepresentationOfExamples);
    return examples.length > 0 ? examples[0] : null;
}
exports.typeExample = typeExample;
/**
 * __$helperMethod__
 * __$meta__={"name":"examples","primary":true}
 */
function typeExamples(node, dumpXMLRepresentationOfExamples) {
    if (dumpXMLRepresentationOfExamples === void 0) { dumpXMLRepresentationOfExamples = false; }
    return exampleObjects(node, false, dumpXMLRepresentationOfExamples);
}
exports.typeExamples = typeExamples;
function dumpExpandableExample(ex, dumpXMLRepresentationOfExamples) {
    if (dumpXMLRepresentationOfExamples === void 0) { dumpXMLRepresentationOfExamples = false; }
    var obj;
    if (ex.isJSONString() || ex.isYAML()) {
        obj = ex.asJSON();
    }
    else {
        obj = ex.original();
    }
    var sObj = {
        value: obj,
        strict: ex.strict(),
        name: ex.name()
    };
    if (ex.hasAnnotations()) {
        var annotations = ex.annotations();
        var annotationsArray = toAnnotations(annotations);
        if (annotationsArray.length > 0) {
            sObj["annotations"] = annotationsArray;
        }
    }
    if (ex.hasScalarAnnotations()) {
        var sAnnotations_1 = ex.scalarsAnnotations();
        var saObj_1 = {};
        Object.keys(sAnnotations_1).forEach(function (pName) {
            var annotationsArray = toAnnotations(sAnnotations_1[pName]);
            if (annotationsArray.length > 0) {
                saObj_1[pName] = [annotationsArray];
            }
        });
        if (Object.keys(saObj_1).length > 0) {
            sObj["scalarsAnnotations"] = saObj_1;
        }
    }
    var displayName = ex.displayName();
    if (displayName) {
        sObj["displayName"] = displayName;
    }
    var description = ex.description();
    if (description != null) {
        sObj["description"] = description;
    }
    if (dumpXMLRepresentationOfExamples) {
        sObj.asXMLString = ex.asXMLString();
    }
    return sObj;
}
exports.dumpExpandableExample = dumpExpandableExample;
function exampleObjects(node, isSingle, dumpXMLRepresentationOfExamples) {
    if (dumpXMLRepresentationOfExamples === void 0) { dumpXMLRepresentationOfExamples = false; }
    var lt = node.localType();
    if (lt.isAnnotationType()) {
        lt = _.find(lt.superTypes(), function (x) { return x.nameId() == lt.nameId(); });
    }
    var examples = lt.examples().filter(function (x) { return x != null && !x.isEmpty() && (x.isSingle() == isSingle); })
        .map(function (ex) { return dumpExpandableExample(ex, dumpXMLRepresentationOfExamples); });
    return examples;
}
function toAnnotations(annotations) {
    var arr = [];
    if (annotations) {
        Object.keys(annotations).forEach(function (aName) {
            arr.push({
                name: aName,
                value: annotations[aName].value()
            });
        });
    }
    return arr;
}
/**
 * __$helperMethod__ Retrieve all traits including those defined in libraries
 * __$meta__{"deprecated":true}
 */
function allTraits(hlNode, serializeMetadata) {
    if (serializeMetadata === void 0) { serializeMetadata = true; }
    if (hlNode.lowLevel().actual().libExpanded) {
        return [];
    }
    return findTemplates(hlNode, function (d) { return universeHelpers.isTraitType(d); }, serializeMetadata, "Trait");
}
exports.allTraits = allTraits;
/**
 * __$helperMethod__ Retrieve all resource types including those defined in libraries
 * __$meta__{"deprecated":true}
 */
function allResourceTypes(hlNode, serializeMetadata) {
    if (serializeMetadata === void 0) { serializeMetadata = true; }
    if (hlNode.lowLevel().actual().libExpanded) {
        return [];
    }
    return findTemplates(hlNode, function (d) { return universeHelpers.isResourceTypeType(d); }, serializeMetadata, "ResourceType");
}
exports.allResourceTypes = allResourceTypes;
function findTemplates(hlNode, filter, serializeMetadata, typeName) {
    var arr = search.globalDeclarations(hlNode).filter(function (x) { return filter(x.definition()); });
    var ll = hlNode.lowLevel();
    var nodePath = ll.includePath();
    if (!nodePath) {
        nodePath = ll.unit().path();
    }
    var isProxy = hlNode.definition().universe().version() == "RAML10"
        && !universeHelpers.isOverlayType(hlNode.definition());
    var exp = isProxy ? new expander.TraitsAndResourceTypesExpander() : null;
    var result = [];
    var rp = new referencePatcher.ReferencePatcher();
    var pName = (typeName == "ResourceType" ? "resourceTypes" : "traits");
    var prop = hlNode.definition().allProperties().find(function (x) { return x.nameId() == pName; });
    for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) {
        var x = arr_1[_i];
        var p = x.lowLevel().unit().path();
        if (isProxy) {
            if (!proxy.LowLevelProxyNode.isInstance(x.lowLevel())) {
                x = exp.createHighLevelNode(x, false, rp, true, false);
                rp.process(x.lowLevel(), hlNode.lowLevel(), typeName, true, true, pName);
                x.setParent(hlNode);
                x.patchProp(prop);
            }
        }
        if (serializeMetadata && p != nodePath) {
            x.wrapperNode().meta().setCalculated();
        }
        result.push(x);
    }
    return result;
}
/**
 * __$helperMethod__
 * __$meta__={"primary":true}
 **/
function schemaContent08(bodyDeclaration) {
    return schemaContent08Internal(bodyDeclaration);
}
exports.schemaContent08 = schemaContent08;
function schemaContent08Internal(bodyDeclaration, cache) {
    var schemaAttribute = bodyDeclaration.attr(universes.Universe08.BodyLike.properties.schema.name);
    if (!schemaAttribute) {
        return null;
    }
    var schemaString = schemaAttribute.value();
    if (!schemaString) {
        return null;
    }
    if (util.stringStartsWith(schemaString, "{")
        || util.stringStartsWith(schemaString, "[")
        || util.stringStartsWith(schemaString, "<")) {
        return schemaAttribute;
    }
    var declaration;
    if (cache) {
        declaration = cache[schemaString];
    }
    else {
        var root = bodyDeclaration.root();
        var globalSchemas = root.elementsOfKind(universes.Universe08.Api.properties.schemas.name);
        declaration = _.find(globalSchemas, function (x) { return x.name() == schemaString; });
    }
    if (!declaration) {
        return schemaAttribute;
    }
    if (!declaration)
        return schemaAttribute;
    if (!declaration.getKind || declaration.getKind() != hl.NodeKind.NODE) {
        return schemaAttribute;
    }
    //we found the schema declaration and should get its contents
    if (declaration.definition().key() != universes.Universe08.GlobalSchema) {
        return schemaAttribute;
    }
    var valueAttribute = declaration.attr(universes.Universe08.GlobalSchema.properties.value.name);
    if (valueAttribute == null) {
        return null;
    }
    return valueAttribute;
}
exports.schemaContent08Internal = schemaContent08Internal;
/**
 * __$helperMethod__
 * __$meta__={"name":"parametrizedProperties","primary":true}
 */
function getTemplateParametrizedProperties(node) {
    var type = node.definition();
    if (universeHelpers.isMethodType(type) || universeHelpers.isTypeDeclarationDescendant(type)) {
        var isInsideTemplate = false;
        var parent = node.parent();
        while (parent != null) {
            var pDef = parent.definition();
            if (universeHelpers.isResourceTypeType(pDef) || universeHelpers.isTraitType(pDef)) {
                isInsideTemplate = true;
                break;
            }
            parent = parent.parent();
        }
        if (!isInsideTemplate) {
            return null;
        }
    }
    if (node == null) {
        return null;
    }
    var lowLevelNode = node.lowLevel();
    if (lowLevelNode == null) {
        return null;
    }
    var children = lowLevelNode.children().filter(function (x) {
        var key = x.key();
        if (!key) {
            return false;
        }
        if (key.charAt(0) == "(" && key.charAt(key.length - 1) == ")") {
            return false;
        }
        return key.indexOf("<<") >= 0;
    });
    if (children.length == 0) {
        return null;
    }
    var result = {};
    children.forEach(function (x) {
        var obj = x.dumpToObject();
        Object.keys(obj).forEach(function (y) { return result[y] = obj[y]; });
    });
    return result;
}
exports.getTemplateParametrizedProperties = getTemplateParametrizedProperties;
/**
 * __$helperMethod__
 * __$meta__={"name":"fixedFacets","primary":true}
 */
function typeFixedFacets(td) {
    var rDef = td.localType();
    var obj = rDef.fixedFacets();
    var keys = Object.keys(obj);
    var arr = [];
    if (!rDef.hasUnionInHierarchy()) {
        for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
            var key = keys_1[_i];
            if (rDef.facet(key) != null) {
                arr.push({
                    name: key,
                    value: obj[key]
                });
            }
        }
    }
    else {
        arr = keys.map(function (key) {
            return {
                name: key,
                value: obj[key]
            };
        });
    }
    if (arr.length == 0) {
        return null;
    }
    return arr;
}
exports.typeFixedFacets = typeFixedFacets;
//# sourceMappingURL=helpersLL.js.map