/* eslint-disable @typescript-eslint/no-non-null-assertion */
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);
};
// #region Imports
import { DomServiceLocator } from '../../../../Dom/Dom';
import { Listen } from '../../../../events/Decorators/ListenDecorator';
import { Component } from '../../..//Decorators/ComponentDecorator';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Boundable } from '../../../Behaviors/Boundable';
import { Disableable } from '../../../Behaviors/Disableable';
import { FilterableChild } from '../../../Behaviors/Filterable';
import { Focusable } from '../../../Behaviors/Focusable';
import { Localeable } from '../../../Behaviors/Localeable';
import { Valueable } from '../../../Behaviors/Valueable';
import { Variantable } from '../../../Behaviors/Variantable';
import { InlineStyleController } from '../../../Controllers/InlineStyleController';
import { KeyboardController } from '../../../Controllers/KeyboardController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { Key } from '../../../Types/Key';
import { CustomElement } from '../../Abstracts/CustomElement';
import { FocusRingElement } from '../../Primitives/FocusRing/FocusRingElement';
import { TextElement } from '../../Primitives/Text/TextElement';
import { epgProgramElementTemplate } from './EpgProgramElementTemplate';
import { epgProgramElementJoyStyle } from './Themes/EpgProgramElement.Joy';
// #endregion
/**
 * EPG Program - An individual program slot rendered within a channel row of an Electronic Program Guide.
 *
 * Represents a single broadcast program occupying a specific time range on a given channel lane.
 * The `lane` attribute places the program on the correct channel row; the `header` property
 * (set via JavaScript) provides the program title for display.
 *
 * @name EpgProgramElement
 * @element mosaik-epg-program
 * @category Selectors
 *
 * @slot - Default content area for program title text
 *
 * @csspart content - The content part.
 * @csspart focusRing - The focusRing part.
 * @csspart header - The header part.
 *
 * @cssprop {String} --epg-program-background-color - The program background color CSS custom property.
 * @cssprop {String} --epg-program-border-color - The program border color CSS custom property.
 * @cssprop {String} --epg-program-border-radius - The program border radius CSS custom property.
 * @cssprop {String} --epg-program-border-style - The program border style CSS custom property.
 * @cssprop {String} --epg-program-border-width - The program border width CSS custom property.
 * @cssprop {String} --epg-program-font-family - The program font family CSS custom property.
 * @cssprop {String} --epg-program-font-letter-spacing - The program font letter spacing CSS custom property.
 * @cssprop {String} --epg-program-font-line-height - The program font line height CSS custom property.
 * @cssprop {String} --epg-program-font-size - The program font size CSS custom property.
 * @cssprop {String} --epg-program-font-text-decoration - The program font text decoration CSS custom property.
 * @cssprop {String} --epg-program-font-text-transform - The program font text transform CSS custom property.
 * @cssprop {String} --epg-program-font-weight - The program font weight CSS custom property.
 * @cssprop {String} --epg-program-foreground-color - The program foreground color CSS custom property.
 * @cssprop {String} --epg-program-gap - The program gap CSS custom property.
 * @cssprop {String} --epg-program-padding-bottom - The program padding bottom CSS custom property.
 * @cssprop {String} --epg-program-padding-left - The program padding left CSS custom property.
 * @cssprop {String} --epg-program-padding-right - The program padding right CSS custom property.
 * @cssprop {String} --epg-program-padding-top - The program padding top CSS custom property.
 * @cssprop {String} --epg-program-shadow - The program shadow CSS custom property.
 * @cssprop {String} --epg-program-shadow-blur - The program shadow blur CSS custom property.
 * @cssprop {String} --epg-program-shadow-color - The program shadow color CSS custom property.
 * @cssprop {String} --epg-program-shadow-offset-x - The program shadow offset x CSS custom property.
 * @cssprop {String} --epg-program-shadow-offset-y - The program shadow offset y CSS custom property.
 * @cssprop {String} --epg-program-shadow-spread - The program shadow spread CSS custom property.
 * @cssprop {String} --epg-program-transition-duration - The program transition duration CSS custom property.
 * @cssprop {String} --epg-program-transition-mode - The program transition mode CSS custom property.
 * @cssprop {String} --epg-program-transition-property - The program transition property CSS custom property.
 * @cssprop {String} --epg-program-translate - The program translate CSS custom property.
 *
 * @dependency mosaik-focus-ring - The Focus Ring element.
 * @dependency mosaik-stack - The Stack element.
 * @dependency mosaik-text - The Text element.
 *
 * @example
 * ```html
 * <mosaik-epg-program lane="0" variant="primary">Morning News</mosaik-epg-program>
 *
 * <mosaik-epg-program lane="1" disabled>Off-air</mosaik-epg-program>
 * ```
 *
 * @public
 */
