"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var path = require("path");
var URL = require("url");
var util = require("../util/index");
var linter = require("./ast.core/linter");
var messageRegistry = require("../../resources/errorMessages");
var ASTDelta = /** @class */ (function () {
    function ASTDelta() {
    }
    return ASTDelta;
}());
exports.ASTDelta = ASTDelta;
var CommandKind;
(function (CommandKind) {
    CommandKind[CommandKind["ADD_CHILD"] = 0] = "ADD_CHILD";
    CommandKind[CommandKind["REMOVE_CHILD"] = 1] = "REMOVE_CHILD";
    CommandKind[CommandKind["MOVE_CHILD"] = 2] = "MOVE_CHILD";
    CommandKind[CommandKind["CHANGE_KEY"] = 3] = "CHANGE_KEY";
    CommandKind[CommandKind["CHANGE_VALUE"] = 4] = "CHANGE_VALUE";
    CommandKind[CommandKind["INIT_RAML_FILE"] = 5] = "INIT_RAML_FILE";
})(CommandKind = exports.CommandKind || (exports.CommandKind = {}));
var TextChangeCommand = /** @class */ (function () {
    function TextChangeCommand(offset, replacementLength, text, unit, target) {
        if (target === void 0) { target = null; }
        this.offset = offset;
        this.replacementLength = replacementLength;
        this.text = text;
        this.unit = unit;
        this.target = target;
    }
    return TextChangeCommand;
}());
exports.TextChangeCommand = TextChangeCommand;
var CompositeCommand = /** @class */ (function () {
    function CompositeCommand() {
        this.commands = [];
    }
    return CompositeCommand;
}());
exports.CompositeCommand = CompositeCommand;
var InsertionPointType;
(function (InsertionPointType) {
    InsertionPointType[InsertionPointType["NONE"] = 0] = "NONE";
    InsertionPointType[InsertionPointType["START"] = 1] = "START";
    InsertionPointType[InsertionPointType["END"] = 2] = "END";
    InsertionPointType[InsertionPointType["POINT"] = 3] = "POINT";
})(InsertionPointType = exports.InsertionPointType || (exports.InsertionPointType = {}));
var ASTChangeCommand = /** @class */ (function () {
    function ASTChangeCommand(kind, target, value, position) {
        this.toSeq = false;
        this.kind = kind;
        this.target = target;
        this.value = value;
        this.position = position;
    }
    return ASTChangeCommand;
}());
exports.ASTChangeCommand = ASTChangeCommand;
function setAttr(t, value) {
    return new ASTChangeCommand(CommandKind.CHANGE_VALUE, t, value, -1);
}
exports.setAttr = setAttr;
function setAttrStructured(t, value) {
    return new ASTChangeCommand(CommandKind.CHANGE_VALUE, t, value.lowLevel(), -1);
}
exports.setAttrStructured = setAttrStructured;
function setKey(t, value) {
    return new ASTChangeCommand(CommandKind.CHANGE_KEY, t, value, -1);
}
exports.setKey = setKey;
function removeNode(t, child) {
    return new ASTChangeCommand(CommandKind.REMOVE_CHILD, t, child, -1);
}
exports.removeNode = removeNode;
function insertNode(t, child, insertAfter, toSeq) {
    if (insertAfter === void 0) { insertAfter = null; }
    if (toSeq === void 0) { toSeq = false; }
    var s = new ASTChangeCommand(CommandKind.ADD_CHILD, t, child, -1);
    s.insertionPoint = insertAfter;
    s.toSeq = toSeq;
    return s;
}
exports.insertNode = insertNode;
function initRamlFile(root, newroot) {
    return new ASTChangeCommand(CommandKind.INIT_RAML_FILE, root, newroot, -1);
}
exports.initRamlFile = initRamlFile;
var LineMapperImpl = /** @class */ (function () {
    function LineMapperImpl(content, absPath) {
        this.content = content;
        this.absPath = absPath;
    }
    LineMapperImpl.prototype.position = function (_pos) {
        var pos = _pos;
        this.initMapping();
        for (var i = 0; i < this.mapping.length; i++) {
            var lineLength = this.mapping[i];
            if (pos < lineLength) {
                return {
                    line: i,
                    column: pos,
                    position: _pos
                };
            }
            pos -= lineLength;
        }
        if (pos == 0) {
            return {
                line: this.mapping.length - 1,
                column: this.mapping[this.mapping.length - 1],
                position: this.content.length
            };
        }
        if (pos == 1) {
            //sometimes YAML library reports an error at a position of document length + 1, no idea what they want
            //to tell us that way
            return {
                line: this.mapping.length - 1,
                column: this.mapping[this.mapping.length - 1] - 1,
                position: _pos - 1
            };
        }
        throw new Error(linter.applyTemplate(messageRegistry.POSITION_EXCEEDS_TEXT_LENGTH, { pos: _pos, length: this.content.length, absPath: this.absPath }));
    };
    LineMapperImpl.prototype.initMapping = function () {
        if (this.mapping != null) {
            return;
        }
        if (this.content == null) {
            throw new Error(linter.applyTemplate(messageRegistry.LINE_MAPPER_HAS_NULL_CONTENT, { path: this.absPath != null ? ('. Path: ' + this.absPath) : ' and null path.' }));
        }
        this.mapping = [];
        var ind = 0;
        var l = this.content.length;
        for (var i = 0; i < l; i++) {
            if (this.content.charAt(i) == '\r') {
                if (i < l - 1 && this.content.charAt(i + 1) == '\n') {
                    this.mapping.push(i - ind + 2);
                    ind = i + 2;
                    i++;
                }
                else {
                    this.mapping.push(i - ind + 1);
                    ind = i + 1;
                }
            }
            else if (this.content.charAt(i) == '\n') {
                this.mapping.push(i - ind + 1);
                ind = i + 1;
            }
        }
        this.mapping.push(l - ind);
    };
    LineMapperImpl.prototype.toPosition = function (line, _column) {
        var column = _column;
        this.initMapping();
        for (var i = line; i < this.mapping.length; i++) {
            var lineLength = this.mapping[i];
            if (column < lineLength) {
                var pos = column;
                for (var j = 0; j < i; j++) {
                    pos += this.mapping[j];
                }
                return {
                    line: i,
                    column: column,
                    position: pos
                };
            }
            column -= lineLength;
        }
        return {
            line: i,
            column: column,
            position: this.content.length
        };
    };
    return LineMapperImpl;
}());
exports.LineMapperImpl = LineMapperImpl;
/**
 * Canonic way of resolving references in RAML specs:
 * * relative reference is regarded as relative to containing unit
 * * absolute local path (starting with slash) is regarderd as relative to root RAML
 * * absolute web paths are regarded as such
 *
 * @param reference reference to be resolved
 * @param unitPath path of unit containing the reference, absolute or relative to root
 * @param rootPath path to root RAML
 * @returns resolved path
 */
