/* Generated from Java with JSweet 2.3.7 - http://www.jsweet.org */
import { Library } from '../../../Library';
import { Document } from '../../../core/models/Document';
import { ReferenceResolverChain } from '../../../core/util/ReferenceResolverChain';
import { VisitorUtil } from '../../../core/util/VisitorUtil';
import { TraverserDirection } from '../../../core/visitors/TraverserDirection';
import { DocumentType } from '../../../core/models/DocumentType';
/**
 * Setup the dereferencer execution.
 *
 * @param {Document} source   original {@link Document}
 * @param {*} resolver provide a custom resolver, otherwise the common {@link io.apicurio.datamodels.core.util.ReferenceResolverChain}
 * is used.
 * @param {boolean} strict   If true, and there are any references that cannot be resolved, raise an exception.
 * Defaults to false.
 * @class
 * @author Jakub Senko <jsenko@redhat.com>
 */
var Dereferencer = /** @class */ (function () {
    function Dereferencer(source, resolver, strict) {
        var _this = this;
        if (((source != null && source instanceof Document) || source === null) && ((resolver != null && (resolver["__interfaces"] != null && resolver["__interfaces"].indexOf("io.apicurio.datamodels.core.util.IReferenceResolver") >= 0 || resolver.constructor != null && resolver.constructor["__interfaces"] != null && resolver.constructor["__interfaces"].indexOf("io.apicurio.datamodels.core.util.IReferenceResolver") >= 0)) || resolver === null) && ((typeof strict === 'boolean') || strict === null)) {
            var __args = arguments;
            if (this.source === undefined)
                this.source = null;
            if (this.resolver === undefined)
                this.resolver = null;
            if (this.strict === undefined)
                this.strict = false;
            this.unresolvable = ([]);
            if (this.source === undefined)
                this.source = null;
            if (this.resolver === undefined)
                this.resolver = null;
            if (this.strict === undefined)
                this.strict = false;
            this.unresolvable = ([]);
            (function () {
                _this.source = source;
                _this.resolver = resolver;
                _this.strict = strict;
            })();
        }
        else if (((source != null && source instanceof Document) || source === null) && resolver === undefined && strict === undefined) {
            var __args = arguments;
            {
                var __args_1 = arguments;
                var resolver_1 = ReferenceResolverChain.getInstance();
                var strict_1 = false;
                if (this.source === undefined)
                    this.source = null;
                if (this.resolver === undefined)
                    this.resolver = null;
                if (this.strict === undefined)
                    this.strict = false;
                this.unresolvable = ([]);
                if (this.source === undefined)
                    this.source = null;
                if (this.resolver === undefined)
                    this.resolver = null;
                if (this.strict === undefined)
                    this.strict = false;
                this.unresolvable = ([]);
                (function () {
                    _this.source = source;
                    _this.resolver = resolver_1;
                    _this.strict = strict_1;
                })();
            }
        }
        else
            throw new Error('invalid overload');
    }
    /**
     * Execute the algorithm.
     *
     * @return {Document} dereferenced clone of the source document.
     * @throws java.lang.RuntimeException if strict and some references could not be dereferenced
     */
    Dereferencer.prototype.dereference = function () {
        var clone = Library.cloneDocument(this.source);
        var strategy = null;
        switch ((clone.getDocumentType())) {
            case DocumentType.asyncapi2:
                strategy = new Aai20IReferenceManipulationStrategy();
                break;
            case DocumentType.openapi2:
                strategy = new Oas20IReferenceManipulationStrategy();
                break;
            case DocumentType.openapi3:
                strategy = new Oas30IReferenceManipulationStrategy();
                break;
            default:
                throw Object.defineProperty(new Error("Unknown document type: " + clone.getDocumentType()), '__classes', { configurable: true, value: ['java.lang.Throwable', 'java.lang.Object', 'java.lang.RuntimeException', 'java.lang.Exception'] });
        }
        var processQueue = ([]);
        /* add */ (processQueue.push(new Dereferencer.Context(this, null, clone)) > 0);
        var resolvedToLocalMap = ({});
        {
            var array180 = /* keySet */ Object.keys(strategy.getExistingLocalComponents(clone));
            for (var index179 = 0; index179 < array180.length; index179++) {
                var ref = array180[index179];
                {
                    /* put */ (resolvedToLocalMap[ref] = ref);
                }
            }
        }
        while ((!(processQueue.length == 0))) {
            {
                var item = processQueue.splice(0, 1)[0];
                var localComponents = strategy.getExistingLocalComponents(clone);
                var rcv = new ReferenceCollectionVisitor();
                VisitorUtil.visitTree(item.node, rcv, TraverserDirection.down);
                var referencedNodes = rcv.getReferencedNodes();
                for (var index181 = 0; index181 < referencedNodes.length; index181++) {
                    var node = referencedNodes[index181];
                    {
                        if (item.parentRef == null && /* containsKey */ localComponents.hasOwnProperty(node.getReference()))
                            continue;
                        var originalRef = new Reference(node.getReference());
                        var resolvedRef = originalRef;
                        if (item.parentRef != null && resolvedRef.isRelative()) {
                            resolvedRef = resolvedRef.withAbsoluteFrom(new Reference(item.parentRef));
                        }
                        if ( /* containsKey */resolvedToLocalMap.hasOwnProperty(resolvedRef.getRef())) {
                            node.setReference(/* get */ (function (m, k) { return m[k] === undefined ? null : m[k]; })(resolvedToLocalMap, resolvedRef.getRef()));
                            continue;
                        }
                        var resolved = this.resolver.resolveRef(resolvedRef.getRef(), node);
                        if (resolved == null) {
                            /* add */ (function (s, e) { if (s.indexOf(e) == -1) {
                                s.push(e);
                                return true;
                            }
                            else {
                                return false;
                            } })(this.unresolvable, node.getReference());
                        }
                        else {
                            var localRef = null;
                            var name_1 = originalRef.getName();
                            for (var i = 0; i < 2147483647; i++) {
                                {
                                    if (i > 0)
                                        name_1 = originalRef.getName() + i;
                                    try {
                                        localRef = strategy.attachAsDefinition(clone, name_1, resolved);
                                        break;
                                    }
                                    catch (ex) {
                                    }
                                    ;
                                }
                                ;
                            }
                            if (localRef == null) {
                                /* add */ (function (s, e) { if (s.indexOf(e) == -1) {
                                    s.push(e);
                                    return true;
                                }
                                else {
                                    return false;
                                } })(this.unresolvable, node.getReference());
                            }
                            else {
                                node.setReference(localRef.getRef());
                                /* add */ (processQueue.push(new Dereferencer.Context(this, originalRef.getRef(), localRef.getNode())) > 0);
                                /* put */ (resolvedToLocalMap[resolvedRef.getRef()] = localRef.getRef());
                            }
                        }
                    }
                }
            }
        }
        ;
        if ( /* size */this.unresolvable.length !== 0 && this.strict)
            throw Object.defineProperty(new Error("Could not resolve some references: " + /* implicit toString */ (function (a) { return a ? '[' + a.join(', ') + ']' : 'null'; })(this.unresolvable)), '__classes', { configurable: true, value: ['java.lang.Throwable', 'java.lang.Object', 'java.lang.RuntimeException', 'java.lang.Exception'] });
        return clone;
    };
    Dereferencer.prototype.getResolver = function () {
        return this.resolver;
    };
    Dereferencer.prototype.isStrict = function () {
        return this.strict;
    };
    /**
     * After {@link #dereference()} is executed and strict is false,
     *
     * @return {string[]} a possibly non-empty set of unresolved references
     */
    Dereferencer.prototype.getUnresolvableReferences = function () {
        return (this.unresolvable.slice(0));
    };
    return Dereferencer;
}());
export { Dereferencer };
Dereferencer["__class"] = "io.apicurio.datamodels.openapi.visitors.dereference.Dereferencer";
(function (Dereferencer) {
    /**
     * State for each recursive step
     * @class
     */
    var Context = /** @class */ (function () {
        function Context(__parent, parentRef, node) {
            this.__parent = __parent;
            if (this.parentRef === undefined)
                this.parentRef = null;
            if (this.node === undefined)
                this.node = null;
            this.parentRef = parentRef;
            this.node = node;
        }
        /**
         *
         * @param {*} o
         * @return {boolean}
         */
        Context.prototype.equals = function (o) {
            if (this === o)
                return true;
            if (o == null || this.constructor !== o.constructor)
                return false;
            var context = o;
            if (this.parentRef != null ? !(function (o1, o2) { if (o1 && o1.equals) {
                return o1.equals(o2);
            }
            else {
                return o1 === o2;
            } })(this.parentRef, context.parentRef) : context.parentRef != null)
                return false;
            return this.node != null ? /* equals */ (function (o1, o2) { if (o1 && o1.equals) {
                return o1.equals(o2);
            }
            else {
                return o1 === o2;
            } })(this.node, context.node) : context.node == null;
        };
        /**
         *
         * @return {number}
         */
        Context.prototype.hashCode = function () {
            var result = this.parentRef != null ? /* hashCode */ (function (o) { if (o.hashCode) {
                return o.hashCode();
            }
            else {
                return o.toString().split('').reduce(function (prevHash, currVal) { return (((prevHash << 5) - prevHash) + currVal.charCodeAt(0)) | 0; }, 0);
            } })(this.parentRef) : 0;
            result = 31 * result + (this.node != null ? /* hashCode */ (function (o) { if (o.hashCode) {
                return o.hashCode();
            }
            else {
                return o.toString().split('').reduce(function (prevHash, currVal) { return (((prevHash << 5) - prevHash) + currVal.charCodeAt(0)) | 0; }, 0);
            } })(this.node) : 0);
            return result;
        };
        return Context;
    }());
    Dereferencer.Context = Context;
    Context["__class"] = "io.apicurio.datamodels.openapi.visitors.dereference.Dereferencer.Context";
})(Dereferencer || (Dereferencer = {}));
import { Reference } from './Reference';
import { ReferenceCollectionVisitor } from './ReferenceCollectionVisitor';
import { Oas30IReferenceManipulationStrategy } from './Oas30IReferenceManipulationStrategy';
import { Oas20IReferenceManipulationStrategy } from './Oas20IReferenceManipulationStrategy';
import { Aai20IReferenceManipulationStrategy } from './Aai20IReferenceManipulationStrategy';
//# sourceMappingURL=Dereferencer.js.map