"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const util = require("util");
const sourcemap = require("source-map");
const sourceMapConverter = require("convert-source-map");
const helpers_1 = require("../common/helpers");
const constants_1 = require("../constants");
class LogSourceMapService {
    constructor($fs, $projectDataService, $injector, $devicePlatformsConstants) {
        this.$fs = $fs;
        this.$projectDataService = $projectDataService;
        this.$injector = $injector;
        this.$devicePlatformsConstants = $devicePlatformsConstants;
        this.getProjectData = _.memoize(this.$projectDataService.getProjectData.bind(this.$projectDataService));
    }
    replaceWithOriginalFileLocations(platform, messageData, loggingOptions) {
        if (!messageData || !loggingOptions.projectDir) {
            return messageData;
        }
        const projectData = this.getProjectData(loggingOptions.projectDir);
        const lines = messageData.split("\n");
        const isAndroid = platform.toLowerCase() === this.$devicePlatformsConstants.Android.toLowerCase();
        const parserFunction = isAndroid ? this.parseAndroidLog.bind(this, projectData) : this.parseIosLog.bind(this);
        let outputData = "";
        lines.forEach(rawLine => {
            const parsedLine = parserFunction(rawLine);
            const originalLocation = this.getOriginalFileLocation(platform, parsedLine, projectData);
            if (originalLocation && originalLocation.sourceFile) {
                const { sourceFile, line, column } = originalLocation;
                outputData = `${outputData}${parsedLine.messagePrefix}${LogSourceMapService.FILE_PREFIX}${sourceFile}:${line}:${column}${parsedLine.messageSuffix}\n`;
            }
            else if (rawLine !== "") {
                outputData = `${outputData}${rawLine}\n`;
            }
        });
        return outputData;
    }
    getOriginalFileLocation(platform, parsedLine, projectData) {
        const fileLoaction = path.join(this.getFilesLocation(platform, projectData), constants_1.APP_FOLDER_NAME);
        if (parsedLine && parsedLine.filePath) {
            const sourceMapFile = path.join(fileLoaction, parsedLine.filePath);
            if (this.$fs.exists(sourceMapFile)) {
                const source = this.$fs.readText(sourceMapFile);
                const sourceMapRaw = sourceMapConverter.fromSource(source);
                if (sourceMapRaw && sourceMapRaw.sourcemap) {
                    const sourceMap = sourceMapRaw.sourcemap;
                    const smc = new sourcemap.SourceMapConsumer(sourceMap);
                    const originalPosition = smc.originalPositionFor({ line: parsedLine.line, column: parsedLine.column });
                    let sourceFile = originalPosition.source && originalPosition.source.replace("webpack:///", "");
                    if (sourceFile) {
                        if (!_.startsWith(sourceFile, constants_1.NODE_MODULES_FOLDER_NAME)) {
                            sourceFile = path.join(projectData.getAppDirectoryRelativePath(), sourceFile);
                        }
                        sourceFile = helpers_1.stringReplaceAll(sourceFile, "/", path.sep);
                        return { sourceFile, line: originalPosition.line, column: originalPosition.column };
                    }
                }
            }
        }
    }
    parseAndroidLog(projectData, rawMessage) {
        const fileIndex = rawMessage.lastIndexOf(LogSourceMapService.FILE_PREFIX);
        const deviceProjectPath = util.format(constants_1.ANDROID_DEVICE_APP_ROOT_TEMPLATE, projectData.projectIdentifiers.android);
        let separator = ",";
        let messageSuffix = "";
        let parts, filePath, line, column, messagePrefix;
        if (fileIndex >= 0) {
            const fileSubstring = rawMessage.substring(fileIndex + LogSourceMapService.FILE_PREFIX.length);
            parts = fileSubstring.split(separator);
            if (parts.length >= 3) {
                parts[0] = parts[0].replace("'", "");
                parts[1] = parts[1].replace(" line: ", "");
                parts[2] = parts[2].replace(" column: ", "");
            }
            else {
                separator = ":";
                parts = fileSubstring.split(separator);
            }
            if (parts.length >= 3) {
                const devicePath = `${deviceProjectPath}/${constants_1.APP_FOLDER_NAME}/`;
                filePath = path.relative(devicePath, `${"/"}${parts[0]}`);
                line = parseInt(parts[1]);
                column = parseInt(parts[2]);
                messagePrefix = rawMessage.substring(0, fileIndex);
                for (let i = 3; i < parts.length; i++) {
                    messageSuffix += `${parts[i]}${i === (parts.length - 1) ? "" : separator}`;
                }
                messagePrefix = _.trimEnd(messagePrefix, "(");
            }
        }
        return { filePath, line, column, messagePrefix, messageSuffix };
    }
    parseIosLog(rawMessage) {
        const fileIndex = rawMessage.lastIndexOf(LogSourceMapService.FILE_PREFIX);
        let messageSuffix = "";
        let parts, filePath, line, column, messagePrefix;
        if (fileIndex >= 0) {
            const fileSubstring = rawMessage.substring(fileIndex + LogSourceMapService.FILE_PREFIX.length);
            parts = fileSubstring.split(":");
            if (parts && parts.length >= 3) {
                filePath = parts[0];
                if (_.startsWith(filePath, constants_1.APP_FOLDER_NAME)) {
                    filePath = path.relative(constants_1.APP_FOLDER_NAME, parts[0]);
                }
                line = parseInt(parts[1]);
                column = parseInt(parts[2]);
                messagePrefix = rawMessage.substring(0, fileIndex);
                for (let i = 3; i < parts.length; i++) {
                    messageSuffix += `${parts[i]}${i === (parts.length - 1) ? "" : ":"}`;
                }
            }
        }
        return { filePath, line, column, messagePrefix, messageSuffix };
    }
    getFilesLocation(platform, projectData) {
        try {
            const platformsData = this.$injector.resolve("platformsDataService").getPlatformData(platform.toLowerCase(), projectData);
            return platformsData.appDestinationDirectoryPath;
        }
        catch (err) {
            return "";
        }
    }
}
LogSourceMapService.FILE_PREFIX = "file:///";
exports.LogSourceMapService = LogSourceMapService;
$injector.register("logSourceMapService", LogSourceMapService);
