/* Generated from Java with JSweet 2.3.7 - http://www.jsweet.org */
import { NodeCompat } from '../../compat/NodeCompat';
/**
 * Construct a node path from a string representation.
 * @param {string} path
 * @class
 * @author eric.wittmann@gmail.com
 */
var NodePath = /** @class */ (function () {
    function NodePath(path) {
        var _this = this;
        if (((typeof path === 'string') || path === null)) {
            var __args = arguments;
            this.segments = ([]);
            this.segments = ([]);
            (function () {
                if (path != null && path.indexOf("/") === 0 && !(function (o1, o2) { if (o1 && o1.equals) {
                    return o1.equals(o2);
                }
                else {
                    return o1 === o2;
                } })(path, "/")) {
                    var currentScanType = NodePath.SCAN_TYPE_PATH;
                    var currentIdx = 1;
                    while ((currentIdx < path.length)) {
                        {
                            var segStart = currentIdx;
                            var segEnd = void 0;
                            if (currentScanType === NodePath.SCAN_TYPE_PATH) {
                                var nextPathSep = path.indexOf("/", segStart);
                                var nextBrace = path.indexOf("[", segStart);
                                if (nextPathSep === -1) {
                                    nextPathSep = path.length;
                                }
                                if (nextBrace === -1) {
                                    nextBrace = path.length;
                                }
                                if (nextPathSep <= nextBrace) {
                                    segEnd = nextPathSep;
                                }
                                else {
                                    segEnd = nextBrace;
                                }
                            }
                            else {
                                var nextCloseBrace = path.indexOf("]", segStart);
                                if (nextCloseBrace === -1) {
                                    nextCloseBrace = path.length;
                                }
                                segEnd = nextCloseBrace + 1;
                            }
                            var seg = path.substring(segStart, segEnd);
                            var segment = NodePath.NodePathSegment.fromString(seg);
                            /* add */ (_this.segments.push(segment) > 0);
                            currentScanType = NodePath.SCAN_TYPE_PATH;
                            currentIdx = segEnd + 1;
                            if (segEnd >= path.length) {
                            }
                            else if ((function (c) { return c.charCodeAt == null ? c : c.charCodeAt(0); })(path.charAt(segEnd)) == '/'.charCodeAt(0)) {
                                currentScanType = NodePath.SCAN_TYPE_PATH;
                                currentIdx = segEnd + 1;
                            }
                            else if ((function (c) { return c.charCodeAt == null ? c : c.charCodeAt(0); })(path.charAt(segEnd)) == '['.charCodeAt(0)) {
                                currentScanType = NodePath.SCAN_TYPE_INDEX;
                                currentIdx = segEnd;
                            }
                            else if ((function (c) { return c.charCodeAt == null ? c : c.charCodeAt(0); })(path.charAt(segEnd)) == ']'.charCodeAt(0)) {
                                if ((function (c) { return c.charCodeAt == null ? c : c.charCodeAt(0); })(path.charAt(segEnd + 1)) == '['.charCodeAt(0)) {
                                    currentScanType = NodePath.SCAN_TYPE_INDEX;
                                    currentIdx = segEnd + 1;
                                }
                                else if ((function (c) { return c.charCodeAt == null ? c : c.charCodeAt(0); })(path.charAt(segEnd + 1)) == '/'.charCodeAt(0)) {
                                    currentScanType = NodePath.SCAN_TYPE_PATH;
                                    currentIdx = segEnd + 1;
                                }
                            }
                        }
                    }
                    ;
                }
            })();
        }
        else if (path === undefined) {
            var __args = arguments;
            this.segments = ([]);
            this.segments = ([]);
        }
        else
            throw new Error('invalid overload');
    }
    NodePath.prototype.prependSegment = function (value, index) {
        if (index === void 0) { index = false; }
        /* add */ this.segments.splice(0, 0, new NodePath.NodePathSegment(value, index));
    };
    NodePath.prototype.appendSegment = function (value, index) {
        if (index === void 0) { index = false; }
        /* add */ (this.segments.push(new NodePath.NodePathSegment(value, index)) > 0);
    };
    /**
     * Resolves a path to its target node within the document model.  This basically
     * walks the tree according to the path segments until it reaches the node being
     * referenced.  If the path does not point to a valid node, then this method
     * returns undefined.
     * @param {Document} document the document to resolve the path relative to
     * @return {Node}
     */
    NodePath.prototype.resolve = function (document) {
        return this.resolveWithVisitor(document, null);
    };
    /**
     * Resolves a path to its target node while also visiting all nodes along the way.
     * @param {Document} document the document to resolve the path relative to
     * @param {*} visitor an optional visitor to invoke for each node in the path (can be null)
     * @return {Node}
     */
    NodePath.prototype.resolveWithVisitor = function (document, visitor) {
        var node = document;
        if (visitor != null) {
            node.accept(visitor);
        }
        var oNode = node;
        for (var index166 = 0; index166 < this.segments.length; index166++) {
            var segment = this.segments[index166];
            {
                oNode = segment.resolve(oNode);
                if (visitor != null && oNode != null && (oNode != null && (oNode["__interfaces"] != null && oNode["__interfaces"].indexOf("io.apicurio.datamodels.core.models.IVisitable") >= 0 || oNode.constructor != null && oNode.constructor["__interfaces"] != null && oNode.constructor["__interfaces"].indexOf("io.apicurio.datamodels.core.models.IVisitable") >= 0))) {
                    oNode.accept(visitor);
                }
            }
        }
        return oNode;
    };
    /**
     * Returns true if this path "contains" the given node.  The path is said to contain
     * a node if the node is visited while resolving it.  In other words, if one of the
     * segments of the path represents the node, then this will return true, otherwise it
     * will return false.
     * @param {Node} node
     * @return {boolean}
     */
    NodePath.prototype.contains = function (node) {
        var tnode = node.ownerDocument();
        if (tnode === node) {
            return true;
        }
        for (var index167 = 0; index167 < this.segments.length; index167++) {
            var segment = this.segments[index167];
            {
                tnode = segment.resolve(tnode);
                if (tnode === node) {
                    return true;
                }
            }
        }
        return false;
    };
    NodePath.prototype.toSegments = function () {
        var rval = ([]);
        this.segments.forEach((function (rval) {
            return function (segment) {
                /* add */ (rval.push(segment.getValue()) > 0);
            };
        })(rval));
        return rval;
    };
    /**
     * @see java.lang.Object#toString()
     * @return {string}
     */
    NodePath.prototype.toString = function () {
        if ( /* size */this.segments.length === 0) {
            return "/";
        }
        var rval = "";
        for (var index168 = 0; index168 < this.segments.length; index168++) {
            var segment = this.segments[index168];
            {
                if (segment.isIndex()) {
                    rval += '[' + segment.asString() + ']';
                }
                else {
                    rval += '/' + segment.asString();
                }
            }
        }
        return rval;
    };
    NodePath.SCAN_TYPE_PATH = 0;
    NodePath.SCAN_TYPE_INDEX = 1;
    return NodePath;
}());
export { NodePath };
NodePath["__class"] = "io.apicurio.datamodels.core.models.NodePath";
(function (NodePath) {
    /**
     * Constructor.
     *
     * @param {string} value RAW (non-escaped) segment value or null
     * @param {boolean} index
     * @class
     * @author eric.wittmann@gmail.com
     */
    var NodePathSegment = /** @class */ (function () {
        function NodePathSegment(value, index) {
            var _this = this;
            if (((typeof value === 'string') || value === null) && ((typeof index === 'boolean') || index === null)) {
                var __args = arguments;
                {
                    var __args_1 = arguments;
                    if (this.value === undefined)
                        this.value = null;
                    if (this.index === undefined)
                        this.index = false;
                    if (this.value === undefined)
                        this.value = null;
                    if (this.index === undefined)
                        this.index = false;
                    (function () {
                        _this.value = value;
                        _this.index = false;
                    })();
                }
                (function () {
                    _this.index = index;
                })();
            }
            else if (((typeof value === 'string') || value === null) && index === undefined) {
                var __args = arguments;
                if (this.value === undefined)
                    this.value = null;
                if (this.index === undefined)
                    this.index = false;
                if (this.value === undefined)
                    this.value = null;
                if (this.index === undefined)
                    this.index = false;
                (function () {
                    _this.value = value;
                    _this.index = false;
                })();
            }
            else
                throw new Error('invalid overload');
        }
        /**
         * @return {string} RAW (non-escaped) segment value or null
         */
        NodePathSegment.prototype.getValue = function () {
            return this.value;
        };
        NodePathSegment.prototype.isIndex = function () {
            return this.index;
        };
        /**
         * Resolves a single segment.
         * @param {*} from
         * @return {*}
         */
        NodePathSegment.prototype.resolve = function (from) {
            if (from == null) {
                return null;
            }
            var childNode = null;
            if (this.isIndex() && (from != null && (from["__interfaces"] != null && from["__interfaces"].indexOf("io.apicurio.datamodels.core.models.IIndexedNode") >= 0 || from.constructor != null && from.constructor["__interfaces"] != null && from.constructor["__interfaces"].indexOf("io.apicurio.datamodels.core.models.IIndexedNode") >= 0))) {
                childNode = from.getItem(this.getValue());
            }
            else if (this.getValue().indexOf("x-") === 0) {
                var fromNode = from;
                if (fromNode.isExtensible()) {
                    childNode = from.getExtension(this.getValue());
                }
                else {
                    childNode = null;
                }
            }
            else {
                childNode = NodeCompat.getProperty(from, this.getValue());
            }
            return childNode;
        };
        /**
         * This is a reverse operation to {@link #fromString(String)}.
         * Not using "toString" as the method name is intentional,
         * since the format of that methods output should not be assumed
         * to be stable and precisely defined.
         *
         * @return {string} ESCAPED segment value or null
         */
        NodePathSegment.prototype.asString = function () {
            if (this.getValue() == null)
                return null;
            return NodePathSegment.escapePathSegmentValue(this.getValue(), !this.isIndex());
        };
        /**
         * Creates a segment from an ESCAPED string.
         * @param {string} segment Escaped segment value. If it represents an "indexed"
         * node, it MUST be surrounded by '[' and ']'.
         * @return {NodePath.NodePathSegment}
         */
        NodePathSegment.fromString = function (segment) {
            if (segment == null) {
                return new NodePath.NodePathSegment(null);
            }
            var isIndex = false;
            if (segment.indexOf("[") === 0 && segment.indexOf("]") === (segment.length - 1)) {
                segment = segment.substring(1, segment.length - 1);
                isIndex = true;
            }
            segment = NodePathSegment.unescapePathSegmentValue(segment);
            return new NodePath.NodePathSegment(segment, isIndex);
        };
        /**
         * When a path is represented as a string,
         * we are using three characters with special meaning
         * to encode it's structure.
         * '/' to separate path segments, and '[' with ']' to denote a segment for an "indexed" node.
         * Since these characters can also appear in the segment values themselves (in their non-special meaning),
         * they have to be escaped.
         * The following rules are used, inspired by <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>:
         * - The escape character is '~', preceding a number which determines which special character is encoded.
         * - '~1' = '/'
         * - '~2' = '['
         * - '~3' = ']'
         * The escape character is itself encoded as '~0'.
         *
         * @param {boolean} escapeSlash In the "indexed" segment, '/' can be used unescaped.
         * @param {string} rawValue
         * @return {string}
         * @private
         */
        NodePathSegment.escapePathSegmentValue = function (rawValue, escapeSlash) {
            var res = rawValue.split("~").join("~0");
            if (escapeSlash)
                res = /* replace */ res.split("/").join("~1");
            res = /* replace */ res.split("[").join("~2");
            res = /* replace */ res.split("]").join("~3");
            return res;
        };
        /**
         * @see io.apicurio.datamodels.core.models.NodePath.NodePathSegment#escapePathSegmentValue(String, boolean)
         * @param {string} escapedValue
         * @return {string}
         * @private
         */
        NodePathSegment.unescapePathSegmentValue = function (escapedValue) {
            var res = escapedValue.split("~3").join("]");
            res = /* replace */ res.split("~2").join("[");
            res = /* replace */ res.split("~1").join("/");
            res = /* replace */ res.split("~0").join("~");
            return res;
        };
        return NodePathSegment;
    }());
    NodePath.NodePathSegment = NodePathSegment;
    NodePathSegment["__class"] = "io.apicurio.datamodels.core.models.NodePath.NodePathSegment";
})(NodePath || (NodePath = {}));
//# sourceMappingURL=NodePath.js.map