"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [0, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
var chai_1 = require("chai");
var data_forge_1 = require("data-forge");
var data_forge_2 = require("data-forge");
var render_chart_1 = require("./render-chart");
var Sugar = require("sugar");
var opn = require('opn');
var path = require("path");
var fs = require("fs-extra");
var find_package_dir_1 = require("./find-package-dir");
var jetpack = require('fs-jetpack');
/**
 * Defines the type of chart to output.
 */
var ChartType;
(function (ChartType) {
    ChartType["Line"] = "line";
    ChartType["Bar"] = "bar";
    ChartType["Scatter"] = "scatter";
})(ChartType = exports.ChartType || (exports.ChartType = {}));
/**
 * Defines the type of an axis.
 */
var AxisType;
(function (AxisType) {
    AxisType["Indexed"] = "indexed";
    AxisType["Timeseries"] = "timeseries";
    AxisType["Category"] = "category";
})(AxisType = exports.AxisType || (exports.AxisType = {}));
/**
 * Defines the position of a horizontal label.
 */
var HorizontalLabelPosition;
(function (HorizontalLabelPosition) {
    HorizontalLabelPosition["InnerRight"] = "inner-right";
    HorizontalLabelPosition["InnerCenter"] = "inner-center";
    HorizontalLabelPosition["InnerLeft"] = "inner-left";
    HorizontalLabelPosition["OuterRight"] = "outer-right";
    HorizontalLabelPosition["OuterCenter"] = "outer-center";
    HorizontalLabelPosition["OuterLeft"] = "outer-left";
})(HorizontalLabelPosition = exports.HorizontalLabelPosition || (exports.HorizontalLabelPosition = {}));
/**
 * Defines the position of a vertical label.
 */
var VerticalLabelPosition;
(function (VerticalLabelPosition) {
    VerticalLabelPosition["InnerTop"] = "inner-top";
    VerticalLabelPosition["InnerMiddle"] = "inner-middle";
    VerticalLabelPosition["InnerBottom"] = "inner-bottom";
    VerticalLabelPosition["OuterTop"] = "outer-top";
    VerticalLabelPosition["OuterMiddle"] = "outer-middle";
    VerticalLabelPosition["OuterBottom"] = "outer-bottom";
})(VerticalLabelPosition = exports.VerticalLabelPosition || (exports.VerticalLabelPosition = {}));
//
// Reusable chart renderer. 
// For improved performance.
//
var globalChartRenderer = null;
var defaultPlotDef = {
    chartType: ChartType.Line,
    width: 300,
    height: 300,
};
/**
 * Fluent API for configuring the plot.
 */
