"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Formatter_1 = require("../common/Formatter");
var fs_1 = require("fs");
var url_1 = require("url");
var path_1 = require("path");
var source_map_1 = require("source-map");
var Formatter = (function (_super) {
    __extends(Formatter, _super);
    function Formatter() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Formatter.prototype._getSource = function (tracepath) {
        var match;
        var source;
        var line;
        var col;
        var map;
        var originalPos;
        var result;
        if (tracepath === '<anonymous>') {
            return 'anonymous';
        }
        if (!(match = /^(.*?):(\d+)(:\d+)?$/.exec(tracepath))) {
            return tracepath;
        }
        tracepath = match[1];
        line = Number(match[2]);
        col = match[3] ? Number(match[3].substring(1)) : null;
        tracepath = path_1.resolve(url_1.parse(tracepath).pathname);
        source = path_1.relative('.', tracepath);
        if (tracepath in instrumentationSourceMap) {
            map = instrumentationSourceMap[tracepath];
            originalPos = getOriginalPosition(map, line, col);
            line = originalPos.line;
            col = originalPos.column;
            if (originalPos.source) {
                source = originalPos.source;
            }
        }
        if ((map = getSourceMap(tracepath))) {
            originalPos = getOriginalPosition(map, line, col);
            line = originalPos.line;
            col = originalPos.column;
            if (originalPos.source) {
                source = path_1.join(path_1.dirname(source), originalPos.source);
            }
        }
        result = source + ':' + line;
        if (col !== null) {
            result += ':' + col;
        }
        return result;
    };
    return Formatter;
}(Formatter_1.default));
exports.default = Formatter;
var instrumentationSourceMap = {};
var fileSourceMaps = {};
var fileSources = {};
function getOriginalPosition(map, line, column) {
    var originalPosition = map.originalPositionFor({ line: line, column: column });
    if (originalPosition.line !== null) {
        return originalPosition;
    }
    var entries = [];
    map.eachMapping(function (entry) {
        if (entry.generatedLine === line) {
            entries.push(entry);
        }
    }, null, map.GENERATED_ORDER);
    if (entries.length === 0) {
        return { line: line, column: column };
    }
    originalPosition = entries[0];
    if (column !== null) {
        var entry = void 0;
        for (var i = 1; i < entries.length; i++) {
            entry = entries[i];
            if (column > originalPosition.generatedColumn && column >= entry.generatedColumn) {
                originalPosition = entry;
            }
        }
    }
    return {
        line: originalPosition.originalLine,
        column: originalPosition.originalColumn,
        source: originalPosition.source
    };
}
function getSourceMap(filepath) {
    var data;
    var rawMap;
    var lines;
    var lastLine;
    var match;
    var sourceMapRegEx = /(?:\/{2}[#@]{1,2}|\/\*)\s+sourceMappingURL\s*=\s*(data:(?:[^;]+;)+base64,)?(\S+)/;
    if (filepath in fileSourceMaps) {
        return fileSourceMaps[filepath];
    }
    try {
        if (filepath in fileSources) {
            data = fileSources[filepath];
        }
        else {
            data = fs_1.readFileSync(filepath).toString('utf-8');
            fileSources[filepath] = data;
        }
        lines = data.trim().split('\n');
        lastLine = lines[lines.length - 1];
        if ((match = sourceMapRegEx.exec(lastLine))) {
            if (match[1]) {
                rawMap = JSON.parse((new Buffer(match[2], 'base64').toString('utf8')));
                fileSourceMaps[filepath] = new source_map_1.SourceMapConsumer(rawMap);
            }
            else {
                var mapFile = path_1.join(path_1.dirname(filepath), match[2]);
                rawMap = JSON.parse(fs_1.readFileSync(mapFile, { encoding: 'utf8' }));
                fileSourceMaps[filepath] = new source_map_1.SourceMapConsumer(rawMap);
            }
            return fileSourceMaps[filepath];
        }
    }
    catch (error) {
        return null;
    }
}
//# sourceMappingURL=Formatter.js.map