// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var EpgElement_1;
import { Component } from '../../../Decorators/ComponentDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
import { epgElementTemplate } from './EpgElementTemplate';
import { epgElementJoyStyle } from './Themes/EpgElement.Joy';
import { EpgNowLineElement } from './EpgNowLineElement';
import { EpgMinimapElement } from './EpgMinimapElement';
import { Property } from '../../../Decorators/PropertyDecorator';
import { EpgChannelElement } from './EpgChannelElement';
import { EpgProgramElement } from './EpgProgramElement';
import { ToolbarElement } from '../../Grouping/Toolbar/ToolbarElement';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { DateBoxElement } from '../../Inputs/DateBox/DateBoxElement';
import { ButtonElement } from '../../Buttons/Button/ButtonElement';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Variantable } from '../../../Behaviors/Variantable';
import { getSlotElements } from '../../../../Dom/Slot';
import { EpgTimelineElement } from './EpgTimelineElement';
import { TextElement } from '../../Primitives/Text/TextElement';
import { Disableable } from '../../../Behaviors/Disableable';
import { Localeable } from '../../../Behaviors/Localeable';
import { Boundable } from '../../../Behaviors/Boundable';
import { Watch } from '../../../Decorators/WatchDecorator';
import { contains, Filterable, getMemberValue } from '../../../Behaviors/Filterable';
import { TextBoxElement } from '../../Inputs/TextBox/TextBoxElement';
// #endregion
/**
 * The `{@link EpgElement}` element.
 *
 * @public
 */
