import * as tslib_1 from "tslib";
import { format } from 'd3-format';
import { equalArrays } from '../internal';
import { Category, dialogAddons, SortByDefault, toolbar } from './annotations';
import Column from './Column';
import { ECompareValueType, DEFAULT_COLOR } from './interfaces';
import { EAdvancedSortMethod } from './INumberColumn';
import { restoreMapping, ScaleMappingFunction } from './MappingFunction';
import { isMissingValue, isUnknown, missingGroup } from './missing';
import ValueColumn from './ValueColumn';
import { noNumberFilter, isDummyNumberFilter, restoreNumberFilter, toCompareGroupValue, isEqualNumberFilter, isNumberIncluded } from './internalNumber';
/**
 * a number column mapped from an original input scale to an output range
 */
var NumberColumn = /** @class */ (function (_super) {
    tslib_1.__extends(NumberColumn, _super);
    function NumberColumn(id, desc, factory) {
        var _this = _super.call(this, id, desc) || this;
        /**
         * currently active filter
         * @type {{min: number, max: number}}
         * @private
         */
        _this.currentFilter = noNumberFilter();
        _this.numberFormat = format('.2f');
        _this.currentGroupThresholds = [];
        _this.groupSortMethod = EAdvancedSortMethod.median;
        _this.mapping = restoreMapping(desc, factory);
        _this.original = _this.mapping.clone();
        _this.colorMapping = factory.colorMappingFunction(desc.colorMapping || desc.color);
        if (desc.numberFormat) {
            _this.numberFormat = format(desc.numberFormat);
        }
        _this.setDefaultGroupRenderer('boxplot');
        _this.setDefaultSummaryRenderer('histogram');
        return _this;
    }
    NumberColumn_1 = NumberColumn;
    NumberColumn.prototype.getNumberFormat = function () {
        return this.numberFormat;
    };
    NumberColumn.prototype.dump = function (toDescRef) {
        var r = _super.prototype.dump.call(this, toDescRef);
        r.map = this.mapping.toJSON();
        r.colorMapping = this.colorMapping.toJSON();
        r.filter = isDummyNumberFilter(this.currentFilter) ? null : this.currentFilter;
        r.groupSortMethod = this.groupSortMethod;
        if (this.currentGroupThresholds) {
            r.stratifyThreshholds = this.currentGroupThresholds;
        }
        return r;
    };
    NumberColumn.prototype.restore = function (dump, factory) {
        _super.prototype.restore.call(this, dump, factory);
        if (dump.map) {
            this.mapping = factory.mappingFunction(dump.map);
        }
        else if (dump.domain) {
            this.mapping = new ScaleMappingFunction(dump.domain, 'linear', dump.range || [0, 1]);
        }
        if (dump.colorMapping) {
            this.colorMapping = factory.colorMappingFunction(dump.colorMapping);
        }
        if (dump.groupSortMethod) {
            this.groupSortMethod = dump.groupSortMethod;
        }
        if (dump.filter) {
            this.currentFilter = restoreNumberFilter(dump.filter);
        }
        if (dump.stratifyThreshholds) {
            this.currentGroupThresholds = dump.stratifyThresholds;
        }
    };
    NumberColumn.prototype.createEventList = function () {
        return _super.prototype.createEventList.call(this).concat([NumberColumn_1.EVENT_MAPPING_CHANGED, NumberColumn_1.EVENT_COLOR_MAPPING_CHANGED, NumberColumn_1.EVENT_FILTER_CHANGED, NumberColumn_1.EVENT_SORTMETHOD_CHANGED, NumberColumn_1.EVENT_GROUPING_CHANGED]);
    };
    NumberColumn.prototype.on = function (type, listener) {
        return _super.prototype.on.call(this, type, listener);
    };
    NumberColumn.prototype.getLabel = function (row) {
        if (this.desc.numberFormat) {
            var raw = this.getRawValue(row);
            //if a dedicated format and a number use the formatter in any case
            if (isNaN(raw)) {
                return 'NaN';
            }
            if (!isFinite(raw)) {
                return raw.toString();
            }
            return this.numberFormat(raw);
        }
        var v = _super.prototype.getValue.call(this, row);
        //keep non number if it is not a number else convert using formatter
        if (typeof v === 'number') {
            return this.numberFormat(+v);
        }
        return String(v);
    };
    NumberColumn.prototype.getRange = function () {
        return this.mapping.getRange(this.numberFormat);
    };
    NumberColumn.prototype.getRawValue = function (row) {
        var v = _super.prototype.getValue.call(this, row);
        if (isMissingValue(v)) {
            return NaN;
        }
        return +v;
    };
    NumberColumn.prototype.getExportValue = function (row, format) {
        return format === 'json' ? this.getRawValue(row) : _super.prototype.getExportValue.call(this, row, format);
    };
    NumberColumn.prototype.getValue = function (row) {
        var v = this.getNumber(row);
        if (isNaN(v)) {
            return null;
        }
        return v;
    };
    NumberColumn.prototype.getNumber = function (row) {
        var v = this.getRawValue(row);
        if (isNaN(v)) {
            return NaN;
        }
        return this.mapping.apply(v);
    };
    NumberColumn.prototype.iterNumber = function (row) {
        return [this.getNumber(row)];
    };
    NumberColumn.prototype.iterRawNumber = function (row) {
        return [this.getRawNumber(row)];
    };
    NumberColumn.prototype.getRawNumber = function (row) {
        return this.getRawValue(row);
    };
    NumberColumn.prototype.toCompareValue = function (row, valueCache) {
        return valueCache != null ? valueCache : this.getNumber(row);
    };
    NumberColumn.prototype.toCompareValueType = function () {
        return ECompareValueType.FLOAT;
    };
    NumberColumn.prototype.toCompareGroupValue = function (rows, _group, valueCache) {
        return toCompareGroupValue(rows, this, this.groupSortMethod, valueCache);
    };
    NumberColumn.prototype.toCompareGroupValueType = function () {
        return ECompareValueType.FLOAT;
    };
    NumberColumn.prototype.getOriginalMapping = function () {
        return this.original.clone();
    };
    NumberColumn.prototype.getMapping = function () {
        return this.mapping.clone();
    };
    NumberColumn.prototype.setMapping = function (mapping) {
        if (this.mapping.eq(mapping)) {
            return;
        }
        this.fire([NumberColumn_1.EVENT_MAPPING_CHANGED, Column.EVENT_DIRTY_VALUES, Column.EVENT_DIRTY_CACHES, Column.EVENT_DIRTY_HEADER, Column.EVENT_DIRTY], this.mapping.clone(), this.mapping = mapping);
    };
    NumberColumn.prototype.getColor = function (row) {
        var v = this.getNumber(row);
        if (isNaN(v)) {
            return DEFAULT_COLOR;
        }
        return this.colorMapping.apply(v);
    };
    NumberColumn.prototype.getColorMapping = function () {
        return this.colorMapping.clone();
    };
    NumberColumn.prototype.setColorMapping = function (mapping) {
        if (this.colorMapping.eq(mapping)) {
            return;
        }
        this.fire([NumberColumn_1.EVENT_COLOR_MAPPING_CHANGED, Column.EVENT_DIRTY_VALUES, Column.EVENT_DIRTY_HEADER, Column.EVENT_DIRTY], this.colorMapping.clone(), this.colorMapping = mapping);
    };
    NumberColumn.prototype.isFiltered = function () {
        return !isDummyNumberFilter(this.currentFilter);
    };
    NumberColumn.prototype.getFilter = function () {
        return Object.assign({}, this.currentFilter);
    };
    NumberColumn.prototype.setFilter = function (value) {
        value = value || { min: -Infinity, max: +Infinity, filterMissing: false };
        if (isEqualNumberFilter(value, this.currentFilter)) {
            return;
        }
        var bak = this.getFilter();
        this.currentFilter.min = isUnknown(value.min) ? -Infinity : value.min;
        this.currentFilter.max = isUnknown(value.max) ? Infinity : value.max;
        this.currentFilter.filterMissing = value.filterMissing;
        this.fire([NumberColumn_1.EVENT_FILTER_CHANGED, Column.EVENT_DIRTY_VALUES, Column.EVENT_DIRTY], bak, this.getFilter());
    };
    /**
     * filter the current row if any filter is set
     * @param row
     * @returns {boolean}
     */
    NumberColumn.prototype.filter = function (row) {
        return isNumberIncluded(this.currentFilter, this.getRawNumber(row));
    };
    NumberColumn.prototype.clearFilter = function () {
        var was = this.isFiltered();
        this.setFilter(null);
        return was;
    };
    NumberColumn.prototype.getGroupThresholds = function () {
        return this.currentGroupThresholds.slice();
    };
    NumberColumn.prototype.setGroupThresholds = function (value) {
        if (equalArrays(this.currentGroupThresholds, value)) {
            return;
        }
        var bak = this.getGroupThresholds();
        this.currentGroupThresholds = value.slice();
        this.fire([NumberColumn_1.EVENT_GROUPING_CHANGED, Column.EVENT_DIRTY_VALUES, Column.EVENT_DIRTY], bak, value);
    };
    NumberColumn.prototype.group = function (row) {
        var value = this.getRawNumber(row);
        if (isNaN(value)) {
            return Object.assign({}, missingGroup);
        }
        var threshold = this.currentGroupThresholds;
        if (threshold.length === 0) {
            // default threshold
            var d = this.mapping.domain;
            threshold = [(d[1] - d[0]) / 2];
        }
        var treshholdIndex = threshold.findIndex(function (t) { return value <= t; });
        // group by thresholds / bins
        switch (treshholdIndex) {
            case -1:
                //bigger than the last threshold
                return {
                    name: this.label + " > " + this.numberFormat(threshold[threshold.length - 1]),
                    color: this.colorMapping.apply(1)
                };
            case 0:
                //smallest
                return {
                    name: this.label + " <= " + this.numberFormat(threshold[0]),
                    color: this.colorMapping.apply(0)
                };
            default:
                return {
                    name: this.numberFormat(threshold[treshholdIndex - 1]) + " <= " + this.label + " <= " + this.numberFormat(threshold[treshholdIndex]),
                    color: this.colorMapping.apply(this.mapping.apply((threshold[treshholdIndex - 1] + threshold[treshholdIndex]) / 2))
                };
        }
    };
    NumberColumn.prototype.getSortMethod = function () {
        return this.groupSortMethod;
    };
    NumberColumn.prototype.setSortMethod = function (sortMethod) {
        if (this.groupSortMethod === sortMethod) {
            return;
        }
        this.fire([NumberColumn_1.EVENT_SORTMETHOD_CHANGED], this.groupSortMethod, this.groupSortMethod = sortMethod);
        // sort by me if not already sorted by me
        if (!this.isGroupSortedByMe().asc) {
            this.toggleMyGroupSorting();
        }
    };
    var NumberColumn_1;
    NumberColumn.EVENT_MAPPING_CHANGED = 'mappingChanged';
    NumberColumn.EVENT_COLOR_MAPPING_CHANGED = 'colorMappingChanged';
    NumberColumn.EVENT_FILTER_CHANGED = 'filterChanged';
    NumberColumn.EVENT_SORTMETHOD_CHANGED = 'sortMethodChanged';
    NumberColumn.EVENT_GROUPING_CHANGED = 'groupingChanged';
    NumberColumn = NumberColumn_1 = tslib_1.__decorate([
        toolbar('groupBy', 'sortGroupBy', 'filterNumber', 'colorMapped', 'editMapping'),
        dialogAddons('sortGroup', 'sortNumber'),
        dialogAddons('group', 'groupNumber'),
        Category('number'),
        SortByDefault('descending')
    ], NumberColumn);
    return NumberColumn;
}(ValueColumn));
export default NumberColumn;
//# sourceMappingURL=NumberColumn.js.map