/*---------------------------------------------------------
 * Copyright (C) Microsoft Corporation. All rights reserved.
 *--------------------------------------------------------*/
"use strict";
const path = require("path");
const url = require("url");
const utils = require("../utils");
const vscode_debugadapter_1 = require("vscode-debugadapter");
/**
 * Resolves a relative path in terms of another file
 */
function resolveRelativeToFile(absPath, relPath) {
    return path.resolve(path.dirname(absPath), relPath);
}
exports.resolveRelativeToFile = resolveRelativeToFile;
/**
 * Determine the absolute path to the sourceRoot.
 */
function getComputedSourceRoot(sourceRoot, generatedPath, webRoot = '') {
    let absSourceRoot;
    if (sourceRoot) {
        if (sourceRoot.startsWith('file:///')) {
            // sourceRoot points to a local path like "file:///c:/project/src", make it an absolute path
            absSourceRoot = utils.canonicalizeUrl(sourceRoot);
        }
        else if (sourceRoot.startsWith('/')) {
            // sourceRoot is like "/src", would be like http://localhost/src, resolve to a local path under webRoot
            // note that C:/src (or /src as an absolute local path) is not a valid sourceroot
            absSourceRoot = path.join(webRoot, sourceRoot);
        }
        else {
            // sourceRoot is like "src" or "../src", relative to the script
            if (path.isAbsolute(generatedPath)) {
                absSourceRoot = resolveRelativeToFile(generatedPath, sourceRoot);
            }
            else {
                // generatedPath is a URL so runtime script is not on disk, resolve the sourceRoot location on disk
                const genDirname = path.dirname(url.parse(generatedPath).pathname);
                absSourceRoot = path.join(webRoot, genDirname, sourceRoot);
            }
        }
        vscode_debugadapter_1.logger.log(`SourceMap: resolved sourceRoot ${sourceRoot} -> ${absSourceRoot}`);
    }
    else if (path.isAbsolute(generatedPath)) {
        absSourceRoot = path.dirname(generatedPath);
        vscode_debugadapter_1.logger.log(`SourceMap: no sourceRoot specified, using script dirname: ${absSourceRoot}`);
    }
    else {
        // runtime script is not on disk, resolve the sourceRoot location on disk
        const urlPath = url.parse(generatedPath).pathname;
        const scriptPathDirname = urlPath ? path.dirname(urlPath) : ''; // could be debugadapter://123, no other info.
        absSourceRoot = path.join(webRoot, scriptPathDirname);
        vscode_debugadapter_1.logger.log(`SourceMap: no sourceRoot specified, using webRoot + script path dirname: ${absSourceRoot}`);
    }
    absSourceRoot = utils.stripTrailingSlash(absSourceRoot);
    absSourceRoot = utils.fixDriveLetterAndSlashes(absSourceRoot);
    return absSourceRoot;
}
exports.getComputedSourceRoot = getComputedSourceRoot;
/**
 * Applies a set of path pattern mappings to the given path. See tests for examples.
 * Returns something validated to be an absolute path.
 */
function applySourceMapPathOverrides(sourcePath, sourceMapPathOverrides) {
    const forwardSlashSourcePath = sourcePath.replace(/\\/g, '/');
    // Iterate the key/vals, only apply the first one that matches.
    // for...in iterates in order, (unless the key is a number)
    for (let pattern in sourceMapPathOverrides) {
        let replacePattern = sourceMapPathOverrides[pattern];
        const entryStr = `"${pattern}": "${replacePattern}"`;
        // Validate the entry
        if (!path.isAbsolute(replacePattern)) {
            vscode_debugadapter_1.logger.log(`Warning: sourceMapPathOverrides entry does not map to an absolute path - ${entryStr}`);
            continue;
        }
        const asterisks = pattern.match(/\*/g) || [];
        if (asterisks.length > 1) {
            vscode_debugadapter_1.logger.log(`Warning: only one asterisk allowed in a sourceMapPathOverrides entry - ${entryStr}`);
            continue;
        }
        const replacePatternAsterisks = replacePattern.match(/\*/g) || [];
        if (replacePatternAsterisks.length > asterisks.length) {
            vscode_debugadapter_1.logger.log(`Warning: the right side of a sourceMapPathOverrides entry must have 0 or 1 asterisks - ${entryStr}}`);
            continue;
        }
        // Does it match?
        const patternSegment = pattern
            .replace(/\*/g, '(.*)')
            .replace(/\\/g, '/');
        const patternRegex = new RegExp(`^${patternSegment}$`, 'i');
        const overridePatternMatches = forwardSlashSourcePath.match(patternRegex);
        if (!overridePatternMatches)
            continue;
        // Grab the value of the wildcard from the match above, replace the wildcard in the
        // replacement pattern, and return the result.
        const wildcardValue = overridePatternMatches[1];
        let mappedPath = replacePattern.replace(/\*/g, wildcardValue);
        mappedPath = path.join(mappedPath); // Fix any ..
        vscode_debugadapter_1.logger.log(`SourceMap: mapping ${sourcePath} => ${mappedPath}, via sourceMapPathOverrides entry - ${entryStr}`);
        return mappedPath;
    }
    return sourcePath;
}
exports.applySourceMapPathOverrides = applySourceMapPathOverrides;
function resolveMapPath(pathToGenerated, mapPath) {
    if (!utils.isURL(mapPath)) {
        if (utils.isURL(pathToGenerated)) {
            const scriptUrl = url.parse(pathToGenerated);
            const scriptPath = scriptUrl.pathname;
            if (!scriptPath) {
                return null;
            }
            // runtime script is not on disk, map won't be either, resolve a URL for the map relative to the script
            const mapUrlPathSegment = mapPath.startsWith('/') ? mapPath : path.posix.join(path.dirname(scriptPath), mapPath);
            mapPath = `${scriptUrl.protocol}//${scriptUrl.host}${mapUrlPathSegment}`;
        }
        else if (path.isAbsolute(pathToGenerated)) {
            // mapPath needs to be resolved to an absolute path or a URL
            // runtime script is on disk, so map should be too
            mapPath = resolveRelativeToFile(pathToGenerated, mapPath);
        }
    }
    return mapPath;
}
exports.resolveMapPath = resolveMapPath;

//# sourceMappingURL=sourceMapUtils.js.map