let EpgElement = class EpgElement extends Filterable(Boundable(Localeable(Appearanceable(Variantable(Disableable(CustomElement)))))) {
    static { EpgElement_1 = this; }
    // #region Fields
    static ZOOM_FACTORS = [15, 30, 60, 120];
    // @QuerySlotAll(EpgChannelElement.is)
    // private readonly _items!: Array<EpgChannelElement>;
    _timelineElement;
    _timer;
    // private readonly _didAutoScroll: boolean = false;
    _zoom;
    _visibleStart;
    _visibleEnd;
    _isNow;
    _showNowLine;
    _showMinimap;
    _timelineFormat;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this.start = new Date();
        this.end = new Date();
        this._zoom = 30;
        this._visibleStart = 0;
        this._visibleEnd = 10;
        this._isNow = false;
        this._showNowLine = false;
        this._showMinimap = false;
        this._timelineFormat = 'HH:mm';
    }
    // #endregion
    // #region Properties
    _dragStartX = 0;
    _scrollStartX = 0;
    /**
     * Returns the `{@link is}` property.
     * The `{@link is}` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-epg';
    }
    /**
     * Gets or sets the `zoom` property.
     *
     * @public
     * @attr
     */
    get zoom() {
        return this._zoom;
    }
    set zoom(value) {
        if (this._zoom !== value) {
            this._zoom = value;
            this.requestUpdate('zoom');
        }
    }
    /**
     * Gets or sets the `visibleStart` property.
     *
     * @public
     * @readonly
     */
    get visibleStart() {
        return this._visibleStart;
    }
    set visibleStart(value) {
        if (this._visibleStart !== value) {
            this._visibleStart = value;
            this.requestUpdate('visibleStart');
        }
    }
    /**
     * Gets or sets the `visibleEnd` property.
     *
     * @public
     * @readonly
     *
     */
    get visibleEnd() {
        return this._visibleEnd;
    }
    set visibleEnd(value) {
        if (this._visibleEnd !== value) {
            this._visibleEnd = value;
            this.requestUpdate('visibleEnd');
        }
    }
    /**
     * Gets or sets the `isNow` property.
     *
     * @public
     * @readonly
     */
    get isNow() {
        return this._isNow;
    }
    set isNow(value) {
        if (this._isNow !== value) {
            this._isNow = value;
            this.requestUpdate('isNow');
        }
    }
    /**
     * Gets or sets the `showNowLine` property.
     *
     * @public
     * @attr
     */
    get showNowLine() {
        return this._showNowLine;
    }
    set showNowLine(value) {
        if (this._showNowLine !== value) {
            this._showNowLine = value;
            this.requestUpdate('showNowLine');
        }
    }
    /**
     * Gets or sets the `showMinimap` property.
     *
     * @public
     * @attr
     */
    get showMinimap() {
        return this._showMinimap;
    }
    set showMinimap(value) {
        if (this._showMinimap !== value) {
            this._showMinimap = value;
            this.requestUpdate('showMinimap');
        }
    }
    /**
     * Gets or sets the `timelineFormat` property.
     *
     * @public
     * @attr
     */
    get timelineFormat() {
        return this._timelineFormat;
    }
    set timelineFormat(value) {
        if (this._timelineFormat !== value) {
            this._timelineFormat = value;
            this.requestUpdate('timelineFormat');
        }
    }
    /**
     * Gets or sets the `totalWidth` property.
     *
     * @public
     * @readonly
     */
    get totalWidth() {
        const totalMs = this.end.getTime() - this.start.getTime();
        return (totalMs / 60000) * this.zoom; // Minuten → Pixel über Zoom
    }
    /**
     * Returns the `items` property.
     *
     * @public
     * @readonly
     */
    get items() {
        return [
            ...getSlotElements(this.shadowRoot, undefined, EpgChannelElement),
            ...getSlotElements(this.shadowRoot, undefined, EpgProgramElement)
        ];
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this._timer = setInterval(() => this.requestUpdate(), 60000);
    }
    /**
     * @public
     * @override
     */
    disconnectedCallback() {
        clearInterval(this._timer);
        super.disconnectedCallback();
    }
    /**
     * @public
     */
    zoomIn() {
        const nextZoom = EpgElement_1.ZOOM_FACTORS.find((factor) => factor > this.zoom);
        this.zoom = nextZoom ?? EpgElement_1.ZOOM_FACTORS[EpgElement_1.ZOOM_FACTORS.length - 1];
    }
    /**
     * @public
     */
    zoomOut() {
        const nextZoom = [...EpgElement_1.ZOOM_FACTORS].reverse().find((factor) => factor < this.zoom);
        this.zoom = nextZoom ?? EpgElement_1.ZOOM_FACTORS[0];
    }
    /**
     * @public
     */
    nextDate() {
        const newStart = new Date(this.start.getTime() + (this.zoom * 60 * 1000));
        const newEnd = new Date(this.end.getTime() + (this.zoom * 60 * 1000));
        this.start = newStart;
        this.end = newEnd;
        this.requestUpdate();
    }
    /**
     * @public
     */
    previousDate() {
        const newStart = new Date(this.start.getTime() - (this.zoom * 60 * 1000));
        const newEnd = new Date(this.end.getTime() - (this.zoom * 60 * 1000));
        this.start = newStart;
        this.end = newEnd;
        this.requestUpdate();
    }
    /**
     * @internal
     */
    onScroll(event) {
        const target = event.target;
        const scrollLeft = target.scrollLeft;
        const scrollTop = target.scrollTop;
        const timeline = this.getTemplatePart('timeline');
        const channels = this.getTemplatePart('channels');
        timeline.scrollLeft = scrollLeft;
        channels.scrollTop = scrollTop;
    }
    updateNowButtonVisibility() {
        // const scroll = this.getTemplatePart('scroll');
        // const now = Date.now();
        // const totalMs = this.end.getTime() - this.start.getTime();
        // const rel = (now - this.start.getTime()) / totalMs;
        // const totalWidth = this._timelineElement.timeSlots.length * 60;
        // const nowX = rel * totalWidth;
        // const viewLeft = scroll.scrollLeft;
        // const viewRight = scroll.scrollLeft + scroll.clientWidth;
        // this.isNow = !(nowX < viewLeft - 60 || nowX > viewRight + 60);
    }
    scrollToNow(smooth = false) {
        // const scroll = this.getTemplatePart('scroll');
        // const now = Date.now();
        // const totalMs = this.end.getTime() - this.start.getTime();
        // const rel = (now - this.start.getTime()) / totalMs;
        // const totalWidth = this._timelineElement.timeSlots.length * 60;
        // scroll.scrollTo({
        //     left: rel * totalWidth - scroll.clientWidth / 2,
        //     behavior: smooth ? 'smooth' : 'auto'
        // });
    }
    onMinimapJump(e) {
        const scroll = this.getTemplatePart('scroll');
        scroll.scrollTop = e.detail * 80;
    }
    dragStart(e) {
        const scroll = this.getTemplatePart('scroll');
        this._dragStartX = e.clientX;
        this._scrollStartX = scroll.scrollLeft;
        const move = (evt) => {
            scroll.scrollLeft = this._scrollStartX - (evt.clientX - this._dragStartX);
        };
        const up = () => {
            window.removeEventListener('mousemove', move);
            window.removeEventListener('mouseup', up);
        };
        window.addEventListener('mousemove', move);
        window.addEventListener('mouseup', up);
    }
    touchStart(e) {
        const scroll = this.getTemplatePart('scroll');
        this._dragStartX = e.touches[0].clientX;
        this._scrollStartX = scroll.scrollLeft;
        const move = (evt) => {
            scroll.scrollLeft = this._scrollStartX - (evt.touches[0].clientX - this._dragStartX);
        };
        const end = () => {
            window.removeEventListener('touchmove', move);
            window.removeEventListener('touchend', end);
        };
        window.addEventListener('touchmove', move);
        window.addEventListener('touchend', end);
    }
    /**
     * @internal
     * @template
     */
    onSlotChange(event) {
        const slotName = event.target.name;
        const items = getSlotElements(this.shadowRoot, slotName);
        // set inherited properties
        items.forEach((x) => {
            x.locale = this.locale;
            x.disabled = this.disabled;
            x.variant = this.variant;
            x.appearance = this.appearance;
        });
    }
    /**
     * @protected
     * @override
     */
    onApplyTemplate() {
        super.onApplyTemplate();
        this._timelineElement = this.getTemplatePart('timeline');
    }
    /**
     * @protected
     */
    onFilterPropertyChanged(_, next) {
        const hasFilterCondition = (x, filter) => {
            const text = this.filterMemberPath
                ? this.filterMemberPath
                    ? String(getMemberValue(x, this.filterMemberPath))
                    : ''
                : x.displayText;
            return contains(text, filter, true);
        };
        if (next) {
            this.items
                .filter((x) => x instanceof EpgProgramElement)
                .forEach((x) => x.isFiltered = !hasFilterCondition(x, next));
        }
        else {
            this.items
                .filter((x) => x instanceof EpgProgramElement)
                .forEach((x) => x.isFiltered = false);
        }
    }
};
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], EpgElement.prototype, "zoom", null);
__decorate([
    Property({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], EpgElement.prototype, "visibleStart", null);
__decorate([
    Property({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], EpgElement.prototype, "visibleEnd", null);
__decorate([
    Property({ type: Boolean }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], EpgElement.prototype, "isNow", null);
__decorate([
    Attribute({ type: Boolean, useDefault: true }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], EpgElement.prototype, "showNowLine", null);
__decorate([
    Attribute({ type: Boolean, useDefault: true }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], EpgElement.prototype, "showMinimap", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], EpgElement.prototype, "timelineFormat", null);
__decorate([
    Watch('filter'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], EpgElement.prototype, "onFilterPropertyChanged", null);
EpgElement = EpgElement_1 = __decorate([
    Component({
        selector: 'mosaik-epg',
        template: epgElementTemplate,
        styles: epgElementJoyStyle,
        options: {
            mode: 'open',
            delegatesFocus: true
        },
        imports: [
            EpgNowLineElement,
            EpgMinimapElement,
            EpgChannelElement,
            EpgProgramElement,
            EpgTimelineElement,
            TextElement,
            ToolbarElement,
            DateBoxElement,
            ButtonElement,
            TextBoxElement
        ]
    }),
    __metadata("design:paramtypes", [])
], EpgElement);
export { EpgElement };
//# sourceMappingURL=EpgElement.js.map