let EpgProgramElement = class EpgProgramElement extends FilterableChild(Localeable(Boundable(Variantable(Appearanceable(Disableable(Focusable(Valueable(CustomElement)))))))) {
    // #region Fields
    _keyboardController;
    _inlineStyleController;
    _boardElement;
    _header;
    _lane;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._boardElement = null;
        this._header = '';
        this._lane = 0;
        this._keyboardController = new KeyboardController(this);
        this._inlineStyleController = new InlineStyleController(this);
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     * The `is` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-epg-program';
    }
    /**
     * Gets or sets the `header` property.
     *
     * @public
     */
    get header() {
        return this._header;
    }
    set header(value) {
        if (this._header !== value) {
            this._header = value;
            this.requestUpdate('header');
        }
    }
    /**
     * Gets or sets the `lane` property.
     *
     * @public
     * @attr
     */
    get lane() { return this._lane; }
    set lane(value) {
        if (this._lane !== value) {
            this._lane = value;
            this.requestUpdate('lane');
        }
    }
    get root() {
        return this._boardElement;
    }
    /**
     * Gets the `displayText` property.
     *
     * @public
     * @readonly
     * @hidden
     */
    get displayText() {
        return this.textContent?.trim() ?? '';
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this._keyboardController
            .add([Key.Space, Key.Enter], (e) => {
            this.dispatchEvent(new CustomEvent('select', { detail: this }));
            e?.stopPropagation();
            e?.preventDefault();
        }, undefined, { preventDefault: true })
            .add([Key.UpArrow, Key.LeftArrow, Key.UpArrow, Key.DownArrow], (e) => {
            const all = Array.from(document.querySelectorAll('epg-program'));
            const idx = all.indexOf(this);
            let next = undefined;
            switch (e?.key ?? '') {
                case 'ArrowRight':
                    next = all[idx + 1];
                    break;
                case 'ArrowLeft':
                    next = all[idx - 1];
                    break;
                case 'ArrowDown':
                    next = all.find((el) => el !== this && Math.abs(el.getBoundingClientRect().top - this.getBoundingClientRect().top) > 60);
                    break;
                case 'ArrowUp':
                    next = [...all].reverse().find((el) => el !== this && Math.abs(el.getBoundingClientRect().top - this.getBoundingClientRect().top) > 60);
                    break;
                default:
                    next = undefined;
                    break;
            }
            if (next instanceof HTMLElement) {
                next.focus();
                e?.preventDefault();
            }
        }, undefined, { preventDefault: true });
    }
    /**
     * @protected
     * @override
     */
    onApplyTemplate() {
        super.onApplyTemplate();
        this._boardElement = DomServiceLocator.current.findAncestor(this, 'mosaik-epg', { strict: true });
        // this._boardElement.on('changed', (e) => {
        //     if (e.detail.propertyName === 'zoomMinutes') {
        //         this.setPosition();
        //     }
        // });
        this.calculatePosition();
    }
    onClick(_) {
        if (this.disabled) {
            return;
        }
        this.dispatchEvent(new CustomEvent('select', { detail: this }));
        // e.stopPropagation();
        // e.preventDefault();
    }
    /**
     * Calculates the program block position (left, width, top, height).
     *
     * @private
     */
    calculatePosition() {
        const board = this._boardElement;
        if (board) {
            const startMs = this.start.getTime() - board.start.getTime();
            const durationMs = this.end.getTime() - this.start.getTime();
            this._inlineStyleController.set('_since-ms', `${startMs}`);
            this._inlineStyleController.set('_duration-ms', `${durationMs}`);
            this._inlineStyleController.set('_lane', `${this.lane}`);
            this._inlineStyleController.set('epg-program-left', 'calc(var(--_since-ms) / var(--_ms-per-hour) * var(--_hour-width))');
            this._inlineStyleController.set('epg-program-width', 'calc(var(--_duration-ms) / var(--_ms-per-hour) * var(--_hour-width))');
            this._inlineStyleController.set('epg-program-top', 'calc(var(--_lane) * var(--_lane-height))');
            this._inlineStyleController.set('epg-program-height', 'var(--_lane-height)');
        }
        else {
            this._inlineStyleController.set('epg-program-left', '0');
            this._inlineStyleController.set('epg-program-width', '0');
            this._inlineStyleController.set('epg-program-top', '0');
            this._inlineStyleController.set('epg-program-height', '0');
        }
    }
};
__decorate([
    Property({
        type: String,
        isStyle: true
    }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], EpgProgramElement.prototype, "header", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], EpgProgramElement.prototype, "lane", null);
__decorate([
    Listen('click'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [MouseEvent]),
    __metadata("design:returntype", void 0)
], EpgProgramElement.prototype, "onClick", null);
EpgProgramElement = __decorate([
    Component({
        selector: 'mosaik-epg-program',
        template: epgProgramElementTemplate,
        styles: epgProgramElementJoyStyle,
        host: {
            role: 'button',
            tabIndex: '0'
        },
        imports: [
            FocusRingElement,
            TextElement
        ]
    }),
    __metadata("design:paramtypes", [])
], EpgProgramElement);
export { EpgProgramElement };
//# sourceMappingURL=EpgProgramElement.js.map