/*---------------------------------------------------------
 * Copyright (C) Microsoft Corporation. All rights reserved.
 *--------------------------------------------------------*/
"use strict";
const path = require("path");
const fs = require("fs");
const basePathTransformer_1 = require("./basePathTransformer");
const vscode_debugadapter_1 = require("vscode-debugadapter");
const utils = require("../utils");
const errors = require("../errors");
/**
 * Converts a local path from Code to a path on the target.
 */
class RemotePathTransformer extends basePathTransformer_1.BasePathTransformer {
    attach(args) {
        // Maybe validate that it's absolute, for either windows or unix
        this._remoteRoot = args.remoteRoot;
        // Validate that localRoot is absolute and exists
        let localRootP = Promise.resolve();
        if (args.localRoot) {
            const localRoot = args.localRoot;
            if (!path.isAbsolute(localRoot)) {
                return Promise.reject(errors.attributePathRelative('localRoot', localRoot));
            }
            localRootP = new Promise((resolve, reject) => {
                fs.exists(localRoot, exists => {
                    if (!exists) {
                        reject(errors.attributePathNotExist('localRoot', localRoot));
                    }
                    this._localRoot = localRoot;
                    resolve();
                });
            });
        }
        return localRootP;
    }
    setBreakpoints(args) {
        if (args.source.path) {
            args.source.path = this.getTargetPathFromClientPath(args.source.path);
        }
        return super.setBreakpoints(args);
    }
    scriptParsed(scriptPath) {
        scriptPath = this.getClientPathFromTargetPath(scriptPath);
        return super.scriptParsed(scriptPath);
    }
    stackTraceResponse(response) {
        response.stackFrames.forEach(frame => {
            const remotePath = frame.source && frame.source.path;
            if (remotePath) {
                const localPath = this.getClientPathFromTargetPath(remotePath);
                if (utils.existsSync(localPath)) {
                    frame.source.path = localPath;
                    frame.source.sourceReference = undefined;
                    frame.source.origin = undefined;
                }
            }
        });
    }
    shouldMapPaths(remotePath) {
        // Map paths only if localRoot/remoteRoot are set, and the remote path is absolute on some system
        return !!this._localRoot && !!this._remoteRoot && (path.posix.isAbsolute(remotePath) || path.win32.isAbsolute(remotePath));
    }
    getClientPathFromTargetPath(remotePath) {
        if (!this.shouldMapPaths(remotePath))
            return remotePath;
        const relPath = relative(this._remoteRoot, remotePath);
        let localPath = join(this._localRoot, relPath);
        localPath = utils.fixDriveLetterAndSlashes(localPath);
        vscode_debugadapter_1.logger.log(`Mapped remoteToLocal: ${remotePath} -> ${localPath}`);
        return localPath;
    }
    getTargetPathFromClientPath(localPath) {
        if (!this.shouldMapPaths(localPath))
            return localPath;
        const relPath = relative(this._localRoot, localPath);
        let remotePath = join(this._remoteRoot, relPath);
        remotePath = utils.fixDriveLetterAndSlashes(remotePath, /*uppercaseDriveLetter=*/ true);
        vscode_debugadapter_1.logger.log(`Mapped localToRemote: ${localPath} -> ${remotePath}`);
        return remotePath;
    }
}
exports.RemotePathTransformer = RemotePathTransformer;
/**
 * Cross-platform path.relative
 */
function relative(a, b) {
    return a.match(/^[A-Za-z]:/) ?
        path.win32.relative(a, b) :
        path.posix.relative(a, b);
}
/**
 * Cross-platform path.join
 */
function join(a, b) {
    return a.match(/^[A-Za-z]:/) ?
        path.win32.join(a, b) :
        utils.forceForwardSlashes(path.posix.join(a, b));
}

//# sourceMappingURL=remotePathTransformer.js.map
