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;
};
import { html, LitElement, nothing } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { createRef, ref } from 'lit/directives/ref.js';
import { startViewTransition } from '../../animations/player.js';
import { addThemingController } from '../../theming/theming-controller.js';
import IgcIconButtonComponent from '../button/icon-button.js';
import { tileManagerContext, } from '../common/context.js';
import { createAsyncContext } from '../common/controllers/async-consumer.js';
import { addDragController, } from '../common/controllers/drag.js';
import { addFullscreenController } from '../common/controllers/fullscreen.js';
import { addSlotController, setSlots } from '../common/controllers/slot.js';
import { registerComponent } from '../common/definitions/register.js';
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
import { partMap } from '../common/part-map.js';
import { asNumber, findElementFromEventPath, isLTR } from '../common/util.js';
import IgcDividerComponent from '../divider/divider.js';
import IgcResizeContainerComponent from '../resize-container/resize-container.js';
import { createTileDragStack, swapTiles } from './position.js';
import { createTileResizeState } from './resize-state.js';
import { styles as shared } from './themes/shared/tile/tile.common.css.js';
import { styles } from './themes/tile.base.css.js';
import { all } from './themes/tile.js';
import { createTileDragGhost, createTileGhost } from './tile-ghost-util.js';
let nextId = 1;
const Slots = setSlots('title', 'maximize-action', 'fullscreen-action', 'actions', 'side-adorner', 'corner-adorner', 'bottom-adorner');
class IgcTileComponent extends EventEmitterMixin(LitElement) {
    static register() {
        registerComponent(IgcTileComponent, IgcIconButtonComponent, IgcDividerComponent, IgcResizeContainerComponent);
    }
    get _tileManagerCtx() {
        return this._context.value;
    }
    get _tileManager() {
        return this._tileManagerCtx?.instance;
    }
    get _cssContainer() {
        return this._tileManagerCtx?.grid.value;
    }
    get _resizeMode() {
        return this._tileManager?.resizeMode ?? 'none';
    }
    get _resizeDisabled() {
        return (this.disableResize ||
            this.maximized ||
            this.fullscreen ||
            this._resizeMode === 'none');
    }
    set colSpan(value) {
        this._colSpan = Math.max(1, asNumber(value));
        this.style.setProperty('--ig-col-span', this._colSpan.toString());
    }
    get colSpan() {
        return this._colSpan;
    }
    set rowSpan(value) {
        this._rowSpan = Math.max(1, asNumber(value));
        this.style.setProperty('--ig-row-span', this._rowSpan.toString());
    }
    get rowSpan() {
        return this._rowSpan;
    }
    set colStart(value) {
        this._colStart = Math.max(0, asNumber(value)) || null;
        this.style.setProperty('--ig-col-start', this._colStart ? this._colStart.toString() : null);
    }
    get colStart() {
        return this._colStart;
    }
    set rowStart(value) {
        this._rowStart = Math.max(0, asNumber(value)) || null;
        this.style.setProperty('--ig-row-start', this._rowStart ? this._rowStart.toString() : null);
    }
    get rowStart() {
        return this._rowStart;
    }
    get fullscreen() {
        return this._fullscreenController.fullscreen;
    }
    set maximized(value) {
        this._maximized = value;
        if (this._tileManagerCtx) {
            this._tileManagerCtx.instance.requestUpdate();
        }
    }
    get maximized() {
        return this._maximized;
    }
    set position(value) {
        this._position = asNumber(value);
        this.style.order = this._position.toString();
    }
    get position() {
        return this._position;
    }
    constructor() {
        super();
        this._slots = addSlotController(this, { slots: Slots });
        this._dragController = addDragController(this, {
            skip: this._skipDrag,
            matchTarget: this._match,
            ghost: this._createDragGhost,
            start: this._handleDragStart,
            over: this._handleDragOver,
            end: this._handleDragEnd,
            cancel: this._handleDragCancel,
        });
        this._fullscreenController = addFullscreenController(this, {
            enter: this._emitFullScreenEvent,
            exit: this._emitFullScreenEvent,
        });
        this._resizeState = createTileResizeState();
        this._dragStack = createTileDragStack();
        this._colSpan = 1;
        this._rowSpan = 1;
        this._colStart = null;
        this._rowStart = null;
        this._position = -1;
        this._setDragConfiguration = ({ instance: { dragMode }, }) => {
            this._dragController.set({
                enabled: dragMode !== 'none',
                trigger: dragMode === 'tile-header' ? () => this._headerRef.value : undefined,
            });
        };
        this._context = createAsyncContext(this, tileManagerContext, this._setDragConfiguration);
        this._headerRef = createRef();
        this._maximized = false;
        this._isDragging = false;
        this._isResizing = false;
        this.disableResize = false;
        this.disableFullscreen = false;
        this.disableMaximize = false;
        this._createResizeGhost = () => {
            return createTileGhost(this);
        };
        addThemingController(this, all);
    }
    connectedCallback() {
        super.connectedCallback();
        this.id = this.id || `tile-${nextId++}`;
        this.style.viewTransitionName =
            this.style.viewTransitionName || `tile-transition-${this.id}`;
    }
    _setDragState(state = true) {
        this._isDragging = state;
        this._tileContent.style.opacity = state ? '0' : '';
        this.style.pointerEvents = state ? 'none' : '';
        this.part.toggle('dragging', state);
    }
    _handleDragStart() {
        if (!this._emitTileDragStart()) {
            return false;
        }
        this._setDragState();
        this._dragStack.push(this);
        return true;
    }
    _handleDragOver({ event, state }) {
        const match = state.element;
        if (this._dragStack.peek() === match) {
            if (this._shouldSwap(event, state, match)) {
                this._dragStack.pop();
                this._dragStack.push(match);
                this._performSwap(match);
            }
            return;
        }
        this._dragStack.push(match);
        this._performSwap(match);
    }
    _handleDragCancel() {
        startViewTransition(() => {
            this._dragStack.restore();
            this._dragStack.reset();
        });
        this._dragController.dispose();
        this._setDragState(false);
        this.emitEvent('igcTileDragCancel', { detail: this });
    }
    _handleDragEnd() {
        this._setDragState(false);
        this._dragStack.reset();
        this.emitEvent('igcTileDragEnd', { detail: this });
    }
    _performSwap(match) {
        startViewTransition(() => swapTiles(this, match));
    }
    _shouldSwap({ clientX, clientY }, state, match) {
        const LTR = isLTR(this);
        const direction = state.pointerState.direction;
        const { left, top, width, height } = match.getBoundingClientRect();
        const relativeX = (clientX - left) / width;
        const relativeY = (clientY - top) / height;
        switch (direction) {
            case 'start':
                return (this.position > match.position &&
                    (LTR ? relativeX <= 0.25 : relativeX >= 0.75));
            case 'end':
                return (this.position < match.position &&
                    (LTR ? relativeX >= 0.75 : relativeX <= 0.25));
            case 'top':
                return this.position > match.position && relativeY <= 0.25;
            case 'bottom':
                return this.position < match.position && relativeY >= 0.75;
            default:
                return false;
        }
    }
    _skipDrag(event) {
        if (this._maximized || this.fullscreen) {
            return true;
        }
        return Boolean(findElementFromEventPath((e) => e.matches('[part*=trigger]') || e.matches('#tile-actions'), event));
    }
    _match(element) {
        return element !== this && IgcTileComponent.tagName === element.localName;
    }
    _createDragGhost() {
        return createTileDragGhost(this);
    }
    _setResizeState(state = true) {
        this._isResizing = state;
        this.style.zIndex = state ? '1' : '';
        this.part.toggle('resizing', state);
    }
    _handleResizeStart(event) {
        if (!this._emitTileResizeStart()) {
            event.preventDefault();
            return;
        }
        this._resizeState.updateState(event.detail.state.initial, this, this._cssContainer);
        this._setResizeState();
    }
    _handleResize({ detail: { state }, }) {
        const trigger = state.trigger;
        const isWidthResize = trigger.matches('[part*="side"], [part="trigger"]');
        const isHeightResize = trigger.matches('[part*="bottom"], [part="trigger"]');
        if (isWidthResize) {
            state.current.width = this._resizeState.calculateSnappedWidth(state);
        }
        if (isHeightResize) {
            state.current.height = this._resizeState.calculateSnappedHeight(state);
        }
    }
    _handleResizeEnd({ detail: { state }, }) {
        const { colSpan, rowSpan } = this._resizeState.calculateResizedGridPosition(state.current);
        state.commit = async () => {
            await startViewTransition(() => {
                this.colSpan = colSpan;
                this.rowSpan = rowSpan;
            }).transition?.updateCallbackDone;
            this._setResizeState(false);
            this.emitEvent('igcTileResizeEnd', { detail: this });
        };
    }
    _handleResizeCancel() {
        this._setResizeState(false);
        this.emitEvent('igcTileResizeCancel', { detail: this });
    }
    _handleFullscreen() {
        this._fullscreenController.setState(!this.fullscreen);
    }
    async _handleMaximize() {
        if (!this._emitMaximizedEvent()) {
            return;
        }
        this.style.zIndex = '1';
        await startViewTransition(() => {
            this.maximized = !this.maximized;
        }).transition?.finished;
        this.style.zIndex = '';
    }
    _emitFullScreenEvent(state) {
        this.requestUpdate();
        return this.emitEvent('igcTileFullscreen', {
            detail: { tile: this, state },
            cancelable: true,
        });
    }
    _emitMaximizedEvent() {
        return this.emitEvent('igcTileMaximize', {
            detail: { tile: this, state: !this.maximized },
            cancelable: true,
        });
    }
    _emitTileDragStart() {
        return this.emitEvent('igcTileDragStart', {
            detail: this,
            cancelable: true,
        });
    }
    _emitTileResizeStart() {
        return this.emitEvent('igcTileResizeStart', {
            detail: this,
            cancelable: true,
        });
    }
    _renderDefaultAction(type) {
        const [icon, listener] = type === 'fullscreen'
            ? [
                this.fullscreen ? 'fullscreen_exit' : 'fullscreen',
                this._handleFullscreen,
            ]
            : [
                this._maximized ? 'collapse_content' : 'expand_content',
                this._handleMaximize,
            ];
        return html `
      <igc-icon-button
        variant="flat"
        collection="default"
        exportparts="icon"
        name=${icon}
        aria-label=${icon}
        @click=${listener}
      ></igc-icon-button>
    `;
    }
    _renderHeader() {
        const hasNoContent = !(this._slots.hasAssignedElements('title') &&
            this._slots.hasAssignedElements('actions'));
        const hideHeader = hasNoContent && this.disableMaximize && this.disableFullscreen;
        const hasMaximizeSlot = !(this.disableMaximize || this.fullscreen);
        const hasFullscreenSlot = !this.disableFullscreen;
        return html `
      <section part="header" ?hidden=${hideHeader} ${ref(this._headerRef)}>
        <header part="title">
          <slot name="title"></slot>
        </header>
        <section id="tile-actions" part="actions">
          ${hasMaximizeSlot
            ? html `
                <slot name="maximize-action">
                  ${this._renderDefaultAction('maximize')}
                </slot>
              `
            : nothing}
          ${hasFullscreenSlot
            ? html `
                <slot name="fullscreen-action">
                  ${this._renderDefaultAction('fullscreen')}
                </slot>
              `
            : nothing}

          <slot name="actions"></slot>
        </section>
      </section>
      <igc-divider></igc-divider>
    `;
    }
    _renderContent() {
        const parts = {
            base: true,
            draggable: this._tileManager?.dragMode !== 'none',
            fullscreen: this.fullscreen,
            dragging: this._isDragging,
            resizable: !this.disableResize && this._tileManager?.resizeMode !== 'none',
            resizing: this._isResizing,
            maximized: this.maximized,
        };
        return html `
      <div part=${partMap(parts)}>
        ${this._renderHeader()}
        <div part="content-container">
          <slot></slot>
        </div>
      </div>
    `;
    }
    _renderAdornerSlot(name) {
        return html `<slot name="${name}-adorner" slot="${name}-adorner"></slot>`;
    }
    render() {
        const isActive = this._resizeMode === 'always';
        return this._resizeDisabled
            ? this._renderContent()
            : html `
          <igc-resize
            part=${partMap({
                resize: true,
                'side-adorner': this._slots.hasAssignedElements('side-adorner'),
                'corner-adorner': this._slots.hasAssignedElements('corner-adorner'),
                'bottom-adorner': this._slots.hasAssignedElements('bottom-adorner'),
            })}
            exportparts="trigger-side, trigger, trigger-bottom"
            mode="deferred"
            ?active=${isActive}
            .ghostFactory=${this._createResizeGhost}
            @igcResizeStart=${this._handleResizeStart}
            @igcResize=${this._handleResize}
            @igcResizeEnd=${this._handleResizeEnd}
            @igcResizeCancel=${this._handleResizeCancel}
          >
            ${this._renderContent()} ${this._renderAdornerSlot('side')}
            ${this._renderAdornerSlot('corner')}
            ${this._renderAdornerSlot('bottom')}
          </igc-resize>
        `;
    }
}
IgcTileComponent.tagName = 'igc-tile';
IgcTileComponent.styles = [styles, shared];
export default IgcTileComponent;
__decorate([
    query(IgcResizeContainerComponent.tagName)
], IgcTileComponent.prototype, "_resizeContainer", void 0);
__decorate([
    query('[part~="base"]', true)
], IgcTileComponent.prototype, "_tileContent", void 0);
__decorate([
    state()
], IgcTileComponent.prototype, "_maximized", void 0);
__decorate([
    state()
], IgcTileComponent.prototype, "_isDragging", void 0);
__decorate([
    state()
], IgcTileComponent.prototype, "_isResizing", void 0);
__decorate([
    property({ type: Number, attribute: 'col-span' })
], IgcTileComponent.prototype, "colSpan", null);
__decorate([
    property({ type: Number, attribute: 'row-span' })
], IgcTileComponent.prototype, "rowSpan", null);
__decorate([
    property({ type: Number, attribute: 'col-start' })
], IgcTileComponent.prototype, "colStart", null);
__decorate([
    property({ type: Number, attribute: 'row-start' })
], IgcTileComponent.prototype, "rowStart", null);
__decorate([
    property({ type: Boolean, reflect: true })
], IgcTileComponent.prototype, "maximized", null);
__decorate([
    property({ type: Boolean, reflect: true, attribute: 'disable-resize' })
], IgcTileComponent.prototype, "disableResize", void 0);
__decorate([
    property({ type: Boolean, reflect: true, attribute: 'disable-fullscreen' })
], IgcTileComponent.prototype, "disableFullscreen", void 0);
__decorate([
    property({ type: Boolean, reflect: true, attribute: 'disable-maximize' })
], IgcTileComponent.prototype, "disableMaximize", void 0);
__decorate([
    property({ type: Number })
], IgcTileComponent.prototype, "position", null);
//# sourceMappingURL=tile.js.map