"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.XyzDataSeries3D = void 0;
var Deleter_1 = require("../../../Core/Deleter");
var Guard_1 = require("../../../Core/Guard");
var NumberRange_1 = require("../../../Core/NumberRange");
var appendDoubleVectorFromJsArray_1 = require("../../../utils/ccall/appendDoubleVectorFromJsArray");
var performance_1 = require("../../../utils/performance");
var vectorToArray_1 = require("../../../utils/vectorToArray");
var BaseDataSeries3D_1 = require("./BaseDataSeries3D");
/**
 * {@link XyzDataSeries3D} is a DataSeries for holding X, Y, Z data in SciChart's
 * {@link https://www.scichart.com/javascript-chart-features | JavaScript 3D Charts}
 * @remarks
 * The {@link XyzDataSeries3D} is primarily used with our {@link ScatterRenderableSeries3D | JavaScript Scatter & Bubble Chart},
 * which draws a variable-sized bubble or shape at each X,Y,Z value
 *
 * A DataSeries stores the data to render. This is independent from the {@link IRenderableSeries3D | RenderableSeries}
 * which defines how that data should be rendered.
 *
 * See derived types of {@link BaseDataSeries3D} to find out what data-series are available.
 * See derived types of {@link IRenderableSeries3D} to find out what 3D JavaScript Chart types are available.
 */