var PlotAPI = /** @class */ (function () {
    function PlotAPI(data, plotDef, axisMap) {
        chai_1.assert.isArray(data, "Expected 'data' parameter to PlotAPI constructor to be an array.");
        this.data = data;
        this.plotDef = Object.assign({}, defaultPlotDef, plotDef); // Clone the def and plot map so they can be updated by the fluent API.
        this.axisMap = Object.assign({}, axisMap);
        this.curAxisName = "x";
    }
    /**
     * Set the type of the chart to be plotted.
     *
     * @param chartType Specifies the chart type.
     */
    PlotAPI.prototype.chartType = function (chartType) {
        this.plotDef.chartType = chartType;
        return this;
    };
    /**
     * Set the width of the chart.
     */
    PlotAPI.prototype.width = function (width) {
        this.plotDef.width = width;
        return this;
    };
    /**
     * Set the height of the chart.
     */
    PlotAPI.prototype.height = function (height) {
        this.plotDef.height = height;
        return this;
    };
    /**
     * Configure the x axis.
     */
    PlotAPI.prototype.x = function () {
        this.curAxisName = "x";
        return this;
    };
    /**
     * Configure the y axis.
     */
    PlotAPI.prototype.y = function () {
        this.curAxisName = "y";
        return this;
    };
    /**
     * Configure the y axis.
     */
    PlotAPI.prototype.y2 = function () {
        this.curAxisName = "y2";
        return this;
    };
    /**
     * Set the label for the axis.
     */
    PlotAPI.prototype.label = function (label) {
        var plotDef = this.plotDef;
        if (!plotDef[this.curAxisName]) {
            plotDef[this.curAxisName] = {};
        }
        var axisConfig = plotDef[this.curAxisName];
        if (!axisConfig.label) {
            axisConfig.label = {};
        }
        else if (typeof (axisConfig.label) === "string") {
            axisConfig.label = {};
        }
        axisConfig.label.text = label;
        return this;
    };
    /**
     * Set the position for the label.
     */
    PlotAPI.prototype.labelPosition = function (position) {
        var plotDef = this.plotDef;
        if (!plotDef[this.curAxisName]) {
            plotDef[this.curAxisName] = {};
        }
        var axisConfig = plotDef[this.curAxisName];
        if (!axisConfig.label) {
            axisConfig.label = {};
        }
        else if (typeof (axisConfig.label) === "string") {
            axisConfig.label = {
                text: axisConfig.label,
            };
        }
        axisConfig.label.position = position;
        return this;
    };
    /**
     * Render the plot to an image file.
     */
    PlotAPI.prototype.renderImage = function (imageFilePath, renderOptions) {
        return __awaiter(this, void 0, void 0, function () {
            var chartRenderer;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!globalChartRenderer) return [3 /*break*/, 2];
                        // Reused global chart renderer.
                        return [4 /*yield*/, globalChartRenderer.renderImage(this.serialize(), imageFilePath)];
                    case 1:
                        // Reused global chart renderer.
                        _a.sent();
                        return [3 /*break*/, 6];
                    case 2:
                        chartRenderer = new render_chart_1.ChartRenderer();
                        return [4 /*yield*/, chartRenderer.start(false)];
                    case 3:
                        _a.sent();
                        return [4 /*yield*/, chartRenderer.renderImage(this.serialize(), imageFilePath)];
                    case 4:
                        _a.sent();
                        return [4 /*yield*/, chartRenderer.end()];
                    case 5:
                        _a.sent();
                        _a.label = 6;
                    case 6:
                        if (renderOptions && renderOptions.openImage) {
                            opn(imageFilePath);
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Export an interactive web visualization of the chart.
     */
    PlotAPI.prototype.exportWeb = function (outputFolderPath, exportOptions) {
        return __awaiter(this, void 0, void 0, function () {
            var packageFolderPath, jsonChartDef, indexJsPath;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!(exportOptions && exportOptions.overwrite)) return [3 /*break*/, 2];
                        return [4 /*yield*/, fs.remove(outputFolderPath)];
                    case 1:
                        _a.sent();
                        _a.label = 2;
                    case 2: return [4 /*yield*/, find_package_dir_1.findPackageDir(__dirname)];
                    case 3:
                        packageFolderPath = _a.sent();
                        return [4 /*yield*/, jetpack.copyAsync(path.join(packageFolderPath, "templates", "web"), outputFolderPath)];
                    case 4:
                        _a.sent();
                        return [4 /*yield*/, jetpack.copyAsync(path.join(packageFolderPath, "templates", "image", "format-chart-def.js"), path.join(outputFolderPath, "format-chart-def.js"))];
                    case 5:
                        _a.sent();
                        jsonChartDef = JSON.stringify(this.serialize(), null, 4);
                        indexJsPath = path.join(outputFolderPath, "index.js");
                        return [4 /*yield*/, jetpack.appendAsync(indexJsPath, "var chartDef =\r\n")];
                    case 6:
                        _a.sent();
                        return [4 /*yield*/, jetpack.appendAsync(indexJsPath, jsonChartDef)];
                    case 7:
                        _a.sent();
                        if (exportOptions && exportOptions.openBrowser) {
                            opn("file://" + path.join(outputFolderPath, "index.html"));
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Export a Node.js project to host a web visualization of the char.
     */
    PlotAPI.prototype.exportNodejs = function (outputFolderPath, exportOptions) {
        return __awaiter(this, void 0, void 0, function () {
            var packageFolderPath, jsonChartDef;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!(exportOptions && exportOptions.overwrite)) return [3 /*break*/, 2];
                        return [4 /*yield*/, fs.remove(outputFolderPath)];
                    case 1:
                        _a.sent();
                        _a.label = 2;
                    case 2: return [4 /*yield*/, find_package_dir_1.findPackageDir(__dirname)];
                    case 3:
                        packageFolderPath = _a.sent();
                        return [4 /*yield*/, jetpack.copyAsync(path.join(packageFolderPath, "templates", "nodejs"), outputFolderPath)];
                    case 4:
                        _a.sent();
                        return [4 /*yield*/, jetpack.copyAsync(path.join(packageFolderPath, "templates", "image", "format-chart-def.js"), path.join(outputFolderPath, "public", "format-chart-def.js"))];
                    case 5:
                        _a.sent();
                        jsonChartDef = JSON.stringify(this.serialize(), null, 4);
                        return [4 /*yield*/, jetpack.writeAsync(path.join(outputFolderPath, "chart-def.json"), jsonChartDef)];
                    case 6:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Serialize the plot definition so that it can be converted to JSON.
     * The JSON definition of the chart can be used to instantiate the chart in a browser.
     */
    PlotAPI.prototype.serialize = function () {
        return {
            data: this.data,
            plotDef: this.plotDef,
            axisMap: this.axisMap,
        };
    };
    return PlotAPI;
}());
function startPlot() {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    globalChartRenderer = new render_chart_1.ChartRenderer();
                    return [4 /*yield*/, globalChartRenderer.start(false)];
                case 1:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
function endPlot() {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, globalChartRenderer.end()];
                case 1:
                    _a.sent();
                    globalChartRenderer = null;
                    return [2 /*return*/];
            }
        });
    });
}
function plotSeries(plotDef) {
    if (!plotDef) {
        plotDef = defaultPlotDef;
    }
    var axisMap = {
        "x": "__index__",
        "y": [
            "__value__",
        ],
    };
    var amt = this.count();
    var dataWithIndex = this.inflate(function (value) { return ({ __value__: value }); })
        .withSeries("__index__", this.getIndex().head(amt))
        .toArray();
    return new PlotAPI(dataWithIndex, plotDef, axisMap);
}
data_forge_1.Series.prototype.startPlot = startPlot;
data_forge_1.Series.prototype.endPlot = endPlot;
data_forge_1.Series.prototype.plot = plotSeries;
function plotDataFrame(plotDef, axisMap) {
    if (!plotDef) {
        plotDef = defaultPlotDef;
    }
    if (!axisMap) {
        axisMap = {
            "x": "__index__",
            "y": this.getColumnNames(),
        };
    }
    else {
        axisMap = Object.assign({}, axisMap);
        if (!axisMap.x) {
            axisMap.x = "__index__";
        }
        if (!axisMap.y) {
            if (!axisMap.y2) {
                // All columns on the y axis.
                axisMap.y = this.getColumnNames();
            }
            else {
                // All columns on y axis, expect those explicitly on the y2 axis.
                axisMap.y = this.getColumnNames()
                    .filter(function (columnName) {
                    if (Sugar.Object.isArray(axisMap.y2)) {
                        if (axisMap.y2.indexOf(columnName) >= 0) {
                            {
                                return false; // This column is moved to y2 axis.
                            }
                        }
                    }
                    else {
                        if (columnName === axisMap.y2) {
                            return false; // This column is moved to y2 axis.
                        }
                    }
                    return true; // This column can stay on y axis.
                });
            }
        }
    }
    var includeIndex = axisMap.x === "__index__" ||
        axisMap.y === "__index__" ||
        axisMap.y2 === "__index__" ||
        (Sugar.Object.isArray(axisMap.y) && axisMap.y.filter(function (y) { return y === "__index__"; }).length > 0) ||
        axisMap.y2 && (Sugar.Object.isArray(axisMap.y2) && axisMap.y2.filter(function (y) { return y === "__index__"; }).length > 0);
    var df = this;
    if (includeIndex) {
        var amt = this.count();
        df = df.withSeries("__index__", df.getIndex().head(amt));
    }
    var data = df.toArray();
    return new PlotAPI(data, plotDef, axisMap);
}
data_forge_2.DataFrame.prototype.startPlot = startPlot;
data_forge_2.DataFrame.prototype.endPlot = endPlot;
data_forge_2.DataFrame.prototype.plot = plotDataFrame;
//# sourceMappingURL=index.js.map