function buildPath(reference, unitPath, rootPath) {
    if (path.isAbsolute(reference)) {
        var e = path.extname(unitPath);
        if ( /*e!=".json"&&*/e != ".xsd") {
            //SUPPORTING 0.8 style resolving due to compatiblity reasons
            reference = reference.substr(1);
            unitPath = toAbsolutePath(rootPath, path.basename(unitPath));
        }
    }
    if (isWebPath(reference) || path.isAbsolute(reference)) {
        return reference;
    }
    if (isWebPath(unitPath) || path.isAbsolute(unitPath)) {
        return toAbsolutePath(path.dirname(unitPath), reference);
    }
    return toAbsolutePath(path.dirname(toAbsolutePath(rootPath, unitPath)), reference);
}
exports.buildPath = buildPath;
/**
 * Resolving reference against context
 * * absolute local and web references are regarded as such
 * * relative references are regarded as relative to the context
 * @param context absolute local or web path
 * @param reference
 * @returns resolved reference
 */
function toAbsolutePath(context, reference) {
    if (isWebPath(reference)) {
        return reference;
    }
    var apath;
    if (isWebPath(context)) {
        var rp = util.stringEndsWith(context, "/") ? context : context + "/";
        apath = URL.resolve(rp, reference).replace(/\\/g, "/");
    }
    else {
        apath = path.resolve(context, reference).replace(/\\/g, "/");
    }
    return apath;
}
exports.toAbsolutePath = toAbsolutePath;
/**
 * Check if reference points to web resource
 * @param reference
 * @returns {boolean}
 */
function isWebPath(reference) {
    if (reference == null)
        return false;
    return util.stringStartsWith(reference, "http://") || util.stringStartsWith(reference, "https://");
}
exports.isWebPath = isWebPath;
function isLowLevelNode(object) {
    return object.start && object.end && object.unit && object.key
        && object.value && object.children && object.includePath;
}
exports.isLowLevelNode = isLowLevelNode;
//# sourceMappingURL=lowLevelAST.js.map