"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 __());
    };
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Reporter_1 = require("./Reporter");
var lang_1 = require("@dojo/core/lang");
var util_1 = require("util");
var charm = require("charm");
var TextReport = require("istanbul/lib/report/text");
var Collector = require("istanbul/lib/collector");
var encode = require("charm/lib/encode");
var eventHandler = Reporter_1.createEventHandler();
var Pretty = (function (_super) {
    __extends(Pretty, _super);
    function Pretty(executor, config) {
        if (config === void 0) { config = {}; }
        var _this = _super.call(this, executor, config) || this;
        _this._spinnerOffset = 0;
        _this.dimensions = config.dimensions || {};
        _this.titleWidth = config.titleWidth || 12;
        _this.maxProgressBarWidth = config.maxProgressBarWidth || 40;
        _this.colorReplacement = lang_1.mixin({
            0: ANSI_COLOR.green + '✓',
            1: ANSI_COLOR.reset + '~',
            2: ANSI_COLOR.red + '×',
            '✓': ANSI_COLOR.green,
            '!': ANSI_COLOR.red,
            '×': ANSI_COLOR.red,
            '~': ANSI_COLOR.reset,
            '⚠': ANSI_COLOR.yellow
        }, config.colorReplacement);
        _this._header = '';
        _this._reports = {};
        _this._log = [];
        _this.tunnelState = '';
        _this._renderTimeout = undefined;
        _this._total = new Report();
        return _this;
    }
    Pretty.prototype.runStart = function () {
        var _this = this;
        this._header = this.executor.config.name;
        this._charm = this._charm || this._newCharm();
        var resize = function () {
            _this.dimensions.width = process.stdout.columns || 80;
            _this.dimensions.height = process.stdout.rows || 24;
        };
        resize();
        process.stdout.on('resize', resize);
        var rerender = function () {
            _this._charm.erase('screen').position(0, 0);
            _this._render();
            _this._renderTimeout = setTimeout(rerender, 200);
        };
        rerender();
    };
    Pretty.prototype.runEnd = function () {
        var _this = this;
        var charm = this._charm;
        clearTimeout(this._renderTimeout);
        charm.erase('screen').position(0, 0);
        var ERROR_LOG_WEIGHT = { '!': 4, '×': 3, '~': 2, '⚠': 1, '✓': 0 };
        var logs = this._log.sort(function (a, b) {
            a = ERROR_LOG_WEIGHT[a.charAt(0)] || 0;
            b = ERROR_LOG_WEIGHT[b.charAt(0)] || 0;
            return a - b;
        }).map(function (line) { return _this._getColor(line) + line; }).join('\n');
        charm.write(logs);
        charm.write('\n\n');
        this._render(true);
        if (this._total.coverage.files().length > 0) {
            charm.write('\n');
            (new TextReport({
                watermarks: this.watermarks
            })).writeReport(this._total.coverage, true);
        }
    };
    Pretty.prototype.coverage = function (data) {
        var reporter = this._reports[data.sessionId];
        reporter && reporter.coverage.add(data.coverage);
        this._total.coverage.add(data.coverage);
    };
    Pretty.prototype.suiteStart = function (suite) {
        if (!suite.hasParent) {
            var numTests = suite.numTests;
            this._total.numTotal += numTests;
            if (suite.sessionId) {
                this._getReporter(suite).numTotal += numTests;
            }
        }
    };
    Pretty.prototype.suiteEnd = function (suite) {
        if (suite.error) {
            this._record(suite.sessionId, FAIL);
            var message = '! ' + suite.id;
            this._log.push(message + '\n' + this.formatter.format(suite.error));
        }
    };
    Pretty.prototype.testEnd = function (test) {
        if (test.skipped) {
            this._record(test.sessionId, SKIP);
            this._log.push('~ ' + test.id + ': ' + (test.skipped || 'skipped'));
        }
        else if (test.error) {
            var message = '× ' + test.id;
            this._record(test.sessionId, FAIL);
            this._log.push(message + '\n' + this.formatter.format(test.error));
        }
        else {
            this._record(test.sessionId, PASS);
            this._log.push('✓ ' + test.id);
        }
    };
    Pretty.prototype.tunnelDownloadProgress = function (message) {
        var progress = message.progress;
        this.tunnelState = 'Downloading ' + (progress.received / progress.total * 100).toFixed(2) + '%';
    };
    Pretty.prototype.tunnelStatus = function (message) {
        this.tunnelState = message.status;
    };
    Pretty.prototype.error = function (error) {
        var message = '! ' + error.message;
        this._log.push(message + '\n' + this.formatter.format(error));
        clearTimeout(this._renderTimeout);
    };
    Pretty.prototype.deprecated = function (message) {
        var text = '⚠ ' + message.original + ' is deprecated.';
        if (message.replacement) {
            text += ' Use ' + message.replacement + ' instead.';
        }
        if (message.message) {
            text += ' ' + message.message;
        }
        this._log.push(text);
    };
    Pretty.prototype._getReporter = function (suite) {
        if (!this._reports[suite.sessionId]) {
            this._reports[suite.sessionId] = new Report(suite.remote && suite.remote.environmentType.toString());
        }
        return this._reports[suite.sessionId];
    };
    Pretty.prototype._newCharm = function () {
        var c = charm();
        c.pipe(process.stdout);
        return c;
    };
    Pretty.prototype._record = function (sessionId, result) {
        var reporter = this._reports[sessionId];
        reporter && reporter.record(result);
        this._total.record(result);
    };
    Pretty.prototype._drawProgressBar = function (report, width) {
        var _this = this;
        var spinnerCharacter = SPINNER_STATES[this._spinnerOffset];
        var charm = this._charm;
        if (!report.numTotal) {
            charm.write('Pending');
            return;
        }
        var totalTextSize = String(report.numTotal).length;
        var remainingWidth = Math.max(width - 4 - (totalTextSize * 2), 1);
        var barSize = Math.min(remainingWidth, report.numTotal, this.maxProgressBarWidth);
        var results = report.getCompressedResults(barSize);
        charm.write('[' + results.map(function (value) { return _this._getColor(value); }).join(''));
        charm.display('reset').write(fit(spinnerCharacter, barSize - results.length) + '] ' +
            fit(report.finished, totalTextSize, true) + '/' + report.numTotal);
    };
    Pretty.prototype._drawSessionReport = function (report) {
        var charm = this._charm;
        var titleWidth = this.titleWidth;
        var leftOfBar = fit(this._abbreviateEnvironment(report.environment).slice(0, titleWidth - 2) + ': ', titleWidth);
        var rightOfBar = '' +
            (report.numFailed ? ', ' + report.numFailed + ' fail' : '') +
            (report.numSkipped ? ', ' + report.numSkipped + ' skip' : '');
        var barWidth = this.dimensions.width - rightOfBar.length - titleWidth;
        charm.write(leftOfBar);
        this._drawProgressBar(report, barWidth);
        charm.write(rightOfBar + '\n');
    };
    Pretty.prototype._abbreviateEnvironment = function (env) {
        var browser = BROWSERS[env.browserName.toLowerCase()] || env.browserName.slice(0, 4);
        var result = [browser];
        if (env.version) {
            var version = String(env.version);
            if (version.indexOf('.') > -1) {
                version = version.slice(0, version.indexOf('.'));
            }
            result.push(version);
        }
        if (env.platform) {
            result.push(env.platform.slice(0, 3));
        }
        return result.join(' ');
    };
    Pretty.prototype._render = function (omitLogs) {
        var _this = this;
        if (omitLogs === void 0) { omitLogs = false; }
        var charm = this._charm;
        var numReporters = Object.keys(this._reports).length;
        var logLength = this.dimensions.height - numReporters - 4 -
            (this.tunnelState ? 2 : 0) - (numReporters ? 1 : 0) - (this._header ? 1 : 0);
        this._spinnerOffset = (++this._spinnerOffset) % SPINNER_STATES.length;
        charm.display('reset');
        if (this._header) {
            charm.display('bright');
            charm.write(this._header + '\n');
            charm.display('reset');
        }
        this.tunnelState && charm.write('Tunnel: ' + this.tunnelState + '\n\n');
        this._drawTotalReporter(this._total);
        if (numReporters) {
            charm.write('\n');
            for (var key in this._reports) {
                this._drawSessionReport(this._reports[key]);
            }
        }
        if (!omitLogs && logLength > 0 && this._log.length) {
            var allowed_1 = { '×': true, '⚠': true, '!': true };
            var logs = this._log.filter(function (line) {
                return allowed_1[line.charAt(0)];
            }).slice(-logLength).map(function (line) {
                var color = _this._getColor(line);
                line = line.split('\n', 1)[0];
                return color + line.slice(0, _this.dimensions.width) + ANSI_COLOR.reset;
            }).join('\n');
            charm.write('\n');
            charm.write(logs);
        }
    };
    Pretty.prototype._drawTotalReporter = function (report) {
        var charm = this._charm;
        var title = 'Total: ';
        var totalTextSize = String(report.numTotal).length;
        charm.write(title);
        this._drawProgressBar(report, this.dimensions.width - title.length);
        charm.write(util_1.format('\nPassed: %s  Failed: %s  Skipped: %d\n', fit(report.numPassed, totalTextSize), fit(report.numFailed, totalTextSize), report.numSkipped));
    };
    Pretty.prototype._getColor = function (value) {
        if (typeof value === 'string') {
            value = value[0];
        }
        return this.colorReplacement[value] || ANSI_COLOR.reset;
    };
    return Pretty;
}(Reporter_1.default));
__decorate([
    eventHandler()
], Pretty.prototype, "runStart", null);
__decorate([
    eventHandler()
], Pretty.prototype, "runEnd", null);
__decorate([
    eventHandler()
], Pretty.prototype, "coverage", null);
__decorate([
    eventHandler()
], Pretty.prototype, "suiteStart", null);
__decorate([
    eventHandler()
], Pretty.prototype, "suiteEnd", null);
__decorate([
    eventHandler()
], Pretty.prototype, "testEnd", null);
__decorate([
    eventHandler()
], Pretty.prototype, "tunnelDownloadProgress", null);
__decorate([
    eventHandler()
], Pretty.prototype, "tunnelStatus", null);
__decorate([
    eventHandler()
], Pretty.prototype, "error", null);
__decorate([
    eventHandler()
], Pretty.prototype, "deprecated", null);
exports.default = Pretty;
var Report = (function () {
    function Report(environment, sessionId) {
        this.numTotal = 0;
        this.numPassed = 0;
        this.numFailed = 0;
        this.numSkipped = 0;
        this.results = [];
        this.coverage = new Collector();
        this.environment = environment;
        this.sessionId = sessionId;
    }
    Object.defineProperty(Report.prototype, "finished", {
        get: function () {
            return this.results.length;
        },
        enumerable: true,
        configurable: true
    });
    Report.prototype.record = function (result) {
        this.results.push(result);
        switch (result) {
            case PASS:
                ++this.numPassed;
                break;
            case SKIP:
                ++this.numSkipped;
                break;
            case FAIL:
                ++this.numFailed;
                break;
        }
    };
    Report.prototype.getCompressedResults = function (maxWidth) {
        var total = Math.max(this.numTotal, this.results.length);
        var width = Math.min(maxWidth, total);
        var resultList = [];
        for (var i = 0; i < this.results.length; ++i) {
            var pos = Math.floor(i / total * width);
            resultList[pos] = Math.max(resultList[pos] || PASS, this.results[i]);
        }
        return resultList;
    };
    return Report;
}());
exports.Report = Report;
var PAD = new Array(100).join(' ');
var SPINNER_STATES = ['/', '-', '\\', '|'];
var PASS = 0;
var SKIP = 1;
var FAIL = 2;
var BROWSERS = {
    chrome: 'Chr',
    firefox: 'Fx',
    opera: 'O',
    safari: 'Saf',
    'internet explorer': 'IE',
    phantomjs: 'Phan'
};
var ANSI_COLOR = {
    red: encode('[31m').toString('utf8'),
    green: encode('[32m').toString('utf8'),
    yellow: encode('[33m').toString('utf8'),
    reset: encode('[0m').toString('utf8')
};
function pad(width) {
    return PAD.slice(0, Math.max(width, 0));
}
function fit(text, width, padLeft) {
    if (padLeft === void 0) { padLeft = false; }
    text = String(text);
    if (text.length < width) {
        if (padLeft) {
            return pad(width - text.length) + text;
        }
        return text + pad(width - text.length);
    }
    return text.slice(0, width);
}
//# sourceMappingURL=Pretty.js.map