import * as i0 from '@angular/core';
import { Injectable, Component, Input, Pipe, EventEmitter, ViewChildren, Output, HostListener, NgModule } from '@angular/core';
import { BehaviorSubject, Subject, map, filter, take, combineLatest, takeUntil } from 'rxjs';
import * as i1 from '@mintplayer/ng-bootstrap/calendar-month';
import * as i3 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i2 from '@mintplayer/ng-bootstrap/icon';
import { BsIconModule } from '@mintplayer/ng-bootstrap/icon';

var ESchedulerMode;
(function (ESchedulerMode) {
    ESchedulerMode[ESchedulerMode["week"] = 0] = "week";
    ESchedulerMode[ESchedulerMode["timeline"] = 1] = "timeline";
})(ESchedulerMode || (ESchedulerMode = {}));

var EDragOperation;
(function (EDragOperation) {
    EDragOperation[EDragOperation["none"] = 0] = "none";
    EDragOperation[EDragOperation["createEvent"] = 1] = "createEvent";
    EDragOperation[EDragOperation["resizeEvent"] = 2] = "resizeEvent";
    EDragOperation[EDragOperation["moveEvent"] = 3] = "moveEvent";
})(EDragOperation || (EDragOperation = {}));

class BsTimelineService {
    splitInParts(event) {
        let startTime = event.start;
        const result = [];
        const eventOrNull = 'color' in event ? event : null;
        while (!this.dateEquals(startTime, event.end)) {
            const end = new Date(startTime.getFullYear(), startTime.getMonth(), startTime.getDate() + 1, 0, 0, 0);
            result.push({ start: startTime, end: end, event: eventOrNull });
            startTime = end;
        }
        if (startTime != event.end) {
            result.push({ start: startTime, end: event.end, event: eventOrNull });
        }
        return { event: event, parts: result };
    }
    dateEquals(date1, date2) {
        return (date1.getFullYear() === date2.getFullYear() &&
            date1.getMonth() === date2.getMonth() &&
            date1.getDate() === date2.getDate());
    }
    getTimeline(events) {
        const timestamps = this.getTimestamps(events);
        const tracks = [];
        timestamps.forEach((timestamp, tIndex) => {
            const starting = events.filter((e) => e.start === timestamp);
            // const ending = events.filter((e) => e.end === timestamp);
            starting.forEach((startedEvent, eIndex) => {
                const freeTracks = tracks.filter(t => this.trackIsFreeAt(t, startedEvent));
                if (freeTracks.length === 0) {
                    tracks.push({ index: tracks.length, events: [startedEvent] });
                }
                else {
                    freeTracks[0].events.push(startedEvent);
                }
            });
        });
        return tracks;
    }
    getTimestamps(events) {
        const allTimestamps = events.map(e => [e.start, e.end])
            .reduce((flat, toFlatten) => flat.concat(toFlatten), []);
        return allTimestamps
            .filter((t, i) => allTimestamps.indexOf(t) === i)
            .sort((t1, t2) => t1 - t2);
    }
    trackIsFreeAt(track, event) {
        if (track.events.every((ev) => (ev.end <= event.start) || (event.end <= ev.start))) {
            return true;
        }
        else {
            return false;
        }
    }
}
BsTimelineService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsTimelineService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
BsTimelineService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsTimelineService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsTimelineService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

