import * as i0 from '@angular/core';
import { Directive, Optional, HostBinding, Input, NgModule } from '@angular/core';
import * as i1 from '@deja-js/component/core';
import { Destroy } from '@deja-js/component/core';
import { fromEvent, filter, switchMap, take, takeUntil, tap, mergeWith } from 'rxjs';
import { coerceBooleanProperty } from '@angular/cdk/coercion';

/*
 *  @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 DejaDraggableDirective extends Destroy {
    constructor(elementRef, clipboardService, idService) {
        super();
        this.clipboardService = clipboardService;
        this.draggable = null;
        this.draginfokey = 'draginfos';
        this.objectKey = 'object';
        this.elementKey = 'element';
        this.uuidKey = 'uuid';
        const element = elementRef.nativeElement;
        fromEvent(element, 'dragstart').pipe(filter(() => !!this.context), switchMap(event => {
            var _a, _b;
            if (!clipboardService) {
                throw new Error('To use the DejaDraggableDirective, please import and provide the DejaClipboardService in your application.');
            }
            // console.log('dragstart');
            const dragInfos = {};
            this.dragdropid = idService.generate();
            dragInfos[this.uuidKey] = this.dragdropid;
            const object = ((_a = this.context) === null || _a === void 0 ? void 0 : _a.object) || element;
            dragInfos[this.objectKey] = object;
            dragInfos[this.elementKey] = element;
            this.clipboardService.set(this.draginfokey, dragInfos);
            let data = 'notavailable';
            if (object) {
                // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
                object.dragged = true;
                data = JSON.stringify(data);
            }
            if ((_b = this.context) === null || _b === void 0 ? void 0 : _b.dragstartcallback) {
                const e = event;
                e.dragInfo = dragInfos;
                e.dragObject = this.context.object;
                e.dragElement = element;
                this.context.dragstartcallback(e);
                event.dataTransfer.setData('text/plain', data);
                if (e.defaultPrevented) {
                    event.preventDefault();
                }
            }
            return fromEvent(element, 'dragend').pipe(take(1));
        }), takeUntil(this.destroyed$)).subscribe(evt => {
            var _a;
            // console.log('dragend');
            const dragEndInfos = this.clipboardService.get(this.draginfokey);
            const obj = dragEndInfos === null || dragEndInfos === void 0 ? void 0 : dragEndInfos[this.objectKey];
            if (obj) {
                // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
                delete obj.dragged;
            }
            if (((_a = this.context) === null || _a === void 0 ? void 0 : _a.dragendcallback) && dragEndInfos) {
                const e = evt;
                e.dragInfo = dragEndInfos;
                e.dragObject = obj;
                e.dragElement = dragEndInfos[this.elementKey];
                this.context.dragendcallback(e);
                if (e.defaultPrevented) {
                    evt.stopPropagation();
                }
            }
            this.clipboardService.clear();
            this.dragdropid = undefined;
        });
    }
    set context(value) {
        this._context = value;
        this.draggable = !!value || null;
    }
    get context() {
        return this._context;
    }
}
DejaDraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDraggableDirective, deps: [{ token: i0.ElementRef }, { token: i1.DejaClipboardService, optional: true }, { token: i1.IdService }], target: i0.ɵɵFactoryTarget.Directive });
DejaDraggableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.1", type: DejaDraggableDirective, selector: "[deja-draggable]", inputs: { context: ["deja-draggable", "context"] }, host: { properties: { "attr.draggable": "this.draggable", "attr.dragdropid": "this.dragdropid" } }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDraggableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[deja-draggable]'
                }]
        }], ctorParameters: function () {
        return [{ type: i0.ElementRef }, { type: i1.DejaClipboardService, decorators: [{
                        type: Optional
                    }] }, { type: i1.IdService }];
    }, propDecorators: { draggable: [{
                type: HostBinding,
                args: ['attr.draggable']
            }], dragdropid: [{
                type: HostBinding,
                args: ['attr.dragdropid']
            }], context: [{
                type: Input,
                args: ['deja-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 DejaDroppableDirective extends Destroy {
    constructor(elementRef, clipboardService) {
        super();
        this.clipboardService = clipboardService;
        this.droppable = null;
        this.draginfokey = 'draginfos';
        this.objectKey = 'object';
        this.droppedKey = 'dropped';
        this.elementKey = 'element';
        this._allEvents = false;
        let inDrag = false;
        const element = elementRef.nativeElement;
        // DragEnter event
        const dragEnterEvent$ = fromEvent(element, 'dragenter').pipe(tap(() => {
            if (!clipboardService) {
                throw new Error('To use the DejaDroppableDirective, please import and provide the DejaClipboardService in your application.');
            }
        }), filter(() => !inDrag && !!this.context && !!this.context.dragentercallback && !!this.clipboardService.get(this.draginfokey)), tap(() => inDrag = true));
        // DragLeave event
        const dragLeaveEvent$ = fromEvent(element, 'dragleave').pipe(filter(() => inDrag && !!this.context && !!this.clipboardService.get(this.draginfokey)), filter(leaveEvent => {
            const bounds = element.getBoundingClientRect();
            const inside = leaveEvent.x >= bounds.left && leaveEvent.x <= bounds.right && leaveEvent.y >= bounds.top && leaveEvent.y <= bounds.bottom;
            return !inside;
        }));
        // Drop event
        const dropEvent$ = fromEvent(element, 'drop').pipe(filter(() => inDrag && !!this.context && !!this.clipboardService.get(this.draginfokey)));
        // DragOver event
        const dragOverEvent$ = fromEvent(element, 'dragover').pipe(filter(() => inDrag));
        const dragEndEvent$ = dragEnterEvent$.pipe(mergeWith(dragLeaveEvent$, dropEvent$), tap(() => inDrag = false));
        // DragEnter
        dragEnterEvent$.pipe(switchMap(dragEvent => {
            const dragInfos = this.clipboardService.get(this.draginfokey);
            const e = dragEvent;
            e.dragInfo = dragInfos;
            // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
            e.dragObject = dragEvent[this.objectKey];
            e.dragElement = element;
            // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
            e.itsMe = dragEvent[this.elementKey] === element;
            this.context.dragentercallback(e);
            if (e.defaultPrevented) {
                dragEvent.preventDefault();
                dragEvent.dataTransfer.dropEffect = 'copy';
            }
            else {
                dragEvent.dataTransfer.dropEffect = 'none';
            }
            const leave$ = dragLeaveEvent$.pipe(take(1), filter(() => !!this.context.dragleavecallback), tap(leaveEvent => {
                const le = new CustomEvent('DejaDragLeave', { cancelable: true });
                this.context.dragleavecallback(le);
                if (le.defaultPrevented) {
                    leaveEvent.preventDefault();
                }
            }));
            const drop$ = dropEvent$.pipe(take(1), filter(() => !!this.context.dropcallback), tap(dropEvent => {
                if (dragInfos) {
                    const evt = dropEvent;
                    evt.dragInfo = dragInfos;
                    evt.dragObject = dragInfos[this.objectKey];
                    evt.dragElement = element;
                    evt.itsMe = dragInfos[this.elementKey] === element;
                    this.context.dropcallback(evt);
                    if (evt.defaultPrevented) {
                        evt.dragInfo[this.droppedKey] = true;
                        dropEvent.preventDefault();
                        dragEvent.dataTransfer.dropEffect = 'copy';
                    }
                    else {
                        dragEvent.dataTransfer.dropEffect = 'none';
                    }
                }
            }));
            const over$ = dragOverEvent$.pipe(
            // eslint-disable-next-line rxjs/no-unsafe-takeuntil
            takeUntil(dragEndEvent$), tap(overEvent => {
                if (!this._allEvents && this.lastTarget && this.lastTarget === overEvent.target) {
                    if (this.lastAccept) {
                        overEvent.preventDefault();
                        dragEvent.dataTransfer.dropEffect = 'copy';
                    }
                    else {
                        dragEvent.dataTransfer.dropEffect = 'none';
                    }
                }
                else if (this.context.dragovercallback && dragInfos) {
                    const evt = overEvent;
                    evt.dragInfo = dragInfos;
                    evt.dragObject = dragInfos[this.objectKey];
                    evt.dragElement = element;
                    evt.itsMe = dragInfos[this.elementKey] === element;
                    this.context.dragovercallback(evt);
                    this.lastTarget = overEvent.target;
                    this.lastAccept = evt.defaultPrevented;
                    if (evt.defaultPrevented) {
                        overEvent.preventDefault();
                        dragEvent.dataTransfer.dropEffect = 'copy';
                    }
                    else {
                        dragEvent.dataTransfer.dropEffect = 'none';
                    }
                }
            }));
            return drop$.pipe(mergeWith(over$, leave$));
        }), takeUntil(this.destroyed$)).subscribe(_event => {
            // console.log(_event.type);
        });
    }
    /**
     * @deprecated
     */
    // eslint-disable-next-line @angular-eslint/no-input-rename
    set allEvents(value) {
        this._allEvents = coerceBooleanProperty(value);
    }
    set context(value) {
        this._context = value;
        this.droppable = !!value || null;
    }
    get context() {
        return this._context;
    }
}
DejaDroppableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDroppableDirective, deps: [{ token: i0.ElementRef }, { token: i1.DejaClipboardService, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
DejaDroppableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.1", type: DejaDroppableDirective, selector: "[deja-droppable]", inputs: { allEvents: ["continous-dragover", "allEvents"], context: ["deja-droppable", "context"] }, host: { properties: { "attr.droppable": "this.droppable" } }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDroppableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[deja-droppable]'
                }]
        }], ctorParameters: function () {
        return [{ type: i0.ElementRef }, { type: i1.DejaClipboardService, decorators: [{
                        type: Optional
                    }] }];
    }, propDecorators: { allEvents: [{
                type: Input,
                args: ['continous-dragover']
            }], droppable: [{
                type: HostBinding,
                args: ['attr.droppable']
            }], context: [{
                type: Input,
                args: ['deja-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 DejaDragDropModule {
}
DejaDragDropModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDragDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
DejaDragDropModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDragDropModule, declarations: [DejaDraggableDirective, DejaDroppableDirective], exports: [DejaDraggableDirective, DejaDroppableDirective] });
DejaDragDropModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDragDropModule });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: DejaDragDropModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [DejaDraggableDirective, DejaDroppableDirective],
                    exports: [DejaDraggableDirective, DejaDroppableDirective]
                }]
        }] });

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

export { DejaDragDropModule, DejaDraggableDirective, DejaDroppableDirective };
//# sourceMappingURL=deja-js-component-dragdrop.mjs.map
