/**
 * Defines Pie Chart Series.
 */
import { __extends } from "tslib";
/**
 * ============================================================================
 * IMPORTS
 * ============================================================================
 * @hidden
 */
import { PercentSeries, PercentSeriesDataItem } from "./PercentSeries";
import { Slice } from "../../core/elements/Slice";
//import { Slice3D } from "../../core/elements/3D/Slice3D";
import { AxisLabelCircular } from "../axes/AxisLabelCircular";
import { PieTick } from "../elements/PieTick";
import { registry } from "../../core/Registry";
import * as $math from "../../core/utils/Math";
import * as $type from "../../core/utils/Type";
import { Percent, percent } from "../../core/utils/Percent";
/**
 * ============================================================================
 * DATA ITEM
 * ============================================================================
 * @hidden
 */
//@todo: sequenced?
/**
 * Defines a [[DataItem]] for [[PieSeries]].
 *
 * @see {@link DataItem}
 */
var PieSeriesDataItem = /** @class */ (function (_super) {
    __extends(PieSeriesDataItem, _super);
    /**
     * Constructor
     */
    function PieSeriesDataItem() {
        var _this = _super.call(this) || this;
        _this.className = "PieSeriesDataItem";
        _this.values.radiusValue = {};
        _this.applyTheme();
        return _this;
    }
    Object.defineProperty(PieSeriesDataItem.prototype, "radiusValue", {
        /**
         * @return Radius
         */
        get: function () {
            return this.values.radiusValue.value;
        },
        /**
         * Slice's radius, if other than default.
         *
         * @param value  Radius
         */
        set: function (value) {
            this.setValue("radiusValue", value);
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Hide the data item (and corresponding visual elements).
     *
     * @param duration  Duration (ms)
     * @param delay     Delay hiding (ms)
     * @param toValue   Target value for animation
     * @param fields    Fields to animate while hiding
     */
    PieSeriesDataItem.prototype.hide = function (duration, delay, toValue, fields) {
        return _super.prototype.hide.call(this, duration, delay, 0, ["value", "radiusValue"]);
    };
    /**
     * Show hidden data item (and corresponding visual elements).
     *
     * @param duration  Duration (ms)
     * @param delay     Delay hiding (ms)
     * @param fields    Fields to animate while hiding
     */
    PieSeriesDataItem.prototype.show = function (duration, delay, fields) {
        return _super.prototype.show.call(this, duration, delay, ["value", "radiusValue"]);
    };
    return PieSeriesDataItem;
}(PercentSeriesDataItem));
export { PieSeriesDataItem };
/**
 * ============================================================================
 * MAIN CLASS
 * ============================================================================
 * @hidden
 */
/**
 * Defines [[Series]] for a slice series on a Pie chart.
 *
 * @see {@link IPieSeriesEvents} for a list of available Events
 * @see {@link IPieSeriesAdapters} for a list of available Adapters
 * @todo Example
 * @important
 */
var PieSeries = /** @class */ (function (_super) {
    __extends(PieSeries, _super);
    /**
     * Constructor
     */
    function PieSeries() {
        var _this = _super.call(this) || this;
        _this.className = "PieSeries";
        _this.alignLabels = true;
        //this.startAngle = -90;
        //this.endAngle = 270;
        _this.layout = "none";
        _this.labels.template.radius = percent(5);
        _this.addDisposer(_this.labels.template.events.on("enabled", _this.invalidate, _this, false));
        _this.applyTheme();
        return _this;
    }
    /**
     * creates slice
     */
    PieSeries.prototype.createSlice = function () {
        return new Slice();
    };
    /**
     * creates tick
     */
    PieSeries.prototype.createTick = function () {
        return new PieTick();
    };
    /**
     * creates label
     */
    PieSeries.prototype.createLabel = function () {
        return new AxisLabelCircular();
    };
    /**
     * Sets defaults that instantiate some objects that rely on parent, so they
     * cannot be set in constructor.
     */
    PieSeries.prototype.applyInternalDefaults = function () {
        _super.prototype.applyInternalDefaults.call(this);
        if (!$type.hasValue(this.readerTitle)) {
            this.readerTitle = this.language.translate("Pie Slice Series");
        }
    };
    /**
     * Returns a new/empty DataItem of the type appropriate for this object.
     *
     * @see {@link DataItem}
     * @return Data Item
     */
    PieSeries.prototype.createDataItem = function () {
        return new PieSeriesDataItem();
    };
    /**
     * Inits slice.
     *
     * @param slice to init
     */
    PieSeries.prototype.initSlice = function (slice) {
        slice.isMeasured = false;
        slice.defaultState.properties.scale = 1;
        slice.observe("scale", this.handleSliceScale, this);
        slice.observe(["dx", "dy", "x", "y", "shiftRadius"], this.handleSliceMove, this);
        slice.tooltipText = "{category}: {value.percent.formatNumber('#.#')}% ({value.value})";
        var hoverState = slice.states.create("hover");
        hoverState.properties.scale = 1.05;
        var defaultState = slice.defaultState;
        defaultState.properties.shiftRadius = 0;
        slice.togglable = true;
        slice.events.on("toggled", function (event) {
            event.target.hideTooltip();
            // The following takes care of removing hover on subsequent click of
            // a slice
            if (event.target.interactions.lastHitPointer
                && event.target.interactions.lastHitPointer.touch
                && !event.target.isActive) {
                event.target.isHover = false;
            }
        });
        var activeState = slice.states.create("active");
        activeState.properties.shiftRadius = 0.10;
    };
    /**
     * (Re)validates the whole series, effectively causing it to redraw.
     *
     * @ignore Exclude from docs
     */
    PieSeries.prototype.validate = function () {
        this._leftItems = [];
        this._rightItems = [];
        this._currentStartAngle = this.startAngle;
        this._arcRect = $math.getArcRect(this.startAngle, this.endAngle);
        this._maxRadiusPercent = 0;
        for (var i = this.startIndex; i < this.endIndex; i++) {
            var dataItem = this.dataItems.getIndex(i);
            var radiusValuePercent = dataItem.values.radiusValue.percent;
            if (radiusValuePercent > this._maxRadiusPercent) {
                this._maxRadiusPercent = radiusValuePercent;
            }
        }
        _super.prototype.validate.call(this);
        if (this.alignLabels) {
            if (this.startAngle > this.endAngle) {
                this._rightItems.reverse();
            }
            else {
                this._leftItems.reverse();
            }
            this._rightItems.sort(function (a, b) {
                var aAngle = (a.slice.middleAngle + 360) % 360;
                var bAngle = (b.slice.middleAngle + 360) % 360;
                if (aAngle > 270) {
                    aAngle -= 360;
                }
                if (bAngle > 270) {
                    bAngle -= 360;
                }
                if (aAngle < bAngle) {
                    return -1;
                }
                else if (aAngle > bAngle) {
                    return 1;
                }
                else {
                    return 0;
                }
            });
            this._leftItems.sort(function (a, b) {
                var aAngle = (a.slice.middleAngle + 360) % 360;
                var bAngle = (b.slice.middleAngle + 360) % 360;
                if (aAngle < bAngle) {
                    return 1;
                }
                else if (aAngle > bAngle) {
                    return -1;
                }
                else {
                    return 0;
                }
            });
            this.arrangeLabels(this._rightItems);
            this.arrangeLabels2(this._rightItems);
            this.arrangeLabels(this._leftItems);
            this.arrangeLabels2(this._leftItems);
        }
    };
    /**
     * Validates data item's element, effectively redrawing it.
     *
     * @ignore Exclude from docs
     * @param dataItem  Data item
     */
    PieSeries.prototype.validateDataElement = function (dataItem) {
        if (this.pixelRadius > 0) {
            if (this.ignoreZeroValues && (dataItem.value == 0 || dataItem.value == null)) {
                dataItem.__disabled = true;
            }
            else {
                dataItem.__disabled = false;
            }
            // SLICE
            var slice = dataItem.slice;
            slice.radius = this.pixelRadius;
            if ($type.isNumber(dataItem.radiusValue)) {
                slice.radius = this.pixelInnerRadius + (this.pixelRadius - this.pixelInnerRadius) * dataItem.values.radiusValue.percent / this._maxRadiusPercent;
            }
            if (!(slice.innerRadius instanceof Percent)) {
                slice.innerRadius = this.pixelInnerRadius;
            }
            slice.startAngle = this._currentStartAngle;
            slice.arc = Math.abs(dataItem.values.value.percent) * (this.endAngle - this.startAngle) / 100;
            // LABEL
            if (!this.labels.template.disabled) {
                var label = dataItem.label;
                var tick = dataItem.tick;
                tick.slice = slice;
                tick.label = label;
                var normalizedMiddleAngle = (slice.middleAngle + 360) % 360; // force angle to be 0 - 360;
                var point = void 0;
                if (this.alignLabels) {
                    var labelRadius = label.pixelRadius(slice.radius);
                    var x = tick.length + labelRadius;
                    label.dx = 0;
                    label.dy = 0;
                    label.verticalCenter = "middle";
                    var arcRect = this._arcRect;
                    // right half
                    if (normalizedMiddleAngle > 270 || normalizedMiddleAngle <= 90) {
                        x += (arcRect.width + arcRect.x) * this.pixelRadius;
                        label.horizontalCenter = "left";
                        this._rightItems.push(dataItem);
                    }
                    // left half
                    else {
                        x -= arcRect.x * this.pixelRadius;
                        label.horizontalCenter = "right";
                        this._leftItems.push(dataItem);
                        x *= -1;
                    }
                    var distance = slice.radius + tick.length + labelRadius;
                    point = { x: x, y: slice.iy * distance };
                    label.moveTo(point);
                }
                else {
                    var depth = slice["depth"];
                    if (!$type.isNumber(depth)) {
                        depth = 0;
                    }
                    label.fixPosition(slice.middleAngle, slice.radius, slice.radiusY, 0, -depth);
                }
            }
            this._currentStartAngle += slice.arc;
            // do this at the end, otherwise bullets won't be positioned properly
            _super.prototype.validateDataElement.call(this, dataItem);
        }
    };
    Object.defineProperty(PieSeries.prototype, "radius", {
        /**
         * @return Radius
         */
        get: function () {
            return this.getPropertyValue("radius");
        },
        /**
         * Outer radius for the series' slices in pixels or [[Percent]].
         *
         * @param value  Radius
         */
        set: function (value) {
            if (this.setPercentProperty("radius", value, true, false, 10, false)) {
                this.invalidateDataItems();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PieSeries.prototype, "pixelRadius", {
        /**
         * @return Radius
         * @ignore
         */
        get: function () {
            return this._pixelRadius;
        },
        /**
         * @ignore
         */
        set: function (value) {
            if (this._pixelRadius != value) {
                this._pixelRadius = value;
                this.invalidateDataItems();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PieSeries.prototype, "pixelInnerRadius", {
        /**
         * @return Pixel inner radius
         * @ignore
         */
        get: function () {
            return this._pixelInnerRadius;
        },
        /**
         * @ignore
         */
        set: function (value) {
            if (this._pixelInnerRadius != value) {
                this._pixelInnerRadius = value;
                this.invalidateDataItems();
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PieSeries.prototype, "innerRadius", {
        /**
         * @ignore Exclude from docs
         * @return Radius
         */
        get: function () {
            return this.getPropertyValue("innerRadius");
        },
        /**
         * Inner radius for the series' slices in pixels.
         *
         * @ignore Exclude from docs
         * @todo Redo so that users can set it
         * @param value  Radius
         */
        set: function (value) {
            this.setPercentProperty("innerRadius", value, true, false, 10, false);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PieSeries.prototype, "startAngle", {
        /**
         * @return Angle
         */
        get: function () {
            var startAngle = this.getPropertyValue("startAngle");
            if ($type.isNumber(startAngle)) {
                return startAngle;
            }
            else {
                return this._startAngleInternal;
            }
        },
        /**
         * Start angle for the series' slices in degrees. (0-360)
         *
         * @param value  Angle
         */
        set: function (value) {
            this.setPropertyValue("startAngle", $math.normalizeAngle(value), true);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(PieSeries.prototype, "endAngle", {
        /**
         * @return Angle
         */
        get: function () {
            var endAngle = this.getPropertyValue("endAngle");
            if ($type.isNumber(endAngle)) {
                return endAngle;
            }
            else {
                return this._endAngleInternal;
            }
        },
        /**
         * End angle for the series' slices in degrees. (0-360)
         *
         * @param value  Angle
         */
        set: function (value) {
            this.setPropertyValue("endAngle", value, true);
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Positions series bullet.
     *
     * @ignore Exclude from docs
     * @param bullet  Bullet
     */
    PieSeries.prototype.positionBullet = function (bullet) {
        _super.prototype.positionBullet.call(this, bullet);
        var dataItem = bullet.dataItem;
        var slice = dataItem.slice;
        var locationX = bullet.locationX;
        if (!$type.isNumber(locationX)) {
            locationX = 0.5;
        }
        var locationY = bullet.locationY;
        if (!$type.isNumber(locationY)) {
            locationY = 1;
        }
        var angle = slice.startAngle + slice.arc * locationX;
        bullet.x = locationY * slice.radius * $math.cos(angle);
        bullet.y = locationY * slice.radiusY * $math.sin(angle);
    };
    /**
     * Repositions bullet and labels when slice moves.
     *
     * @ignore Exclude from docs
     * @param event  Event
     */
    PieSeries.prototype.handleSliceMove = function (event) {
        if (!this.alignLabels) {
            var slice = event.target;
            var dataItem = slice.dataItem;
            // moving textelement, as label dx and dy are already employed for aligning
            //@labeltodo
            if (dataItem) {
                var label = dataItem.label;
                if (label) {
                    label.dx = label.fdx + slice.dx + slice.pixelX;
                    label.dy = label.fdy + slice.dy + slice.pixelY;
                }
            }
        }
    };
    Object.defineProperty(PieSeries.prototype, "bbox", {
        /**
         * Returns bounding box (square) for this element.
         *
         * @ignore Exclude from docs
         */
        get: function () {
            if (this.definedBBox) {
                return this.definedBBox;
            }
            var chart = this.chart;
            if (chart) {
                return $math.getArcRect(chart.startAngle, chart.endAngle, this.pixelRadius);
            }
            return $math.getArcRect(this.startAngle, this.endAngle, this.pixelRadius);
        },
        enumerable: true,
        configurable: true
    });
    return PieSeries;
}(PercentSeries));
export { PieSeries };
/**
 * bboxter class in system, so that it can be instantiated using its name from
 * anywhere.
 *
 * @ignore
 */
registry.registeredClasses["PieSeries"] = PieSeries;
registry.registeredClasses["PieSeriesDataItem"] = PieSeriesDataItem;
//# sourceMappingURL=PieSeries.js.map