"use strict";
var __values = (this && this.__values) || function (o) {
    var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
    if (m) return m.call(o);
    return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
};
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var child_process_1 = __importDefault(require("child_process"));
var path_1 = __importDefault(require("path"));
var fs_1 = __importDefault(require("fs"));
function getCommitHistory(fileName) {
    var rawLog = _fetchFileHistory(fileName);
    return _parseGitLogOutput(rawLog);
}
exports.default = getCommitHistory;
function _fetchFileHistory(fileName) {
    var directory;
    var format = ('{"id": "%H", "authorName": "%an", "relativeDate": "%cr", "authorDate": %at, ' +
        ' "message": "%s", "body": "%b", "hash": "%h"}').replace(/\"/g, '#/dquotes/');
    var flags = " --pretty=\"format:" + format + "\" --topo-order --date=local --numstat --follow";
    var fstats = fs_1.default.statSync(fileName);
    if (fstats.isDirectory()) {
        directory = fileName;
        fileName = '.';
    }
    else {
        directory = path_1.default.dirname(fileName);
        fileName = _escapeForCli(path_1.default.basename(fileName));
    }
    var cmd = "git log" + flags + " " + fileName;
    if (process.env.DEBUG === '1') {
        console.warn("$ " + cmd);
    }
    return child_process_1.default.execSync(cmd, {
        stdio: 'pipe',
        cwd: directory,
    }).toString();
}
function _parseGitLogOutput(output) {
    var e_1, _a;
    var logItems = [];
    var logLines = output.split('\n');
    var currentCommitText = null;
    var totalLinesAdded = 0;
    var totalLinesDeleted = 0;
    var files = [];
    var addLogItem = function () {
        var commitObj = _parseCommitObj(currentCommitText);
        if (!commitObj) {
            console.warn("failed to parse commit Object: " + currentCommitText);
        }
        else {
            commitObj.linesAdded = totalLinesAdded;
            commitObj.linesDeleted = totalLinesDeleted;
            commitObj.files = files;
            logItems.push(commitObj);
        }
        totalLinesAdded = 0;
        totalLinesDeleted = 0;
        return (files = []);
    };
    try {
        for (var logLines_1 = __values(logLines), logLines_1_1 = logLines_1.next(); !logLines_1_1.done; logLines_1_1 = logLines_1.next()) {
            var line = logLines_1_1.value;
            var matches;
            if (line.match(/^\{\#\/dquotes\/id\#\/dquotes\/\:/)) {
                if (currentCommitText != null) {
                    addLogItem();
                }
                currentCommitText = line;
            }
            else if ((matches = line.match(/^([\d\-]+)\s+([\d\-]+)\s+(.*)/))) {
                var _b = __read(matches.slice(1), 3), linesAdded = _b[0], linesDeleted = _b[1], fileName = _b[2];
                linesAdded = parseInt(linesAdded);
                linesDeleted = parseInt(linesDeleted);
                totalLinesAdded += linesAdded;
                totalLinesDeleted += linesDeleted;
                files.push({
                    name: fileName.trim(),
                    linesAdded: linesAdded,
                    linesDeleted: linesDeleted,
                });
            }
            else if (line != null) {
                currentCommitText += line;
            }
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (logLines_1_1 && !logLines_1_1.done && (_a = logLines_1.return)) _a.call(logLines_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
    if (currentCommitText) {
        addLogItem();
    }
    return logItems;
}
function _parseCommitObj(line) {
    var encLine = line
        .replace(/\t/g, '  ')
        .replace(/\"/g, "'")
        .replace(/(\n|\n\r)/g, ' <br>')
        .replace(/\r/g, ' <br>')
        .replace(/\#\/dquotes\//g, '"')
        .replace(/\\/g, '\\\\')
        .replace(/[\x00-\x1F\x7F-\x9F]/g, ' ');
    try {
        return JSON.parse(encLine);
    }
    catch (error) {
        console.warn(line + '\n\n');
        console.warn("failed to parse JSON " + encLine);
        return null;
    }
}
function _escapeForCli(filePath) {
    var escapePrefix = process.platform === 'win32' ? '^' : '\\';
    return filePath.replace(/([\s\(\)\-])/g, escapePrefix + '$1');
}