var XyzDataSeries3D = /** @class */ (function (_super) {
    __extends(XyzDataSeries3D, _super);
    /**
     * Creates an instance of {@link XyzDataSeries3D}
     * @param webAssemblyContext the {@link TSciChart3D | SciChart WebAssembly Context} containing native methods
     * and access to our underlying WebGL2 rendering engine
     * @param options the {@link IXyzDataSeries3DOptions} which can be passed to configure the DataSeries at construct time
     */
    function XyzDataSeries3D(webAssemblyContext, options) {
        var _this = _super.call(this, webAssemblyContext, options) || this;
        _this.type = BaseDataSeries3D_1.EDataSeriesType3D.Xyz3D;
        _this.xValues = new webAssemblyContext.SCRTDoubleVector();
        _this.yValues = new webAssemblyContext.SCRTDoubleVector();
        _this.zValues = new webAssemblyContext.SCRTDoubleVector();
        _this.metadata = [];
        if ((options === null || options === void 0 ? void 0 : options.xValues) && (options === null || options === void 0 ? void 0 : options.yValues) && (options === null || options === void 0 ? void 0 : options.zValues)) {
            _this.appendRange(options.xValues, options.yValues, options.zValues, options === null || options === void 0 ? void 0 : options.metadata);
        }
        return _this;
    }
    /**
     * Gets a native / WebAssembly vector of X-values in the DataSeries
     */
    XyzDataSeries3D.prototype.getNativeXValues = function () {
        return this.xValues;
    };
    /**
     * Gets a native / WebAssembly vector of Y-values in the DataSeries
     */
    XyzDataSeries3D.prototype.getNativeYValues = function () {
        return this.yValues;
    };
    /**
     * Gets a native / WebAssembly vector of Z-values in the DataSeries
     */
    XyzDataSeries3D.prototype.getNativeZValues = function () {
        return this.zValues;
    };
    /**
     * Gets a js array of {@link IPointMetadata3D | Metadata values} in the DataSeries
     */
    XyzDataSeries3D.prototype.getMetadataValues = function () {
        return this.metadata;
    };
    Object.defineProperty(XyzDataSeries3D.prototype, "xRange", {
        /**
         * @inheritDoc
         */
        get: function () {
            // Todo, an optimisation here is to know if containsNaN or not. When false, this will use SIMD calculations
            var nativeRange = this.webAssemblyContext.NumberUtil.MinMax(this.xValues, true);
            var tsRange = new NumberRange_1.NumberRange(nativeRange.minD, nativeRange.maxD);
            nativeRange.delete();
            return tsRange;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(XyzDataSeries3D.prototype, "yRange", {
        /**
         * @inheritDoc
         */
        get: function () {
            // Todo, an optimisation here is to know if containsNaN or not. When false, this will use SIMD calculations
            var nativeRange = this.webAssemblyContext.NumberUtil.MinMax(this.yValues, true);
            var tsRange = new NumberRange_1.NumberRange(nativeRange.minD, nativeRange.maxD);
            nativeRange.delete();
            return tsRange;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(XyzDataSeries3D.prototype, "zRange", {
        /**
         * @inheritDoc
         */
        get: function () {
            // Todo, an optimisation here is to know if containsNaN or not. When false, this will use SIMD calculations
            var nativeRange = this.webAssemblyContext.NumberUtil.MinMax(this.zValues, true);
            var tsRange = new NumberRange_1.NumberRange(nativeRange.minD, nativeRange.maxD);
            nativeRange.delete();
            return tsRange;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Appends a single X, Y, Z point to the {@link XyzDataSeries3D}
     * @remarks
     * For best performance on drawing large datasets, use the {@link appendRange} method
     *
     * Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param x The X-value
     * @param y The Y-value
     * @param z The Z-value
     * @param metadata An optional {@link IPointMetadata3D} value
     */
    XyzDataSeries3D.prototype.append = function (x, y, z, metadata) {
        if (!this.getIsDeleted()) {
            this.xValues.push_back(x);
            this.yValues.push_back(y);
            this.zValues.push_back(z);
            this.metadata.push(metadata); // its ok to push undefined here as its not a sparse array
            this.notifyDataChanged();
        }
    };
    /**
     * Appends a range of X, Y, Z points to the {@link XyzDataSeries3D}
     * @remarks
     * This method is considerably higher performance than {@link append} which appends a single point
     *
     * Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param xValues The X-values
     * @param yValues The Y-values
     * @param zValues The Z-values
     * @param metadatas Optional {@link IPointMetadata3D} values
     */
    XyzDataSeries3D.prototype.appendRange = function (xValues, yValues, zValues, metadatas) {
        if (!this.getIsDeleted()) {
            Guard_1.Guard.arraysSameLength(xValues, "xValues", yValues, "yValues");
            Guard_1.Guard.arraysSameLength(yValues, "yValues", zValues, "zValues");
            // Handle metadata efficiently
            if (metadatas) {
                Guard_1.Guard.arraysSameLength(metadatas, "metadatas", xValues, "xValues");
                var currentLength = this.metadata.length;
                this.metadata.length = currentLength + xValues.length;
                for (var i = 0; i < xValues.length; i++) {
                    this.metadata[currentLength + i] = metadatas[i];
                }
            }
            else {
                // Expand metadata array by count with undefined values
                var currentLength = this.metadata.length;
                this.metadata.length = currentLength + xValues.length;
                // Array expansion with undefined values is automatic in JavaScript
            }
            // Use efficient appendDoubleVectorFromJsArray for vector operations
            (0, appendDoubleVectorFromJsArray_1.appendDoubleVectorFromJsArray)(this.webAssemblyContext, this.xValues, xValues);
            (0, appendDoubleVectorFromJsArray_1.appendDoubleVectorFromJsArray)(this.webAssemblyContext, this.yValues, yValues);
            (0, appendDoubleVectorFromJsArray_1.appendDoubleVectorFromJsArray)(this.webAssemblyContext, this.zValues, zValues);
            this.notifyDataChanged();
        }
    };
    /**
     * Updates a single X, Y, Z-value by index
     * @remarks Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param index the index to update
     * @param x The new X value
     * @param y The new Y value
     * @param z The new Z value
     */
    XyzDataSeries3D.prototype.update = function (index, x, y, z, metadata) {
        if (!this.getIsDeleted()) {
            this.xValues.set(index, x);
            this.yValues.set(index, y);
            this.zValues.set(index, z);
            this.metadata[index] = metadata;
            this.notifyDataChanged();
        }
    };
    /**
     * Inserts a single X,Y,Z value at the start index
     * @remarks
     * For best performance on drawing large datasets, use the {@link insertRange} method
     *
     * Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param startIndex the index to insert at
     * @param x the Xvalue
     * @param y the YValue
     * @param z the ZValue
     * @param metadata Optional metadata value
     */
    XyzDataSeries3D.prototype.insert = function (startIndex, x, y, z, metadata) {
        var _a;
        var startMark = performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DataUpdateStart, { contextId: this.dataSeriesName });
        if (!this.getIsDeleted()) {
            if (startIndex < 0 || startIndex > this.count()) {
                throw new Error("Start index is out of range");
            }
            this.xValues.insertAt(startIndex, x);
            this.yValues.insertAt(startIndex, y);
            this.zValues.insertAt(startIndex, z);
            this.metadata.splice(startIndex, 0, metadata);
            this.notifyDataChanged();
        }
        performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DataUpdateEnd, {
            relatedId: (_a = startMark === null || startMark === void 0 ? void 0 : startMark.detail) === null || _a === void 0 ? void 0 : _a.relatedId,
            contextId: this.dataSeriesName
        });
    };
    /**
     * Inserts a range of X,Y,Z values at the startIndex
     * @remarks
     * Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param startIndex the index to insert at
     * @param xValues the XValues
     * @param yValues the YValues
     * @param zValues the ZValues
     * @param metadatas Optional metadata values to insert
     */
    XyzDataSeries3D.prototype.insertRange = function (startIndex, xValues, yValues, zValues, metadatas) {
        var _a;
        var startMark = performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DataUpdateStart, { contextId: this.dataSeriesName });
        if (!this.getIsDeleted()) {
            Guard_1.Guard.arraysSameLength(xValues, "xValues", yValues, "yValues");
            Guard_1.Guard.arraysSameLength(zValues, "zValues", yValues, "yValues");
            if (startIndex < 0 || startIndex > this.count()) {
                throw new Error("Start index is out of range");
            }
            // Use efficient insertDoubleVectorFromJsArray for vector operations
            (0, appendDoubleVectorFromJsArray_1.insertDoubleVectorFromJsArray)(this.webAssemblyContext, xValues, this.xValues, startIndex);
            (0, appendDoubleVectorFromJsArray_1.insertDoubleVectorFromJsArray)(this.webAssemblyContext, yValues, this.yValues, startIndex);
            (0, appendDoubleVectorFromJsArray_1.insertDoubleVectorFromJsArray)(this.webAssemblyContext, zValues, this.zValues, startIndex);
            // Handle metadata insertion
            if (metadatas) {
                var previousValues = this.metadata.slice(0, startIndex);
                var nextValues = this.metadata.slice(startIndex);
                this.metadata = previousValues.concat(metadatas, nextValues);
            }
            else {
                var undefinedMetadata = Array(xValues.length).fill(undefined);
                var previousValues = this.metadata.slice(0, startIndex);
                var nextValues = this.metadata.slice(startIndex);
                this.metadata = previousValues.concat(undefinedMetadata, nextValues);
            }
            this.notifyDataChanged();
        }
        performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DataUpdateEnd, {
            relatedId: (_a = startMark === null || startMark === void 0 ? void 0 : startMark.detail) === null || _a === void 0 ? void 0 : _a.relatedId,
            contextId: this.dataSeriesName
        });
    };
    /**
     * Removes a single X,Y,Z value at the specified index
     * @remarks Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param index the index to remove at
     */
    XyzDataSeries3D.prototype.removeAt = function (index) {
        if (!this.getIsDeleted()) {
            if (index < 0 || index >= this.count()) {
                throw new Error("index is out of range");
            }
            this.xValues.removeAt(index);
            this.yValues.removeAt(index);
            this.zValues.removeAt(index);
            this.metadata.splice(index, 1);
            this.notifyDataChanged();
        }
    };
    /**
     * Removes a range of X,Y,Z values at the specified index
     * @remarks Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param startIndex the start index to remove at
     * @param count the number of points to remove
     */
    XyzDataSeries3D.prototype.removeRange = function (startIndex, count) {
        if (!this.getIsDeleted()) {
            if (startIndex < 0 || startIndex + count > this.count()) {
                throw new Error("index is out of range");
            }
            this.xValues.removeRange(startIndex, count);
            this.yValues.removeRange(startIndex, count);
            this.zValues.removeRange(startIndex, count);
            this.metadata.splice(startIndex, count);
            this.notifyDataChanged();
        }
    };
    /**
     * Clears the entire DataSeries.
     * @remarks
     * Note this does not free memory, WebAssembly/Native memory is released by calling {@link delete}, after which the
     * DataSeries is no longer usable.
     *
     * Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     */
    XyzDataSeries3D.prototype.clear = function () {
        if (!this.getIsDeleted()) {
            this.xValues.clear();
            this.yValues.clear();
            this.zValues.clear();
            this.metadata = [];
            this.notifyDataChanged();
        }
    };
    /**
     * Sets metadata for a single point at the specified index without changing X, Y, Z values
     * @remarks Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param index The index of the point to update
     * @param metadata The new metadata value
     */
    XyzDataSeries3D.prototype.setMetadataAt = function (index, metadata) {
        if (!this.getIsDeleted()) {
            if (index < 0 || index >= this.count()) {
                throw new Error("index is out of range");
            }
            this.metadata[index] = metadata;
            this.notifyDataChanged();
        }
    };
    /**
     * Sets metadata for all points without changing X, Y, Z values
     * @remarks Any changes of the DataSeries will trigger a redraw on the parent {@link SciChart3DSurface}
     * @param metadatas The array of new metadata values. Must have the same length as the current data series
     */
    XyzDataSeries3D.prototype.setMetadata = function (metadatas) {
        if (!this.getIsDeleted()) {
            if (metadatas && metadatas.length !== this.count()) {
                throw new Error("metadata array length must match the number of data points");
            }
            this.metadata = metadatas ? __spreadArray([], metadatas, true) : [];
            this.notifyDataChanged();
        }
    };
    /**
     * @inheritDoc
     */
    XyzDataSeries3D.prototype.delete = function () {
        this.xValues = (0, Deleter_1.deleteSafe)(this.xValues);
        this.yValues = (0, Deleter_1.deleteSafe)(this.yValues);
        this.zValues = (0, Deleter_1.deleteSafe)(this.zValues);
        this.metadata = [];
        _super.prototype.delete.call(this);
    };
    /**
     * Gets the count of data-points in the DataSeries
     */
    XyzDataSeries3D.prototype.count = function () {
        if (this.xValues) {
            return this.xValues.size();
        }
        return 0;
    };
    Object.defineProperty(XyzDataSeries3D.prototype, "capacity", {
        /**
         * Gets or sets the capacity of data-points in the DataSeries
         */
        get: function () {
            return this.xValues.capacity();
        },
        /**
         * Gets or sets the capacity of data-points in the DataSeries
         */
        set: function (value) {
            if (value > this.capacity) {
                this.reserve(value);
            }
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Reserves memory for the specified number of data-points
     * @param size The number of data-points to reserve memory for
     */
    XyzDataSeries3D.prototype.reserve = function (size) {
        Guard_1.Guard.argumentIsRealInteger(size, "capacity");
        this.xValues.reserve(size);
        this.yValues.reserve(size);
        this.zValues.reserve(size);
    };
    XyzDataSeries3D.prototype.getOptions = function (excludeData) {
        var baseOptions = _super.prototype.getOptions.call(this, excludeData);
        if (excludeData) {
            return baseOptions;
        }
        var xValues = (0, vectorToArray_1.vectorToArray)(this.xValues, this.webAssemblyContext);
        var yValues = (0, vectorToArray_1.vectorToArray)(this.yValues, this.webAssemblyContext);
        var zValues = (0, vectorToArray_1.vectorToArray)(this.zValues, this.webAssemblyContext);
        var options = {
            xValues: xValues,
            yValues: yValues,
            zValues: zValues,
            metadata: this.metadata
        };
        return Object.assign(baseOptions, options);
    };
    return XyzDataSeries3D;
}(BaseDataSeries3D_1.BaseDataSeries3D));
exports.XyzDataSeries3D = XyzDataSeries3D;
