"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MetricsLocationTracker = void 0;
const validation = require("../../json/validation");
const optional_1 = require("../../types/optional");
const metricsUtil = require("./util");
/**
 * A type describing metrics location tracker.
 *
 * The tracker manages stack of metrics location items.
 */
class MetricsLocationTracker {
    // endregion
    // region Initialization
    /**
     * Create new metrics location tracker with all required attributes.
     * @param rootPosition - Current root position of the tracker.
     * @param locations - Array of metrics location to track.
     */
    constructor(rootPosition = 0, locations = []) {
        this.rootPosition = rootPosition;
        this.locationStack = locations.map((location) => new MetricsLocationStackItem(location));
    }
    // endregion
    // region Location Stack Management
    /**
     * Check whether location stack is empty or not.
     */
    get isEmpty() {
        return this.locationStack.length === 0;
    }
    /**
     * Push new location to location tracker's stack.
     * @param location - Location to push to stack.
     */
    pushLocation(location) {
        this.locationStack.push(new MetricsLocationStackItem(location));
    }
    /**
     * Pop location from location tracker's stack.
     */
    popLocation() {
        var _a;
        if (this.locationStack.length === 0) {
            validation.unexpectedType("ignoredValue", "non-empty location stack", "empty location stack");
            return null;
        }
        return (_a = this.locationStack.pop()) === null || _a === void 0 ? void 0 : _a.location;
    }
    /**
     * Returns tracker's current position.
     */
    get currentPosition() {
        const stackItem = this.lastStackItem;
        if ((0, optional_1.isSome)(stackItem)) {
            return stackItem.position;
        }
        else {
            return this.rootPosition;
        }
    }
    /**
     * Set current position of tracker.
     * This is necessary when large today modules are broken apart into multipart shelves.
     * We need to preserve the position of content within server-response, not our logical shelves.
     * @param position - Position to set to.
     */
    setCurrentPosition(position) {
        const stackItem = this.lastStackItem;
        if ((0, optional_1.isSome)(stackItem)) {
            stackItem.position = position;
        }
        else {
            this.rootPosition = position;
        }
    }
    /**
     * Advance tracker's position.
     */
    nextPosition() {
        const stackItem = this.lastStackItem;
        if ((0, optional_1.isSome)(stackItem)) {
            stackItem.position += 1;
        }
        else {
            this.rootPosition += 1;
        }
    }
    /**
     * Convert location tracker's stack items to array of metric location objects.
     */
    get stackItemsToLocations() {
        return this.locationStack.map((stackItem) => stackItem.location);
    }
    /**
     * Returns last stack item in location stack or `null` if stack is empty.
     */
    get lastStackItem() {
        const length = this.locationStack.length;
        if (length === 0) {
            return null;
        }
        return this.locationStack[length - 1];
    }
    // endregion
    // region Adding Location
    /**
     * Create new basic location and add it to existing locations of the location tracker
     * and return resulting array of locations.
     * @param options - Base metrics options which include location tracker to get current locations from.
     * @param title - New location title.
     */
    static locationsByAddingBasicLocation(options, title) {
        const locations = options.locationTracker.stackItemsToLocations;
        locations.push(MetricsLocationTracker.buildBasicLocation(options, title));
        return locations;
    }
    /**
     * Create new content location and add it to existing locations of the location tracker
     * and return resulting array of locations.
     * @param options - Content metrics options which include location tracker to get current locations from.
     * @param title - New location title.
     */
    static locationsByAddingContentLocation(options, title) {
        const locations = options.locationTracker.stackItemsToLocations;
        locations.push(MetricsLocationTracker.buildContentLocation(options, title));
        return locations;
    }
    // endregion
    // region Metrics Options
    /**
     * Create new basic location from base metrics options
     * and push it to the stack of location tracker included into options.
     * @param options - Base metrics options which include location tracker to push new location to.
     * @param title - Location title.
     */
    static pushBasicLocation(options, title) {
        options.locationTracker.pushLocation(MetricsLocationTracker.buildBasicLocation(options, title));
    }
    /**
     * Create new content location from content metrics options
     * and push it to the stack of location tracker included into options.
     * @param options - Content metrics options which include location tracker to push new location to.
     * @param title - Location title.
     */
    static pushContentLocation(options, title) {
        options.locationTracker.pushLocation(MetricsLocationTracker.buildContentLocation(options, title));
    }
    /**
     * Pop last location from location tracker contained in metrics options.
     * @param options - Metrics options containing the location tracker.
     */
    static popLocation(options) {
        return options.locationTracker.popLocation();
    }
    // endregion
    // region Location Builders
    static buildBasicLocation(options, title) {
        let name = title;
        if ((0, optional_1.isSome)(options.anonymizationOptions)) {
            name = options.anonymizationOptions.anonymizationString;
        }
        const location = {
            locationPosition: options.locationTracker.currentPosition,
            locationType: metricsUtil.targetTypeForMetricsOptions(options),
            name: name,
        };
        if ((0, optional_1.isSome)(options.recoMetricsData)) {
            Object.assign(location, options.recoMetricsData);
        }
        return location;
    }
    static buildContentLocation(options, title) {
        const base = MetricsLocationTracker.buildBasicLocation(options, title);
        // Use the location tracker if there is no id override.
        if ((0, optional_1.isNothing)(options.id)) {
            base.idType = "sequential" /* MetricsIDType.sequential */;
            base.id = options.locationTracker.currentPosition.toString();
        }
        else {
            // If there is a id specified, use that.
            base.idType = metricsUtil.idTypeForMetricsOptions(options);
            let id = options.id;
            if ((0, optional_1.isSome)(options.anonymizationOptions)) {
                id = options.anonymizationOptions.anonymizationString;
            }
            base.id = id;
        }
        if ((0, optional_1.isSome)(options.fcKind)) {
            base.fcKind = options.fcKind;
        }
        if ((0, optional_1.isSome)(options.displayStyle)) {
            base.displayStyle = options.displayStyle;
        }
        return base;
    }
}
exports.MetricsLocationTracker = MetricsLocationTracker;
/**
 * A type describing a metrics location item in location tracking stack.
 */
class MetricsLocationStackItem {
    /**
     * Create new metrics location stack item with all required attributes.
     * @param location - The metrics location associated with this item.
     * @param position - The position of the item.
     */
    constructor(location, position = 0) {
        this.location = location;
        this.position = position;
    }
}
//# sourceMappingURL=location.js.map