class ResourceGroupPresenterComponent {
    constructor() {
        this.level = 0;
        this.resourceOrGroup$ = new BehaviorSubject(null);
        this.timeSlots$ = new BehaviorSubject([]);
        this.isExpanded$ = new BehaviorSubject(false);
        this.destroyed$ = new Subject();
        this.data$ = this.resourceOrGroup$
            .pipe(map((resourceOrGroup) => {
            if (!resourceOrGroup) {
                return null;
            }
            else if ('children' in resourceOrGroup) {
                return {
                    resource: null,
                    resourceGroup: resourceOrGroup
                };
            }
            else {
                return {
                    resource: resourceOrGroup,
                    resourceGroup: null
                };
            }
        }))
            .pipe(filter((resourceOrGroup) => !!resourceOrGroup))
            .pipe(map((resourceOrGroup) => resourceOrGroup));
        this.colSpan$ = this.timeSlots$
            .pipe(map(timeSlots => timeSlots
            .map(timeslot => timeslot.slots.length)
            .reduce((sum, current) => sum + current, 0)));
    }
    //#region resourceOrGroup
    get resourceOrGroup() {
        return this.resourceOrGroup$.value;
    }
    set resourceGroup(value) {
        this.resourceOrGroup$.next(value);
    }
    //#endregion
    //#region timeSlots
    get timeSlots() {
        return this.timeSlots$.value;
    }
    set timeSlots(value) {
        this.timeSlots$.next(value);
    }
    //#endregion
    //#region isExpanded
    get isExpanded() {
        return this.isExpanded$.value;
    }
    set isExpanded(value) {
        this.isExpanded$.next(value);
    }
    //#endregion
    toggleExpanded() {
        this.isExpanded$.pipe(take(1)).subscribe((isExpanded) => {
            this.isExpanded$.next(!isExpanded);
        });
    }
    ngOnDestroy() {
        this.destroyed$.next(true);
    }
}
ResourceGroupPresenterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ResourceGroupPresenterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
ResourceGroupPresenterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: ResourceGroupPresenterComponent, selector: "bs-resource-group-presenter", inputs: { level: "level", resourceGroup: "resourceGroup", timeSlots: "timeSlots", isExpanded: "isExpanded" }, ngImport: i0, template: "<ng-container *ngIf=\"(data$ | async) as data\">\n\n    <!-- Data is a resource group -->\n    <ng-container *ngIf=\"data.resourceGroup\">\n        <!-- Header -->\n        <tr class=\"p-0 cursor-pointer\" *ngIf=\"(timeSlots$ | async) as timeSlots\" [title]=\"data.resourceGroup.description\">\n            <ng-container *ngIf=\"(colSpan$ | async) as colspan\">\n                <td class=\"p-2 cursor-pointer\" [colSpan]=\"colspan + 1\" (click)=\"toggleExpanded()\">\n                    <span class=\"p-2 align-middle position-sticky\">\n                        <bs-icon [icon]=\"'chevron-down'\" [style.padding-left.px]=\"level * 20\" *ngIf=\"isExpanded$ | async\"></bs-icon>\n                        <bs-icon [icon]=\"'chevron-right'\" [style.padding-left.px]=\"level * 20\" *ngIf=\"(isExpanded$ | async) === false\"></bs-icon>\n                        {{ data.resourceGroup.description }}\n                    </span>\n                </td>\n            </ng-container>\n        </tr>\n\n        <!-- Subgroups or resources -->\n        <ng-container *ngIf=\"isExpanded$ | async\">\n            <ng-container *ngIf=\"(timeSlots$ | async) as timeSlots\">\n                <ng-container *ngFor=\"let child of data.resourceGroup.children\">\n                    <bs-resource-group-presenter [resourceGroup]=\"child\" [timeSlots]=\"timeSlots\" [level]=\"level + 1\"></bs-resource-group-presenter>\n                </ng-container>\n            </ng-container>\n        </ng-container>\n    </ng-container>\n\n    <!-- Data is a resource -->\n    <tr *ngIf=\"data.resource\" class=\"p-0 bordered\" [title]=\"data.resource.description\">\n        <td class=\"p-0 bg-white\">\n            <div class=\"p-2\">{{ data.resource.description }}</div>\n        </td>\n        <ng-container *ngFor=\"let slots of (timeSlots$ | async)\">\n            <td class=\"bg-white border-1\" *ngFor=\"let slot of slots.slots\">\n                <!-- {{ slot.start | date: 'dd/MM/yyyy HH:mm:ss' }} -->\n            </td>\n        </ng-container>\n    </tr>\n</ng-container>", styles: [":host{display:contents}tr{border-bottom-width:1px}tr:not(.bordered) td span.position-sticky{left:0;right:0}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.BsIconComponent, selector: "bs-icon", inputs: ["icon"] }, { kind: "component", type: ResourceGroupPresenterComponent, selector: "bs-resource-group-presenter", inputs: ["level", "resourceGroup", "timeSlots", "isExpanded"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: ResourceGroupPresenterComponent, decorators: [{
            type: Component,
            args: [{ selector: 'bs-resource-group-presenter', template: "<ng-container *ngIf=\"(data$ | async) as data\">\n\n    <!-- Data is a resource group -->\n    <ng-container *ngIf=\"data.resourceGroup\">\n        <!-- Header -->\n        <tr class=\"p-0 cursor-pointer\" *ngIf=\"(timeSlots$ | async) as timeSlots\" [title]=\"data.resourceGroup.description\">\n            <ng-container *ngIf=\"(colSpan$ | async) as colspan\">\n                <td class=\"p-2 cursor-pointer\" [colSpan]=\"colspan + 1\" (click)=\"toggleExpanded()\">\n                    <span class=\"p-2 align-middle position-sticky\">\n                        <bs-icon [icon]=\"'chevron-down'\" [style.padding-left.px]=\"level * 20\" *ngIf=\"isExpanded$ | async\"></bs-icon>\n                        <bs-icon [icon]=\"'chevron-right'\" [style.padding-left.px]=\"level * 20\" *ngIf=\"(isExpanded$ | async) === false\"></bs-icon>\n                        {{ data.resourceGroup.description }}\n                    </span>\n                </td>\n            </ng-container>\n        </tr>\n\n        <!-- Subgroups or resources -->\n        <ng-container *ngIf=\"isExpanded$ | async\">\n            <ng-container *ngIf=\"(timeSlots$ | async) as timeSlots\">\n                <ng-container *ngFor=\"let child of data.resourceGroup.children\">\n                    <bs-resource-group-presenter [resourceGroup]=\"child\" [timeSlots]=\"timeSlots\" [level]=\"level + 1\"></bs-resource-group-presenter>\n                </ng-container>\n            </ng-container>\n        </ng-container>\n    </ng-container>\n\n    <!-- Data is a resource -->\n    <tr *ngIf=\"data.resource\" class=\"p-0 bordered\" [title]=\"data.resource.description\">\n        <td class=\"p-0 bg-white\">\n            <div class=\"p-2\">{{ data.resource.description }}</div>\n        </td>\n        <ng-container *ngFor=\"let slots of (timeSlots$ | async)\">\n            <td class=\"bg-white border-1\" *ngFor=\"let slot of slots.slots\">\n                <!-- {{ slot.start | date: 'dd/MM/yyyy HH:mm:ss' }} -->\n            </td>\n        </ng-container>\n    </tr>\n</ng-container>", styles: [":host{display:contents}tr{border-bottom-width:1px}tr:not(.bordered) td span.position-sticky{left:0;right:0}\n"] }]
        }], ctorParameters: function () { return []; }, propDecorators: { level: [{
                type: Input
            }], resourceGroup: [{
                type: Input
            }], timeSlots: [{
                type: Input
            }], isExpanded: [{
                type: Input
            }] } });

class BsSecondsTimespanPipe {
    transform(value) {
        return (value.end.getTime() - value.start.getTime()) / 1000;
    }
}
BsSecondsTimespanPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSecondsTimespanPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
BsSecondsTimespanPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: BsSecondsTimespanPipe, name: "bsSecondsTimespan" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSecondsTimespanPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'bsSecondsTimespan'
                }]
        }] });

class BsSecondsTodayOffsetPipe {
    transform(value) {
        const today = new Date(value.start);
        today.setHours(0);
        today.setMinutes(0);
        today.setSeconds(0);
        return (value.start.getTime() - today.getTime()) / 1000;
    }
}
BsSecondsTodayOffsetPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSecondsTodayOffsetPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
BsSecondsTodayOffsetPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: BsSecondsTodayOffsetPipe, name: "bsSecondsTodayOffset" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSecondsTodayOffsetPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'bsSecondsTodayOffset'
                }]
        }] });

class DayOfWeekPipe {
    transform(value) {
        const dayOfWeek = value.start.getDay();
        if (dayOfWeek === 0) {
            return 7;
        }
        else {
            return dayOfWeek;
        }
    }
}
DayOfWeekPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: DayOfWeekPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
DayOfWeekPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: DayOfWeekPipe, name: "dayOfWeek" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: DayOfWeekPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'dayOfWeek'
                }]
        }] });

