import * as i0 from '@angular/core';
import { Injectable, Component, ViewEncapsulation, ViewChild, Directive, Input, NgModule } from '@angular/core';
import * as i2 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import { Destroy } from '@deja-js/component/core';
import { BehaviorSubject, tap, filter, takeUntil, delay, combineLatestWith, fromEvent, switchMap, of, isObservable, take, map, Subject, mergeWith, distinctUntilChanged } from 'rxjs';
import { Rect, Position } from '@deja-js/component/core/graphics';

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class MouseDragDropService extends Destroy {
    constructor() {
        super();
        this.dragCursor$ = new BehaviorSubject(null);
        this.dropCursor$ = new BehaviorSubject(null);
        this.dragging$ = new BehaviorSubject(false);
        this._isDragging = false;
        this.dragging$.pipe(tap(value => this._isDragging = value), filter(value => !value), takeUntil(this.destroyed$)).subscribe(() => this.context = undefined);
    }
    get isDragging() {
        return this._isDragging;
    }
}
MouseDragDropService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
MouseDragDropService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: function () { return []; } });

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class MouseDragDropCursorComponent extends Destroy {
    constructor(elementRef, dragDropService) {
        super();
        this.elementRef = elementRef;
        this.dragDropService = dragDropService;
        this.cursor$ = new BehaviorSubject(null);
        // Hide
        this.cursor$.pipe(filter(cursor => !cursor), tap(cursor => {
            if (this.currentCursor) {
                if (this.contentElement) {
                    this.contentElement.style.opacity = '0';
                }
                if (this.iconElement) {
                    this.iconElement.style.opacity = '0';
                }
            }
            this.currentCursor = cursor;
        }), delay(300), takeUntil(this.destroyed$)).subscribe(() => {
            this.position = undefined;
        });
        // Show
        this.cursor$.pipe(filter(cursor => !!cursor), tap(cursor => {
            elementRef.nativeElement.style.display = '';
            if (this.contentElement) {
                this.contentElement.style.opacity = '0';
            }
            if (this.iconElement) {
                this.iconElement.style.opacity = '0';
            }
            this.currentCursor = cursor;
        }), filter(cursor => !cursor.className || cursor.className !== 'hidden'), tap(cursor => {
            if (cursor.html) {
                elementRef.nativeElement.className = cursor.className;
                if (this.contentElement) {
                    this.contentElement.innerHTML = cursor.html;
                    this.contentElement.style.width = `${cursor.width || 48}px`;
                    this.contentElement.style.height = `${cursor.height || 48}px`;
                }
            }
            else if (this.iconElement) {
                this.iconElement.style.opacity = '1';
            }
        }), delay(1), takeUntil(this.destroyed$)).subscribe(cursor => {
            if (!!cursor.html && this.contentElement) {
                this.contentElement.style.opacity = '1';
            }
        });
        this.dragDropService.dragCursor$.pipe(combineLatestWith(this.dragDropService.dropCursor$), takeUntil(this.destroyed$)).subscribe(([dragCursor, dropCursor]) => {
            var _a, _b, _c, _d;
            const cursor = (dragCursor || dropCursor) && {
                className: (dropCursor === null || dropCursor === void 0 ? void 0 : dropCursor.className) || (dragCursor === null || dragCursor === void 0 ? void 0 : dragCursor.className),
                html: (dropCursor === null || dropCursor === void 0 ? void 0 : dropCursor.html) || (dragCursor === null || dragCursor === void 0 ? void 0 : dragCursor.html) || (dropCursor && (dragCursor === null || dragCursor === void 0 ? void 0 : dragCursor.originalHtml)),
                width: (dropCursor === null || dropCursor === void 0 ? void 0 : dropCursor.width) || (dragCursor === null || dragCursor === void 0 ? void 0 : dragCursor.width),
                height: (dropCursor === null || dropCursor === void 0 ? void 0 : dropCursor.height) || (dragCursor === null || dragCursor === void 0 ? void 0 : dragCursor.height),
                position: dragCursor === null || dragCursor === void 0 ? void 0 : dragCursor.position,
                originalEvent: dragCursor === null || dragCursor === void 0 ? void 0 : dragCursor.originalEvent
            };
            if ((cursor === null || cursor === void 0 ? void 0 : cursor.html) !== ((_a = this.currentCursor) === null || _a === void 0 ? void 0 : _a.html) || (cursor === null || cursor === void 0 ? void 0 : cursor.className) !== ((_b = this.currentCursor) === null || _b === void 0 ? void 0 : _b.className) || (cursor === null || cursor === void 0 ? void 0 : cursor.width) !== ((_c = this.currentCursor) === null || _c === void 0 ? void 0 : _c.width) || (cursor === null || cursor === void 0 ? void 0 : cursor.height) !== ((_d = this.currentCursor) === null || _d === void 0 ? void 0 : _d.height)) {
                // Update Content
                this.cursor$.next(cursor);
            }
            else {
                // Update only Position
                this.position = cursor === null || cursor === void 0 ? void 0 : cursor.position;
            }
        });
    }
    set position(value) {
        if (value) {
            this.elementRef.nativeElement.style.left = `${value.left}px`;
            this.elementRef.nativeElement.style.top = `${value.top}px`;
            this.elementRef.nativeElement.style.display = '';
        }
        else {
            this.elementRef.nativeElement.style.display = 'none';
        }
    }
    get iconElement() {
        var _a;
        return (_a = this.icon) === null || _a === void 0 ? void 0 : _a.nativeElement;
    }
    get contentElement() {
        var _a;
        return (_a = this.content) === null || _a === void 0 ? void 0 : _a.nativeElement;
    }
}
MouseDragDropCursorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropCursorComponent, deps: [{ token: i0.ElementRef }, { token: MouseDragDropService }], target: i0.ɵɵFactoryTarget.Component });
MouseDragDropCursorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: MouseDragDropCursorComponent, selector: "mouse-dragdrop-cursor", viewQueries: [{ propertyName: "icon", first: true, predicate: ["block"], descendants: true, static: true }, { propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div id=\"block\" #block>\n    <mat-icon #block>block</mat-icon>\n</div>\n<div #content id=\"content\"></div>\n", styles: ["mouse-dragdrop-cursor{position:fixed;width:0;height:0;overflow:visible;z-index:10000;user-select:none;display:flex;align-items:center;justify-content:space-around}mouse-dragdrop-cursor #block{position:absolute;top:0;left:0;width:3rem;height:3rem;display:flex;align-items:center;justify-content:space-around;transform:translate(-50%,-50%);transition-property:opacity;transition-timing-function:linear;transition-duration:.3s;cursor:default}mouse-dragdrop-cursor #content{position:absolute;top:0;left:0;transform:translate(-50%,-50%);transition-property:opacity;transition-timing-function:linear;transition-duration:.3s;cursor:default}\n"], dependencies: [{ kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], encapsulation: i0.ViewEncapsulation.None });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropCursorComponent, decorators: [{
            type: Component,
            args: [{ encapsulation: ViewEncapsulation.None, selector: 'mouse-dragdrop-cursor', template: "<div id=\"block\" #block>\n    <mat-icon #block>block</mat-icon>\n</div>\n<div #content id=\"content\"></div>\n", styles: ["mouse-dragdrop-cursor{position:fixed;width:0;height:0;overflow:visible;z-index:10000;user-select:none;display:flex;align-items:center;justify-content:space-around}mouse-dragdrop-cursor #block{position:absolute;top:0;left:0;width:3rem;height:3rem;display:flex;align-items:center;justify-content:space-around;transform:translate(-50%,-50%);transition-property:opacity;transition-timing-function:linear;transition-duration:.3s;cursor:default}mouse-dragdrop-cursor #content{position:absolute;top:0;left:0;transform:translate(-50%,-50%);transition-property:opacity;transition-timing-function:linear;transition-duration:.3s;cursor:default}\n"] }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: MouseDragDropService }]; }, propDecorators: { icon: [{
                type: ViewChild,
                args: ['block', { static: true }]
            }], content: [{
                type: ViewChild,
                args: ['content', { static: true }]
            }] } });

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class MouseDraggableDirective extends Destroy {
    constructor(elementRef, dragDropService) {
        super();
        const element = elementRef.nativeElement;
        const mouseLeaveEvent$ = fromEvent(element, 'mouseleave');
        const mouseEnterEvent$ = fromEvent(element, 'mouseenter');
        const mouseUpEvent$ = fromEvent(element.ownerDocument, 'mouseup');
        const mouseDownEvent$ = fromEvent(element, 'mousedown');
        const mouseMoveEvent$ = fromEvent(element.ownerDocument, 'mousemove');
        mouseEnterEvent$.pipe(filter(() => !dragDropService.isDragging), switchMap(() => mouseDownEvent$.pipe(filter(event => event.buttons === 1), 
        // eslint-disable-next-line rxjs/no-unsafe-takeuntil
        takeUntil(mouseLeaveEvent$), switchMap(mouseDownEvent => {
            const match = (el) => el.tagName === this.context.target.toUpperCase() || `#${el.id}` === this.context.target || el.hasAttribute(this.context.target.substring(1, this.context.target.length - 1)) || el.className.split(' ').some(className => `.${className}` === this.context.target);
            let target$ = of(null);
            if (this.context) {
                let target;
                if (this.context.target) {
                    target = mouseDownEvent.target;
                    // eslint-disable-next-line no-loops/no-loops
                    while (target && !match(target)) {
                        target = target.parentElement;
                    }
                }
                else {
                    target = element;
                }
                if (target && this.context.dragStart) {
                    const dragContext = this.context.dragStart(target);
                    if (dragContext) {
                        if (isObservable(dragContext)) {
                            const dragContext$ = dragContext;
                            // Observable
                            target$ = dragContext$.pipe(take(1), map(context => {
                                dragDropService.context = context;
                                return context && target; // Map to target if ddctx is defined
                            }));
                        }
                        else {
                            dragDropService.context = dragContext;
                            target$ = of(target);
                        }
                    }
                }
            }
            return target$.pipe(filter(target => !!target), // Start Drag if target is defined
            switchMap(target => {
                dragDropService.dragging$.next(true);
                const moveUp$ = new Subject();
                const enterWhileNotDragDropEvent$ = mouseEnterEvent$.pipe(filter(event => event.buttons !== 1 && dragDropService.isDragging));
                const kill$ = mouseUpEvent$.pipe(mergeWith(enterWhileNotDragDropEvent$, moveUp$), take(1), tap(() => {
                    dragDropService.dragCursor$.next(null);
                    dragDropService.dragging$.next(false);
                }));
                return mouseMoveEvent$.pipe(
                // eslint-disable-next-line rxjs/no-unsafe-takeuntil
                takeUntil(kill$), tap(mouseMoveEvent => {
                    if (target && mouseMoveEvent.buttons === 1) {
                        const bounds = new Rect(element.getBoundingClientRect());
                        const position = new Position(mouseMoveEvent.pageX, mouseMoveEvent.pageY);
                        const html = bounds.containsPoint(position) ? target.innerHTML : undefined;
                        const padding = 5;
                        let deadBounds = new Rect(mouseDownEvent.pageX, mouseDownEvent.pageY, padding * 2, padding * 2);
                        deadBounds = deadBounds.offset(-padding, -padding);
                        if (!deadBounds.containsPoint(position)) {
                            // Post cursor infos to service
                            dragDropService.dragCursor$.next({
                                position: position,
                                html: html,
                                originalHtml: target.innerHTML,
                                width: target.offsetWidth,
                                height: target.offsetHeight,
                                className: this.context.className,
                                originalEvent: mouseMoveEvent
                            });
                        }
                    }
                    else {
                        moveUp$.next();
                    }
                    // ev.preventDefault();
                    return false;
                }));
            }));
        }))), takeUntil(this.destroyed$)).subscribe();
    }
    set context(value) {
        this._context = value;
    }
    get context() {
        return this._context;
    }
}
MouseDraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDraggableDirective, deps: [{ token: i0.ElementRef }, { token: MouseDragDropService }], target: i0.ɵɵFactoryTarget.Directive });
MouseDraggableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.1", type: MouseDraggableDirective, selector: "[mouse-draggable]", inputs: { context: ["mouse-draggable", "context"] }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDraggableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[mouse-draggable]'
                }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: MouseDragDropService }]; }, propDecorators: { context: [{
                type: Input,
                args: ['mouse-draggable']
            }] } });

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class MouseDroppableDirective extends Destroy {
    constructor(elementRef, dragDropService) {
        super();
        const element = elementRef.nativeElement;
        let dragContext;
        const dragging$ = dragDropService.dragging$.pipe(distinctUntilChanged());
        const drop$ = dragDropService.dragCursor$.pipe(filter(value => !!value), switchMap(dragCursor => dragging$.pipe(filter(value => !value), take(1), tap(() => {
            var _a;
            // console.log(`Drop ${!!this._dragContext}`)
            if (dragContext && ((_a = this.context) === null || _a === void 0 ? void 0 : _a.drop)) {
                this.context.drop(dragContext, dragCursor);
            }
            dragContext = undefined;
            dragDropService.dropCursor$.next(null);
        }))));
        dragging$.pipe(filter(value => value), switchMap(() => 
        // console.log(`Drag ${!!this._dragContext}`)
        dragDropService.dragCursor$.pipe(
        // eslint-disable-next-line rxjs/no-unsafe-takeuntil
        takeUntil(drop$), switchMap(dragCursor => {
            var _a;
            const bounds = new Rect(element.getBoundingClientRect());
            if (this.context && dragCursor) {
                const { pageX, pageY } = dragCursor.originalEvent;
                if (bounds.containsPoint(new Position(pageX, pageY))) {
                    if (!dragContext) {
                        dragContext = dragDropService.context;
                        if (this.context.dragEnter) {
                            const dropCursor$ = this.context.dragEnter(dragContext, dragCursor);
                            if (dropCursor$) {
                                const dropCursorObs$ = dropCursor$;
                                if (dropCursorObs$.subscribe) {
                                    // Observable
                                    return dropCursorObs$;
                                }
                                else {
                                    return of(dropCursor$);
                                }
                            }
                        }
                    }
                    else if (this.context.dragOver) {
                        const dropCursor = this.context.dragOver(dragContext, dragCursor);
                        if (dropCursor) {
                            return of(dropCursor);
                        }
                    }
                }
                else if (dragContext) {
                    if ((_a = this.context) === null || _a === void 0 ? void 0 : _a.dragLeave) {
                        this.context.dragLeave(dragContext);
                    }
                    dragContext = undefined;
                    dragDropService.dropCursor$.next(null);
                }
            }
            return of(null);
        }))), filter(dropCursor => !!dropCursor), takeUntil(this.destroyed$)).subscribe(dropCursor => dragDropService.dropCursor$.next(dropCursor));
    }
    set context(value) {
        this._context = value;
    }
    get context() {
        return this._context;
    }
}
MouseDroppableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDroppableDirective, deps: [{ token: i0.ElementRef }, { token: MouseDragDropService }], target: i0.ɵɵFactoryTarget.Directive });
MouseDroppableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.1", type: MouseDroppableDirective, selector: "[mouse-droppable]", inputs: { context: ["mouse-droppable", "context"] }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDroppableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[mouse-droppable]'
                }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: MouseDragDropService }]; }, propDecorators: { context: [{
                type: Input,
                args: ['mouse-droppable']
            }] } });

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class MouseDragDropModule {
}
MouseDragDropModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
MouseDragDropModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropModule, declarations: [MouseDragDropCursorComponent,
        MouseDraggableDirective,
        MouseDroppableDirective], imports: [MatIconModule], exports: [MouseDragDropCursorComponent,
        MouseDraggableDirective,
        MouseDroppableDirective] });
MouseDragDropModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropModule, imports: [MatIconModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: MouseDragDropModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        MouseDragDropCursorComponent,
                        MouseDraggableDirective,
                        MouseDroppableDirective
                    ],
                    imports: [
                        MatIconModule
                    ],
                    exports: [
                        MouseDragDropCursorComponent,
                        MouseDraggableDirective,
                        MouseDroppableDirective
                    ]
                }]
        }] });

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

export { MouseDragDropCursorComponent, MouseDragDropModule, MouseDragDropService, MouseDraggableDirective, MouseDroppableDirective };
//# sourceMappingURL=deja-js-component-v2-mouse-dragdrop.mjs.map
