import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Directive, EventEmitter, Inject, InjectionToken, Input, Optional, Output, } from '@angular/core';
import { Subject } from 'rxjs';
/** Injection token to be used to override the default options for `r-sort`. */
export const R_SORT_DEFAULT_OPTIONS = new InjectionToken('R_SORT_DEFAULT_OPTIONS');
/** Container for RSortables to manage the sort state and provide default sort parameters. */
export class RSort {
    constructor(_defaultOptions) {
        this._defaultOptions = _defaultOptions;
        /** Collection of all registered sortables that this directive manages. */
        this.sortables = new Map();
        this._markInitialized = () => { };
        /** Used to notify any child components listening to state changes. */
        this._stateChanges = new Subject();
        /**
         * The direction to set when an RSortable is initially sorted.
         * May be overriden by the RSortable's sort start.
         */
        this.start = 'asc';
        this._direction = '';
        /** Event emitted when the user changes either the active sort or sort direction. */
        this.sortChange = new EventEmitter();
    }
    /** The sort direction of the currently active RSortable. */
    get direction() { return this._direction; }
    set direction(direction) {
        if (direction && direction !== 'asc' && direction !== 'desc') {
            this._direction = direction;
        }
    }
    /**
     * Whether to disable the user from clearing the sort by finishing the sort direction cycle.
     * May be overriden by the RSortable's disable clear input.
     */
    get disableClear() { return this._disableClear; }
    set disableClear(v) { this._disableClear = coerceBooleanProperty(v); }
    /**
     * Register function to be used by the contained RSortables. Adds the RSortable to the
     * collection of RSortables.
     */
    register(sortable) {
        this.sortables.set(sortable.id, sortable);
    }
    /**
     * Unregister function to be used by the contained RSortables. Removes the RSortable from the
     * collection of contained RSortables.
     */
    deregister(sortable) {
        this.sortables.delete(sortable.id);
    }
    /** Sets the active sort id and determines the new sort direction. */
    sort(sortable) {
        if (this.active != sortable.id) {
            this.active = sortable.id;
            this.direction = sortable.start ? sortable.start : this.start;
        }
        else {
            this.direction = this.getNextSortDirection(sortable);
        }
        this.sortChange.emit({ active: this.active, direction: this.direction });
    }
    /** Returns the next sort direction of the active sortable, checking for potential overrides. */
    getNextSortDirection(sortable) {
        var _a, _b, _c;
        if (!sortable) {
            return '';
        }
        // Get the sort direction cycle with the potential sortable overrides.
        const disableClear = (_b = (_a = sortable === null || sortable === void 0 ? void 0 : sortable.disableClear) !== null && _a !== void 0 ? _a : this.disableClear) !== null && _b !== void 0 ? _b : !!((_c = this._defaultOptions) === null || _c === void 0 ? void 0 : _c.disableClear);
        let sortDirectionCycle = getSortDirectionCycle(sortable.start || this.start, disableClear);
        // Get and return the next direction in the cycle
        let nextDirectionIndex = sortDirectionCycle.indexOf(this.direction) + 1;
        if (nextDirectionIndex >= sortDirectionCycle.length) {
            nextDirectionIndex = 0;
        }
        return sortDirectionCycle[nextDirectionIndex];
    }
    ngOnInit() {
        this._markInitialized();
    }
    ngOnChanges() {
        this._stateChanges.next();
    }
    ngOnDestroy() {
        this._stateChanges.complete();
    }
}
RSort.decorators = [
    { type: Directive, args: [{
                selector: '[rSort]',
                exportAs: 'rSort',
                host: { 'class': 'r-sort' },
                inputs: ['disabled: rSortDisabled']
            },] }
];
RSort.ctorParameters = () => [
    { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [R_SORT_DEFAULT_OPTIONS,] }] }
];
RSort.propDecorators = {
    active: [{ type: Input, args: ['rSortActive',] }],
    start: [{ type: Input, args: ['rSortStart',] }],
    direction: [{ type: Input, args: ['rSortDirection',] }],
    disableClear: [{ type: Input, args: ['rSortDisableClear',] }],
    sortChange: [{ type: Output, args: ['rSortChange',] }]
};
/** Returns the sort direction cycle to use given the provided parameters of order and clear. */
function getSortDirectionCycle(start, disableClear) {
    let sortOrder = ['asc', 'desc'];
    if (start == 'desc') {
        sortOrder.reverse();
    }
    if (!disableClear) {
        sortOrder.push('');
    }
    return sortOrder;
}
//# sourceMappingURL=sort.js.map