class BsSchedulerComponent {
    constructor(calendarMonthService, timelineService) {
        this.calendarMonthService = calendarMonthService;
        this.timelineService = timelineService;
        this.resources$ = new BehaviorSubject([]);
        this.weekOptions$ = new BehaviorSubject({ unitHeight: 30 });
        this.timelineOptions$ = new BehaviorSubject({ unitWidth: 50 });
        this.previewEvent$ = new BehaviorSubject(null);
        this.timeSlotDuration$ = new BehaviorSubject(1800);
        this.timeSlots$ = new BehaviorSubject([]);
        this.mouseState$ = new BehaviorSubject(false);
        this.hoveredTimeSlot$ = new BehaviorSubject(null);
        this.hoveredEvent$ = new BehaviorSubject(null);
        this.destroyed$ = new Subject();
        //#region Mode
        this.modes = ESchedulerMode;
        this.mode$ = new BehaviorSubject(ESchedulerMode.week);
        this.modeChange = new EventEmitter();
        //#endregion
        // //#region Scale
        // scale$ = new BehaviorSubject<SchedulerScale>(availableScales[4]);
        // @Output() public scaleChange = new EventEmitter<SchedulerScale>();
        // public get scale() {
        //   return this.scale$.value;
        // }
        // @Input() public set scale(value: SchedulerScale) {
        //   this.scale$.next(value);
        // }
        // //#endregion
        //#region WeekOptions
        this.weekOptionsChange = new EventEmitter();
        //#endregion
        //#region TimelineOptions
        this.timelineOptionsChange = new EventEmitter();
        //#endregion
        //#region maxInnerHeight
        this.maxInnerHeight = null;
        this.operation = null;
        this.dragStartTimeslot = null;
        const monday = this.calendarMonthService.getMondayBefore(new Date());
        this.currentWeekOrMonth$ = new BehaviorSubject(monday);
        this.shownDays$ = combineLatest([this.currentWeekOrMonth$, this.mode$])
            .pipe(map(([currentDay, mode]) => {
            currentDay.setHours(0);
            currentDay.setMinutes(0);
            currentDay.setSeconds(0);
            currentDay.setMilliseconds(0);
            switch (mode) {
                case ESchedulerMode.week: {
                    return Array.from(Array(7).keys()).map((x) => this.addDays(currentDay, x));
                }
                case ESchedulerMode.timeline: {
                    const firstDay = new Date(currentDay.getFullYear(), currentDay.getMonth(), 1);
                    const daysOfMonth = new Date(currentDay.getFullYear(), currentDay.getMonth() + 1, 0).getDate();
                    return Array.from(Array(daysOfMonth).keys()).map((x) => this.addDays(firstDay, x));
                }
            }
        }));
        this.daysOfWeekWithTimestamps$ = this.shownDays$
            .pipe(map((shownDays) => ({ start: shownDays[0].getTime(), end: shownDays[shownDays.length - 1].getTime() + 24 * 60 * 60 * 1000 })));
        this.events$ = this.resources$
            .pipe(map((resourcesOrGroups) => resourcesOrGroups.map(resOrGroup => this.getResourcesForGroup(resOrGroup))))
            .pipe(map(jaggedResources => jaggedResources.reduce((flat, toFlatten) => flat.concat(toFlatten), [])))
            .pipe(map(resources => resources.map(res => res.events)))
            .pipe(map(jaggedEvents => jaggedEvents.reduce((flat, toFlatten) => flat.concat(toFlatten), [])));
        // groups.reduce((flat, toFlatten) => flat.concat(toFlatten.children), [])
        this.eventParts$ = this.events$.pipe(map((events) => events.map((ev) => this.timelineService.splitInParts(ev))));
        this.eventPartsForThisWeek$ = combineLatest([
            this.daysOfWeekWithTimestamps$,
            this.eventParts$
                .pipe(map(eventParts => eventParts.map(evp => evp.parts)))
                .pipe(map(jaggedParts => jaggedParts.reduce((flat, toFlatten) => flat.concat(toFlatten), [])))
        ])
            .pipe(map(([startAndEnd, eventParts]) => {
            return eventParts.filter(eventPart => {
                return !((eventPart.end.getTime() <= startAndEnd.start) || (eventPart.start.getTime() >= startAndEnd.end));
            });
        }));
        this.previewEventParts$ = this.previewEvent$.pipe(map((event) => {
            if (event) {
                return this.timelineService.splitInParts(event);
            }
            else {
                return null;
            }
        }));
        this.previewEventPartsForThisWeek$ = combineLatest([this.daysOfWeekWithTimestamps$, this.previewEventParts$])
            .pipe(map(([startAndEnd, previewEventParts]) => {
            if (previewEventParts) {
                return previewEventParts.parts.filter(eventPart => {
                    return !((eventPart.end.getTime() <= startAndEnd.start) || (eventPart.start.getTime() >= startAndEnd.end));
                });
            }
            else {
                return [];
            }
        }));
        this.timelinedEventPartsForThisWeek$ = this.eventPartsForThisWeek$
            .pipe(map(eventParts => {
            // We'll only use the events for this week
            const events = eventParts.map(ep => ep.event)
                .filter((e, i, list) => list.indexOf(e) === i)
                .filter((e) => !!e)
                .map((e) => e);
            const timeline = this.timelineService.getTimeline(events);
            const result = timeline.map(track => track.events.map(ev => ({ event: ev, index: track.index })))
                .reduce((flat, toFlatten) => flat.concat(toFlatten), [])
                .map((evi) => eventParts.filter(p => p.event === evi.event).map(p => ({ part: p, index: evi.index })))
                .reduce((flat, toFlatten) => flat.concat(toFlatten), []);
            return {
                total: timeline.length,
                parts: result
            };
        }));
        combineLatest([this.mode$, this.shownDays$, this.timeSlotDuration$])
            .pipe(filter(([mode, shownDays, duration]) => mode !== null))
            .pipe(map(([mode, shownDays, duration]) => {
            switch (mode) {
                case ESchedulerMode.week: {
                    const timeSlotsPerDay = Math.floor((60 * 60 * 24) / duration);
                    return Array.from(Array(timeSlotsPerDay).keys()).map((index) => {
                        const timeslotForMonday = this.createTimeslot(shownDays[0], index, duration);
                        return {
                            slots: shownDays.map((day) => {
                                const start = new Date(day);
                                start.setHours(timeslotForMonday.start.getHours());
                                start.setMinutes(timeslotForMonday.start.getMinutes());
                                start.setSeconds(timeslotForMonday.start.getSeconds());
                                start.setMilliseconds(timeslotForMonday.start.getMilliseconds());
                                const end = new Date(day);
                                end.setHours(timeslotForMonday.end.getHours());
                                end.setMinutes(timeslotForMonday.end.getMinutes());
                                end.setSeconds(timeslotForMonday.end.getSeconds());
                                end.setMilliseconds(timeslotForMonday.end.getMilliseconds());
                                end.setDate(end.getDate() + timeslotForMonday.end.getDate() - timeslotForMonday.start.getDate());
                                return { start, end };
                            }),
                            stamp: timeslotForMonday.start
                        };
                    });
                }
                case ESchedulerMode.timeline: {
                    const totalTimeslots = (24 * 60 * 60) / duration;
                    return shownDays.map((day) => {
                        return {
                            slots: Array.from(Array(totalTimeslots).keys())
                                .map((index) => {
                                return this.createTimeslot(day, index, duration);
                            }),
                            stamp: day
                        };
                    });
                }
                default: {
                    throw 'Unknown value for Mode: ' + mode;
                }
            }
        }))
            .subscribe((timeslots) => {
            // For performance reasons, we're not using an observable here, but persist the timeslots in a BehaviorSubject.
            this.timeSlots$.next(timeslots);
        });
        this.weekOptions$
            .pipe(takeUntil(this.destroyed$))
            .subscribe((weekOptions) => {
            this.weekOptionsChange.emit(weekOptions);
        });
        this.timelineOptions$
            .pipe(takeUntil(this.destroyed$))
            .subscribe((timelineOptions) => {
            this.timelineOptionsChange.emit(timelineOptions);
        });
        // combineLatest([this.mode$, this.scale$])
        //   .pipe(filter(([mode, scale]) => mode === ESchedulerMode.timeline))
    }
    createTimeslot(date, index, duration) {
        const timeSlotStart = new Date(date);
        timeSlotStart.setTime(+timeSlotStart.getTime() + index * duration * 1000);
        const timeSlotEnd = new Date(timeSlotStart);
        timeSlotEnd.setTime(+timeSlotEnd.getTime() + duration * 1000);
        return { start: timeSlotStart, end: timeSlotEnd };
    }
    getResourcesForGroup(resourceOrGroup) {
        if ('children' in resourceOrGroup) {
            return resourceOrGroup.children
                .map((child) => this.getResourcesForGroup(child))
                .reduce((flat, toFlatten) => flat.concat(toFlatten), []);
        }
        else {
            return [resourceOrGroup];
        }
    }
    get mode() {
        return this.mode$.value;
    }
    set mode(value) {
        this.mode$.next(value);
    }
    get weekOptions() {
        return this.weekOptions$.value;
    }
    set weekOptions(value) {
        this.weekOptions$.next(value);
    }
    get timelineOptions() {
        return this.timelineOptions$.value;
    }
    set timelineOptions(value) {
        this.timelineOptions$.next(value);
    }
    //#endregion
    //#region Resources
    get resources() {
        return this.resources$.value;
    }
    set resources(value) {
        this.resources$.next(value);
    }
    //#endregion
    addDays(date, days) {
        const result = new Date(date);
        result.setDate(result.getDate() + days);
        return result;
    }
    onPreviousWeekOrMonth() {
        this.onChangeWeekOrMonth(false);
    }
    onNextWeekOrMonth() {
        this.onChangeWeekOrMonth(true);
    }
    onChangeWeekOrMonth(next) {
        combineLatest([this.currentWeekOrMonth$, this.mode$])
            .pipe(map(([currentWeekOrMonth, mode]) => {
            switch (mode) {
                case ESchedulerMode.week: {
                    return this.addDays(currentWeekOrMonth, (next ? 7 : -7));
                }
                case ESchedulerMode.timeline: {
                    return new Date(currentWeekOrMonth.getFullYear(), currentWeekOrMonth.getMonth() + (next ? 1 : -1), 1);
                }
            }
        }), take(1))
            .subscribe((w) => this.currentWeekOrMonth$.next(w));
    }
    onHoverEvent(ev) {
        this.hoveredEvent$.next(ev);
    }
    onLeaveEvent(ev) {
        this.hoveredEvent$.next(null);
    }
    onCreateEvent(ev, slot) {
        ev.preventDefault();
        this.mouseState$.next(true);
        this.dragStartTimeslot = slot;
        this.operation = {
            operation: EDragOperation.createEvent,
            event: {
                start: slot.start,
                end: slot.end,
                color: '#F00',
                description: 'Test event',
            },
            meta: null,
        };
        this.previewEvent$.next({ start: slot.start, end: slot.end });
    }
    randomColor() {
        const brightness = 128;
        return '#' + this.randomChannel(brightness) + this.randomChannel(brightness) + this.randomChannel(brightness);
    }
    randomChannel(brightness) {
        const r = 255 - brightness;
        const n = 0 | ((Math.random() * r) + brightness);
        const s = n.toString(16);
        return (s.length == 1) ? '0' + s : s;
    }
    onStartDragEvent(eventPart, ev) {
        ev.preventDefault();
        this.hoveredTimeSlot$.pipe(take(1)).subscribe((hoveredTimeSlot) => {
            if (eventPart.event) {
                this.dragStartTimeslot = hoveredTimeSlot;
                this.operation = {
                    operation: EDragOperation.moveEvent,
                    event: eventPart.event,
                    meta: null,
                };
                this.previewEvent$.next({ start: eventPart.event.start, end: eventPart.event.end });
            }
        });
    }
    onStartResizeEvent(event, position) {
        if (event) {
            switch (position) {
                case 'top':
                    {
                        this.operation = {
                            operation: EDragOperation.resizeEvent,
                            event: event,
                            meta: { position },
                        };
                        this.previewEvent$.next({ start: event.start, end: event.end });
                    }
                    break;
                case 'bottom':
                    {
                        this.operation = {
                            operation: EDragOperation.resizeEvent,
                            event: event,
                            meta: { position },
                        };
                        this.previewEvent$.next({ start: event.start, end: event.end });
                    }
                    break;
            }
        }
    }
    //#region hoveredTimeslot$
    getHoveredTimeslot(ev, timeSlots) {
        const hoveredSlots = this.timeSlotElements.filter((el) => {
            const rct = el.nativeElement.getBoundingClientRect();
            if (rct.left <= ev.x && ev.x <= rct.right && rct.top <= ev.y && ev.y <= rct.bottom) {
                return true;
            }
            else {
                return false;
            }
        });
        if (!hoveredSlots || hoveredSlots.length === 0) {
            return null;
        }
        const slotElement = hoveredSlots[0].nativeElement;
        const strRow = slotElement.getAttribute('data-row');
        if (!strRow) {
            return null;
        }
        const row = parseInt(strRow);
        const strColumn = slotElement.getAttribute('data-column');
        if (!strColumn) {
            return null;
        }
        const column = parseInt(strColumn);
        const slot = timeSlots[row].slots[column];
        return slot;
    }
    onMousemove(ev) {
        this.timeSlots$.pipe(take(1)).subscribe((timeSlots) => {
            const hovered = this.getHoveredTimeslot(ev, timeSlots);
            this.hoveredTimeSlot$.next(hovered);
            if (this.operation) {
                switch (this.operation.operation) {
                    case EDragOperation.createEvent:
                        {
                            if (this.operation.event && this.dragStartTimeslot && hovered && (this.operation.event.end.getTime() != hovered.end.getTime())) {
                                if (this.dragStartTimeslot.start.getTime() === hovered.start.getTime()) {
                                    // 1 slot
                                }
                                else if (this.dragStartTimeslot.start.getTime() < hovered.start.getTime()) {
                                    // Drag down
                                    this.previewEvent$
                                        .pipe(filter((ev) => !!ev && !!this.dragStartTimeslot))
                                        .pipe(map((ev) => {
                                        if (ev && this.dragStartTimeslot) {
                                            ev.start = this.dragStartTimeslot.start;
                                            ev.end = hovered.end;
                                        }
                                        return ev;
                                    }))
                                        .pipe(take(1))
                                        .subscribe((ev) => this.previewEvent$.next(ev));
                                }
                                else if (this.dragStartTimeslot.start.getTime() > hovered.start.getTime()) {
                                    // Drag up
                                    this.previewEvent$
                                        .pipe(filter((ev) => !!ev && !!this.dragStartTimeslot))
                                        .pipe(map((ev) => {
                                        if (ev && this.dragStartTimeslot) {
                                            ev.start = hovered.start;
                                            ev.end = this.dragStartTimeslot.end;
                                        }
                                        return ev;
                                    }))
                                        .pipe(take(1))
                                        .subscribe((ev) => this.previewEvent$.next(ev));
                                }
                            }
                        }
                        break;
                    case EDragOperation.moveEvent:
                        {
                            if (hovered && this.dragStartTimeslot) {
                                this.previewEvent$
                                    .pipe(filter((ev) => !!ev && !!this.dragStartTimeslot))
                                    .pipe(map((ev) => {
                                    if (ev && this.dragStartTimeslot) {
                                        const result = {
                                            start: new Date(ev.start.getTime() + hovered.start.getTime() - this.dragStartTimeslot.start.getTime()),
                                            end: new Date(ev.end.getTime() + hovered.start.getTime() - this.dragStartTimeslot.start.getTime())
                                        };
                                        this.dragStartTimeslot = hovered;
                                        return result;
                                    }
                                    else {
                                        return ev;
                                    }
                                }))
                                    .pipe(take(1))
                                    .subscribe(ev => this.previewEvent$.next(ev));
                            }
                        }
                        break;
                    case EDragOperation.resizeEvent:
                        {
                            if (hovered) {
                                this.previewEvent$
                                    .pipe(filter((ev) => !!ev))
                                    .pipe(map((ev) => {
                                    if (ev && this.operation && this.operation.event) {
                                        if (this.operation.meta.position === 'top') {
                                            ev.start = hovered.start;
                                            ev.end = this.operation.event.end;
                                        }
                                        else if (this.operation.meta.position === 'bottom') {
                                            ev.start = this.operation.event.start;
                                            ev.end = hovered.end;
                                        }
                                    }
                                    return ev;
                                }))
                                    .pipe(take(1))
                                    .subscribe((ev) => this.previewEvent$.next(ev));
                            }
                        }
                        break;
                }
            }
        });
    }
    //#endregion
    onMouseUp(ev) {
        if (this.operation) {
            switch (this.operation.operation) {
                case EDragOperation.createEvent:
                    {
                        combineLatest([this.previewEvent$])
                            .pipe(take(1))
                            .subscribe(([previewEvent]) => {
                            if (previewEvent) {
                                this.operation = null;
                                this.dragStartTimeslot = null;
                                this.resources$.next([
                                    ...this.resources$.value,
                                    {
                                        description: 'New resource group',
                                        events: [{
                                                start: previewEvent.start,
                                                end: previewEvent.end,
                                                color: this.randomColor(),
                                                description: 'New event'
                                            }]
                                    }
                                ]);
                                this.previewEvent$.next(null);
                            }
                        });
                    }
                    break;
                case EDragOperation.moveEvent:
                case EDragOperation.resizeEvent:
                    {
                        this.previewEvent$
                            .pipe(filter((ev) => !!ev))
                            .pipe(take(1))
                            .subscribe((previewEvent) => {
                            if (this.operation && this.operation.event && previewEvent) {
                                this.operation.event.start = previewEvent.start;
                                this.operation.event.end = previewEvent.end;
                                this.operation = null;
                                this.dragStartTimeslot = null;
                                this.resources$.next(this.resources$.value);
                                this.previewEvent$.next(null);
                            }
                        });
                    }
                    break;
            }
        }
    }
    ngOnDestroy() {
        this.destroyed$.next(true);
    }
}
BsSchedulerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSchedulerComponent, deps: [{ token: i1.BsCalendarMonthService }, { token: BsTimelineService }], target: i0.ɵɵFactoryTarget.Component });
BsSchedulerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.4", type: BsSchedulerComponent, selector: "bs-scheduler", inputs: { mode: "mode", weekOptions: "weekOptions", timelineOptions: "timelineOptions", maxInnerHeight: "maxInnerHeight", resources: "resources" }, outputs: { modeChange: "modeChange", weekOptionsChange: "weekOptionsChange", timelineOptionsChange: "timelineOptionsChange" }, host: { listeners: { "document:mousemove": "onMousemove($event)", "document:mouseup": "onMouseUp($event)" } }, viewQueries: [{ propertyName: "timeSlotElements", predicate: ["slot"], descendants: true }], ngImport: i0, template: "<div class=\"d-flex flex-column w-100 overflow-y-auto mb-0 week-schedule\" [style.max-height.px]=\"null\"\n    *ngIf=\"(mode$ | async) === modes.week\">\n    <div class=\"calendar-head\">\n        <div class=\"w-100 d-flex flex-row\">\n            <div class=\"d-flex calendar-left justify-content-between\">\n                <button class=\"btn btn-default flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n                    <bs-icon [icon]=\"'chevron-left'\" class=\"px-0\"></bs-icon>\n                </button>\n                <button class=\"btn btn-default flex-end\" (click)=\"onNextWeekOrMonth()\">\n                    <bs-icon [icon]=\"'chevron-right'\" class=\"px-0\"></bs-icon>\n                </button>\n            </div>\n            <div class=\"flex-grow-1 calendar-head-cell\" *ngFor=\"let day of (shownDays$ | async)\">\n                <span class=\"d-block col-form-label text-center text-nowrap\">\n                    <span>{{ day | date: 'dd-MM' }}</span><span class=\"d-none d-lg-inline-block\">-{{ day | date: 'yyyy' }}</span>\n                </span>\n            </div>\n        </div>\n    </div>\n    <div class=\"calendar-body\" [style.height.px]=\"maxInnerHeight\">\n        <div class=\"position-relative\" *ngIf=\"(timeSlots$ | async) as row\">\n            <ng-container *ngIf=\"(weekOptions$ | async) as weekOptions\">\n                <!-- Timeslots -->\n                <div *ngFor=\"let timeslots of row; let i = index\" class=\"d-flex flex-row p-0 timeslot\" [style.height.px]=\"weekOptions.unitHeight\">\n                    <div class=\"calendar-cell calendar-left align-top px-2 py-0\">{{ timeslots.slots[0].start | date: 'HH:mm:ss' }}</div>\n                    <div class=\"calendar-cell flex-grow-1\" *ngFor=\"let slot of timeslots.slots; let j = index\" #slot (mousedown)=\"onCreateEvent($event, slot)\" [attr.data-row]=\"i\" [attr.data-column]=\"j\"></div>\n                </div>\n\n                <!-- Events -->\n                <ng-container *ngIf=\"(timeSlotDuration$ | async) as timeSlotDuration\">\n                    <ng-container *ngIf=\"(timelinedEventPartsForThisWeek$ | async) as partData\">\n                        <div *ngFor=\"let eventPart of partData.parts\" class=\"event p-0\"\n                            [style.top.px]=\"(eventPart.part | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart.part | dayOfWeek) - 1) + '))'\">\n                            <div class=\"event-inner\" [class.hover]=\"(hoveredEvent$ | async) === eventPart.part.event\"\n                                [style.width]=\"'calc(100% / ' + partData.total + ')'\"\n                                [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n                                [style.margin-left]=\"'calc(100% / ' + partData.total + ' * ' + eventPart.index + ')'\">\n\n                                <div class=\"event-resize top\"\n                                    *ngIf=\"eventPart.part.start === eventPart.part.event?.start\"\n                                    (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'top')\"></div>\n                                <div class=\"event-border\"></div>\n                                <div class=\"event-wrapper\" *ngIf=\"eventPart.part.event\"\n                                    (mousedown)=\"onStartDragEvent(eventPart.part, $event)\"\n                                    (mouseenter)=\"onHoverEvent(eventPart.part.event)\"\n                                    (mouseleave)=\"onLeaveEvent(eventPart.part.event)\">\n                                    <div class=\"event-bg\" [style.background-color]=\"eventPart.part.event.color\"></div>\n                                    <div class=\"event-label\">{{ eventPart.part.event.description }}</div>\n                                </div>\n                                <div class=\"event-resize bottom\"\n                                    *ngIf=\"eventPart.part.end === eventPart.part.event?.end\"\n                                    (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'bottom')\"></div>\n                            </div>\n                        </div>\n                    </ng-container>\n                    <ng-container *ngIf=\"(previewEventPartsForThisWeek$ | async) as previewPartData\">\n                        <div *ngFor=\"let eventPart of previewPartData\" class=\"event preview p-0\"\n                            [style.top.px]=\"(eventPart | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart | dayOfWeek) - 1) + '))'\">\n                            <div class=\"event-inner w-100\"\n                                [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\">\n                            </div>\n                        </div>\n                    </ng-container>\n                </ng-container>\n            </ng-container>\n        </div>\n    </div>\n</div>\n<div class=\"d-flex flex-column-100 overflow-y-auto mb-0 bg-white timeline\" *ngIf=\"(mode$ | async) === modes.timeline\">\n    <div class=\"calendar-head d-flex\">\n        <button class=\"btn flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n            <bs-icon [icon]=\"'chevron-left'\" class=\"px-0\"></bs-icon>\n        </button>\n        <div class=\"flex-grow-1 h3 py-2 mb-0 text-center\">{{ currentWeekOrMonth$ | async | date: 'MMMM yyyy' }}</div>\n        <button class=\"btn flex-start\" (click)=\"onNextWeekOrMonth()\">\n            <bs-icon [icon]=\"'chevron-right'\" class=\"px-0\"></bs-icon>\n        </button>\n    </div>\n    \n    <div class=\"calendar-body table-responsive overflow-x-auto\">\n        <table class=\"table mb-0\">\n            <ng-container *ngIf=\"(timeSlots$ | async) as timeSlots\">\n                <tr>\n                    <td></td>\n                    <td *ngFor=\"let day of timeSlots\" [attr.colspan]=\"day.slots.length\" class=\"text-center px-2\">\n                        <span class=\"position-sticky day-label\">{{ day.stamp | date: 'd EE' }}</span>\n                    </td>\n                </tr>\n                <tr>\n                    <td></td>\n                    <ng-container *ngIf=\"(timelineOptions$ | async) as timelineOptions\">\n                        <ng-container *ngFor=\"let day of timeSlots\">\n                            <td *ngFor=\"let slot of day.slots\">\n                                <span class=\"d-block p-0 text-center\" [style.width.px]=\"timelineOptions.unitWidth\">\n                                    {{ slot.start | date: 'HH:mm' }}\n                                </span>\n                            </td>\n                        </ng-container>\n                    </ng-container>\n                </tr>\n                <bs-resource-group-presenter *ngFor=\"let group of (resources$ | async)\" [resourceGroup]=\"group\" [timeSlots]=\"timeSlots\"></bs-resource-group-presenter>\n            </ng-container>\n        </table>\n    </div>\n</div>", styles: [":host{display:block;border:1px solid #333;border-top-right-radius:10px;border-top-left-radius:10px;overflow:hidden}.calendar-head{background:#F7F7F7;color:#007aff}.tabel .calendar-head{flex:0 0 auto}.tabel .calendar-body{display:block;flex:1 1 auto}.week-schedule .calendar-head>div{padding-right:18px}.week-schedule .calendar-body{overflow-y:scroll;overflow-x:hidden}.week-schedule .calendar-body .calendar-cell{border-right:1px solid #DEE2E6;border-bottom:1px solid #DEE2E6;cursor:default}.week-schedule .calendar-body .calendar-cell.hover{border-top-width:3px}.week-schedule .calendar-left{width:90px}.week-schedule .event{z-index:5;width:calc((100% - 90px) / 7);height:100px;overflow:hidden;position:absolute;-webkit-user-select:none;user-select:none;pointer-events:none}.week-schedule .event.preview{background:#666;opacity:.6}.week-schedule .event .event-border{background:black;top:0;left:0;bottom:3px;width:3px;position:absolute;z-index:10;opacity:.3}.week-schedule .event .event-inner{position:relative;inset:0 5px 5px 0;cursor:move;pointer-events:all;overflow:hidden}.week-schedule .event .event-inner .event-wrapper{width:calc(100% - 2px);margin:1px auto 1px 0;height:calc(100% - 3px)}.week-schedule .event .event-inner .event-wrapper .event-bg{opacity:.5;height:100%;transition:opacity .15s ease-in-out}.week-schedule .event .event-inner .event-wrapper .event-label{position:absolute;top:0;font-size:12px;font-weight:600;padding:4px}.week-schedule .event .event-inner .event-resize{position:absolute;cursor:ns-resize;height:4px;left:0;right:0;z-index:400}.week-schedule .event .event-inner .event-resize.top{top:0}.week-schedule .event .event-inner .event-resize.bottom{bottom:0}.week-schedule .event .event-inner .event-resize:hover{background:#DDD}.week-schedule .event .event-inner.hover .event-bg{opacity:.7!important}@media (max-width: 767px){.week-schedule.tabel .calendar-head .calendar-head-cell{text-orientation:sideways;writing-mode:vertical-rl}}.timeline.tabel{flex-flow:column}.timeline .calendar-body .tabel{background-color:#f7f7f7}.timeline .calendar-body .tabel tr:first-child td{background-color:#fff;border:1px solid #000}.timeline .calendar-body .tabel tr:first-child td:first-child{min-width:10rem}.timeline .calendar-body .tabel tr:first-child span.day-label{left:0;right:0}.timeline .calendar-body .tabel tr:nth-child(2) td{border-width:1px;border-color:inherit}.timeline .calendar-body .tabel>:not(:first-child){border-top:none!important}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.BsIconComponent, selector: "bs-icon", inputs: ["icon"] }, { kind: "component", type: ResourceGroupPresenterComponent, selector: "bs-resource-group-presenter", inputs: ["level", "resourceGroup", "timeSlots", "isExpanded"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.DatePipe, name: "date" }, { kind: "pipe", type: BsSecondsTimespanPipe, name: "bsSecondsTimespan" }, { kind: "pipe", type: BsSecondsTodayOffsetPipe, name: "bsSecondsTodayOffset" }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSchedulerComponent, decorators: [{
            type: Component,
            args: [{ selector: 'bs-scheduler', template: "<div class=\"d-flex flex-column w-100 overflow-y-auto mb-0 week-schedule\" [style.max-height.px]=\"null\"\n    *ngIf=\"(mode$ | async) === modes.week\">\n    <div class=\"calendar-head\">\n        <div class=\"w-100 d-flex flex-row\">\n            <div class=\"d-flex calendar-left justify-content-between\">\n                <button class=\"btn btn-default flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n                    <bs-icon [icon]=\"'chevron-left'\" class=\"px-0\"></bs-icon>\n                </button>\n                <button class=\"btn btn-default flex-end\" (click)=\"onNextWeekOrMonth()\">\n                    <bs-icon [icon]=\"'chevron-right'\" class=\"px-0\"></bs-icon>\n                </button>\n            </div>\n            <div class=\"flex-grow-1 calendar-head-cell\" *ngFor=\"let day of (shownDays$ | async)\">\n                <span class=\"d-block col-form-label text-center text-nowrap\">\n                    <span>{{ day | date: 'dd-MM' }}</span><span class=\"d-none d-lg-inline-block\">-{{ day | date: 'yyyy' }}</span>\n                </span>\n            </div>\n        </div>\n    </div>\n    <div class=\"calendar-body\" [style.height.px]=\"maxInnerHeight\">\n        <div class=\"position-relative\" *ngIf=\"(timeSlots$ | async) as row\">\n            <ng-container *ngIf=\"(weekOptions$ | async) as weekOptions\">\n                <!-- Timeslots -->\n                <div *ngFor=\"let timeslots of row; let i = index\" class=\"d-flex flex-row p-0 timeslot\" [style.height.px]=\"weekOptions.unitHeight\">\n                    <div class=\"calendar-cell calendar-left align-top px-2 py-0\">{{ timeslots.slots[0].start | date: 'HH:mm:ss' }}</div>\n                    <div class=\"calendar-cell flex-grow-1\" *ngFor=\"let slot of timeslots.slots; let j = index\" #slot (mousedown)=\"onCreateEvent($event, slot)\" [attr.data-row]=\"i\" [attr.data-column]=\"j\"></div>\n                </div>\n\n                <!-- Events -->\n                <ng-container *ngIf=\"(timeSlotDuration$ | async) as timeSlotDuration\">\n                    <ng-container *ngIf=\"(timelinedEventPartsForThisWeek$ | async) as partData\">\n                        <div *ngFor=\"let eventPart of partData.parts\" class=\"event p-0\"\n                            [style.top.px]=\"(eventPart.part | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart.part | dayOfWeek) - 1) + '))'\">\n                            <div class=\"event-inner\" [class.hover]=\"(hoveredEvent$ | async) === eventPart.part.event\"\n                                [style.width]=\"'calc(100% / ' + partData.total + ')'\"\n                                [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n                                [style.margin-left]=\"'calc(100% / ' + partData.total + ' * ' + eventPart.index + ')'\">\n\n                                <div class=\"event-resize top\"\n                                    *ngIf=\"eventPart.part.start === eventPart.part.event?.start\"\n                                    (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'top')\"></div>\n                                <div class=\"event-border\"></div>\n                                <div class=\"event-wrapper\" *ngIf=\"eventPart.part.event\"\n                                    (mousedown)=\"onStartDragEvent(eventPart.part, $event)\"\n                                    (mouseenter)=\"onHoverEvent(eventPart.part.event)\"\n                                    (mouseleave)=\"onLeaveEvent(eventPart.part.event)\">\n                                    <div class=\"event-bg\" [style.background-color]=\"eventPart.part.event.color\"></div>\n                                    <div class=\"event-label\">{{ eventPart.part.event.description }}</div>\n                                </div>\n                                <div class=\"event-resize bottom\"\n                                    *ngIf=\"eventPart.part.end === eventPart.part.event?.end\"\n                                    (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'bottom')\"></div>\n                            </div>\n                        </div>\n                    </ng-container>\n                    <ng-container *ngIf=\"(previewEventPartsForThisWeek$ | async) as previewPartData\">\n                        <div *ngFor=\"let eventPart of previewPartData\" class=\"event preview p-0\"\n                            [style.top.px]=\"(eventPart | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n                            [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart | dayOfWeek) - 1) + '))'\">\n                            <div class=\"event-inner w-100\"\n                                [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\">\n                            </div>\n                        </div>\n                    </ng-container>\n                </ng-container>\n            </ng-container>\n        </div>\n    </div>\n</div>\n<div class=\"d-flex flex-column-100 overflow-y-auto mb-0 bg-white timeline\" *ngIf=\"(mode$ | async) === modes.timeline\">\n    <div class=\"calendar-head d-flex\">\n        <button class=\"btn flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n            <bs-icon [icon]=\"'chevron-left'\" class=\"px-0\"></bs-icon>\n        </button>\n        <div class=\"flex-grow-1 h3 py-2 mb-0 text-center\">{{ currentWeekOrMonth$ | async | date: 'MMMM yyyy' }}</div>\n        <button class=\"btn flex-start\" (click)=\"onNextWeekOrMonth()\">\n            <bs-icon [icon]=\"'chevron-right'\" class=\"px-0\"></bs-icon>\n        </button>\n    </div>\n    \n    <div class=\"calendar-body table-responsive overflow-x-auto\">\n        <table class=\"table mb-0\">\n            <ng-container *ngIf=\"(timeSlots$ | async) as timeSlots\">\n                <tr>\n                    <td></td>\n                    <td *ngFor=\"let day of timeSlots\" [attr.colspan]=\"day.slots.length\" class=\"text-center px-2\">\n                        <span class=\"position-sticky day-label\">{{ day.stamp | date: 'd EE' }}</span>\n                    </td>\n                </tr>\n                <tr>\n                    <td></td>\n                    <ng-container *ngIf=\"(timelineOptions$ | async) as timelineOptions\">\n                        <ng-container *ngFor=\"let day of timeSlots\">\n                            <td *ngFor=\"let slot of day.slots\">\n                                <span class=\"d-block p-0 text-center\" [style.width.px]=\"timelineOptions.unitWidth\">\n                                    {{ slot.start | date: 'HH:mm' }}\n                                </span>\n                            </td>\n                        </ng-container>\n                    </ng-container>\n                </tr>\n                <bs-resource-group-presenter *ngFor=\"let group of (resources$ | async)\" [resourceGroup]=\"group\" [timeSlots]=\"timeSlots\"></bs-resource-group-presenter>\n            </ng-container>\n        </table>\n    </div>\n</div>", styles: [":host{display:block;border:1px solid #333;border-top-right-radius:10px;border-top-left-radius:10px;overflow:hidden}.calendar-head{background:#F7F7F7;color:#007aff}.tabel .calendar-head{flex:0 0 auto}.tabel .calendar-body{display:block;flex:1 1 auto}.week-schedule .calendar-head>div{padding-right:18px}.week-schedule .calendar-body{overflow-y:scroll;overflow-x:hidden}.week-schedule .calendar-body .calendar-cell{border-right:1px solid #DEE2E6;border-bottom:1px solid #DEE2E6;cursor:default}.week-schedule .calendar-body .calendar-cell.hover{border-top-width:3px}.week-schedule .calendar-left{width:90px}.week-schedule .event{z-index:5;width:calc((100% - 90px) / 7);height:100px;overflow:hidden;position:absolute;-webkit-user-select:none;user-select:none;pointer-events:none}.week-schedule .event.preview{background:#666;opacity:.6}.week-schedule .event .event-border{background:black;top:0;left:0;bottom:3px;width:3px;position:absolute;z-index:10;opacity:.3}.week-schedule .event .event-inner{position:relative;inset:0 5px 5px 0;cursor:move;pointer-events:all;overflow:hidden}.week-schedule .event .event-inner .event-wrapper{width:calc(100% - 2px);margin:1px auto 1px 0;height:calc(100% - 3px)}.week-schedule .event .event-inner .event-wrapper .event-bg{opacity:.5;height:100%;transition:opacity .15s ease-in-out}.week-schedule .event .event-inner .event-wrapper .event-label{position:absolute;top:0;font-size:12px;font-weight:600;padding:4px}.week-schedule .event .event-inner .event-resize{position:absolute;cursor:ns-resize;height:4px;left:0;right:0;z-index:400}.week-schedule .event .event-inner .event-resize.top{top:0}.week-schedule .event .event-inner .event-resize.bottom{bottom:0}.week-schedule .event .event-inner .event-resize:hover{background:#DDD}.week-schedule .event .event-inner.hover .event-bg{opacity:.7!important}@media (max-width: 767px){.week-schedule.tabel .calendar-head .calendar-head-cell{text-orientation:sideways;writing-mode:vertical-rl}}.timeline.tabel{flex-flow:column}.timeline .calendar-body .tabel{background-color:#f7f7f7}.timeline .calendar-body .tabel tr:first-child td{background-color:#fff;border:1px solid #000}.timeline .calendar-body .tabel tr:first-child td:first-child{min-width:10rem}.timeline .calendar-body .tabel tr:first-child span.day-label{left:0;right:0}.timeline .calendar-body .tabel tr:nth-child(2) td{border-width:1px;border-color:inherit}.timeline .calendar-body .tabel>:not(:first-child){border-top:none!important}\n"] }]
        }], ctorParameters: function () { return [{ type: i1.BsCalendarMonthService }, { type: BsTimelineService }]; }, propDecorators: { timeSlotElements: [{
                type: ViewChildren,
                args: ['slot']
            }], modeChange: [{
                type: Output
            }], mode: [{
                type: Input
            }], weekOptionsChange: [{
                type: Output
            }], weekOptions: [{
                type: Input
            }], timelineOptionsChange: [{
                type: Output
            }], timelineOptions: [{
                type: Input
            }], maxInnerHeight: [{
                type: Input
            }], resources: [{
                type: Input
            }], onMousemove: [{
                type: HostListener,
                args: ['document:mousemove', ['$event']]
            }], onMouseUp: [{
                type: HostListener,
                args: ['document:mouseup', ['$event']]
            }] } });

const availableScales = [
    { time: 60, pixels: 60, markerSize: 900 },
    { time: 120, pixels: 60, markerSize: 900 },
    { time: 300, pixels: 60, markerSize: 900 },
    { time: 900, pixels: 60, markerSize: 900 },
    { time: 3600, pixels: 60, markerSize: 21600 },
    { time: 7200, pixels: 60, markerSize: 21600 },
    { time: 10800, pixels: 60, markerSize: 21600 },
    { time: 21600, pixels: 60, markerSize: 21600 },
    { time: 86400, pixels: 60, markerSize: 604800 }, // 6000s / 60px   = 100 s/px
];

class DateOffsetPipe {
    transform(value) {
        const today = new Date(value.start);
        today.setHours(0);
        today.setMinutes(0);
        today.setSeconds(0);
        return (value.start.getTime() - today.getTime()) / 1000;
    }
}
DateOffsetPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: DateOffsetPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
DateOffsetPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: DateOffsetPipe, name: "dateOffset" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: DateOffsetPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'dateOffset'
                }]
        }] });

class BsSchedulerModule {
}
BsSchedulerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSchedulerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
BsSchedulerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.4", ngImport: i0, type: BsSchedulerModule, declarations: [BsSchedulerComponent,
        BsSecondsTimespanPipe,
        BsSecondsTodayOffsetPipe,
        DateOffsetPipe,
        DayOfWeekPipe,
        ResourceGroupPresenterComponent], imports: [CommonModule,
        BsIconModule], exports: [BsSchedulerComponent,
        ResourceGroupPresenterComponent] });
BsSchedulerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSchedulerModule, imports: [CommonModule,
        BsIconModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.4", ngImport: i0, type: BsSchedulerModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        BsSchedulerComponent,
                        BsSecondsTimespanPipe,
                        BsSecondsTodayOffsetPipe,
                        DateOffsetPipe,
                        DayOfWeekPipe,
                        ResourceGroupPresenterComponent
                    ],
                    imports: [
                        CommonModule,
                        BsIconModule,
                    ],
                    exports: [
                        BsSchedulerComponent,
                        ResourceGroupPresenterComponent
                    ]
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { BsSchedulerComponent, BsSchedulerModule, ESchedulerMode, ResourceGroupPresenterComponent, availableScales };
//# sourceMappingURL=mintplayer-ng-bootstrap-scheduler.mjs.map
