import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { Directive, Input, EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, Output, HostBinding, NgModule } from '@angular/core';
import { coerceNumberProperty, 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
 */
/**
 * Separator for the spltter component
 */
class SplitGutterDirective {
    /**
     * Constructor
     */
    constructor(elementRef, renderer) {
        this.elementRef = elementRef;
        this.renderer = renderer;
        this._disabled = false;
    }
    /**
     * Order of the seperator
     */
    set order(v) {
        this.setStyle('order', coerceNumberProperty(v));
    }
    /**
     * Direction of the separator
     * Can be `horizontal` or `vertical`
     */
    set direction(v) {
        this._direction = v;
        this.refreshStyle();
    }
    /**
     * Separator size in pixel
     */
    set size(v) {
        if (!v) {
            this.setStyle('flex-basis', '');
        }
        else if (typeof v === 'string') {
            this.setStyle('flex-basis', `${coerceNumberProperty(v)}px`);
        }
        else {
            this.setStyle('flex-basis', `${v}px`);
        }
    }
    /**
     * Disable the separator
     * By default `false`
     */
    set disabled(v) {
        this._disabled = coerceBooleanProperty(v);
        this.refreshStyle();
    }
    refreshStyle() {
        const state = this._disabled ? 'disabled' : this._direction;
        this.setStyle('cursor', this.getCursor(state));
        this.setStyle('background-image', `url("${this.getImage(state)}")`);
        // Add a content in css, to allow the gutter to take the full wize
        if (state === 'horizontal') {
            this.setStyle('content', ' ');
        }
    }
    setStyle(key, value) {
        void (value === null || value === undefined ? this.renderer.removeStyle(this.elementRef.nativeElement, key) : this.renderer.setStyle(this.elementRef.nativeElement, key, value));
    }
    getCursor(state) {
        switch (state) {
            case 'disabled':
                return 'default';
            case 'vertical':
                return 'row-resize';
            case 'horizontal':
                return 'col-resize';
            default:
                return null;
        }
    }
    getImage(state) {
        switch (state) {
            case 'disabled':
                return '';
            case 'vertical':
                return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFCAMAAABl/6zIAAAABlBMVEUAAADMzMzIT8AyAAAAAXRSTlMAQObYZgAAABRJREFUeAFjYGRkwIMJSeMHlBkOABP7AEGzSuPKAAAAAElFTkSuQmCC';
            case 'horizontal':
                // eslint-disable-next-line no-secrets/no-secrets
                return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==';
            default:
                return null;
        }
    }
}
SplitGutterDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: SplitGutterDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
SplitGutterDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: SplitGutterDirective, selector: "split-gutter", inputs: { order: "order", direction: "direction", size: "size", disabled: "disabled" }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: SplitGutterDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'split-gutter'
                }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { order: [{
                type: Input
            }], direction: [{
                type: Input
            }], size: [{
                type: Input
            }], disabled: [{
                type: Input
            }] } });

/*
 *  @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
 */
const gutterSize = 'gutterSize';
const disabled = 'disabled';
/**
 * Splitter Component for Angular
 *
 * The splitter component allows to split horizontally or vertically, a container in N resizable part.
 */
class DejaSplitterComponent {
    /**
     * Constructor
     */
    constructor(cdRef, elementRef, renderer) {
        this.cdRef = cdRef;
        this.elementRef = elementRef;
        this.renderer = renderer;
        /**
         * Direction of the split
         * Can be `horizontal` or `vertical`
         */
        this.direction = 'horizontal';
        /**
         * Separator width
         */
        this.gutterSize = 10;
        /**
         * Event triggered when the user start to drag the cursor
         */
        this.dragStart = new EventEmitter(false);
        /**
         * Event triggered during the cursor's drag
         */
        this.dragProgress = new EventEmitter(false);
        /**
         * Event triggered when the user stop to drag the cursor
         */
        this.dragEnd = new EventEmitter(false);
        this._areas = [];
        this.isDragging = false;
        this.containerSize = 0;
        this.areaAsize = 0;
        this.areaBsize = 0;
        this.eventsDragFct = [];
        this._disabled = false;
        console.warn('@deja-js/component/splitter is deprecated, and will be removed in a further version. Please use @deja-js/component/v2/splitter instead.');
    }
    /**
     * Host Binding
     */
    get styleFlexDirection() {
        return this.direction === 'horizontal' ? 'row' : 'column';
    }
    /**
     * Host Binding
     */
    get styleWidth() {
        return (this.width && !isNaN(this.width) && this.width > 0) ? `${this.width}px` : '100%';
    }
    /**
     * Host Binding
     */
    get styleHeight() {
        return (this.height && !isNaN(this.height) && this.height > 0) ? `${this.height}px` : '100%';
    }
    get nbGutters() {
        return this._areas.length - 1;
    }
    /** Retourne ou definit si le selecteur est desactivé. */
    set disabled(value) {
        this._disabled = coerceBooleanProperty(value) || null;
    }
    get disabled() {
        return this._disabled;
    }
    get areas() {
        return this._areas;
    }
    /**
     * Lifecycle hook that is called when any data-bound property of a directive changes.
     */
    ngOnChanges(changes) {
        if (changes[gutterSize] || changes[disabled]) {
            this.refresh();
        }
    }
    /**
     * Lifecycle hook that is called when a directive, pipe or service is destroyed.
     */
    ngOnDestroy() {
        this.stopDragging();
    }
    /**
     * Add a new area into the component
     * @param component Area to add
     * @param orderUser Position of the new area into the component
     * @param sizeUser Size of the new area
     * @param minPixel Min size of the new area
     */
    addArea(component, orderUser, sizeUser, minPixel) {
        this._areas.push({
            component,
            orderUser,
            order: -1,
            sizeUser,
            size: -1,
            minPixel
        });
        this.refresh();
    }
    /**
     * Update an existing area into the component
     * @param component Area to update
     * @param orderUser Position of the area into the component
     * @param sizeUser Size of the area
     * @param minPixel  Min size of the area
     */
    updateArea(component, orderUser, sizeUser, minPixel) {
        const item = this._areas.find(a => a.component === component);
        if (item) {
            item.orderUser = orderUser;
            item.sizeUser = sizeUser;
            item.minPixel = minPixel;
            this.refresh();
        }
    }
    /**
     * Delete an existing area into the component
     * @param area Area to delete
     */
    removeArea(area) {
        const item = this._areas.find(a => a.component === area);
        if (item) {
            const index = this._areas.indexOf(item);
            this._areas.splice(index, 1);
            this._areas.forEach((a, i) => a.order = i * 2);
            this.refresh();
        }
    }
    /**
     * Function called when the user start to drag the cursor
     * @param startEvent drag event
     * @param gutterOrder separator number
     */
    startDragging(event, gutterOrder) {
        const startEvent = event;
        startEvent.preventDefault();
        if (this.disabled) {
            return;
        }
        const areaA = this._areas.find(a => a.order === gutterOrder - 1);
        const areaB = this._areas.find(a => a.order === gutterOrder + 1);
        if (!areaA || !areaB) {
            return;
        }
        const prop = (this.direction === 'horizontal') ? 'offsetWidth' : 'offsetHeight';
        this.containerSize = this.elementRef.nativeElement[prop];
        this.areaAsize = this.containerSize * areaA.size / 100;
        this.areaBsize = this.containerSize * areaB.size / 100;
        const start = {
            x: startEvent.screenX,
            y: startEvent.screenY
        };
        this.eventsDragFct.push(this.renderer.listen('document', 'mousemove', (e) => this.dragEvent(e, start, areaA, areaB)));
        this.eventsDragFct.push(this.renderer.listen('document', 'touchmove', (e) => this.dragEvent(e, start, areaA, areaB)));
        this.eventsDragFct.push(this.renderer.listen('document', 'mouseup', () => this.stopDragging()));
        this.eventsDragFct.push(this.renderer.listen('document', 'touchend', () => this.stopDragging()));
        this.eventsDragFct.push(this.renderer.listen('document', 'touchcancel', () => this.stopDragging()));
        areaA.component.lockEvents();
        areaB.component.lockEvents();
        this.isDragging = true;
        this.notify('start');
    }
    refresh() {
        this.stopDragging();
        // ORDERS: Set css 'order' property depending on user input or added order
        const nbCorrectOrder = this._areas.filter(a => a.orderUser !== null && !isNaN(a.orderUser)).length;
        if (nbCorrectOrder === this._areas.length) {
            this._areas.sort((a, b) => +a.orderUser - +b.orderUser);
        }
        this._areas.forEach((a, i) => {
            a.order = i * 2;
            a.component.setStyle('order', a.order);
        });
        // SIZES: Set css 'flex-basis' property depending on user input or equal sizes
        const totalSize = this._areas.map(a => a.sizeUser).reduce((acc, s) => acc + s, 0);
        const toBeDefined = this._areas.filter(a => !a.sizeUser || isNaN(a.sizeUser));
        if ((totalSize < 99.99 || totalSize > 100.01) && this._areas.length > 1) {
            if (toBeDefined.length === 0) {
                // Map to 100%
                this._areas.forEach(a => {
                    const adjustedSize = Number(a.sizeUser) * 100 / totalSize;
                    a.size = adjustedSize;
                });
            }
            else if (totalSize < 99.99) {
                // Share the remaining size to the undefined areas
                let remain = (100 - totalSize);
                let toBeDefinedLength = toBeDefined.length;
                toBeDefined.forEach(a => {
                    const size = remain / toBeDefinedLength--;
                    a.size = size;
                    remain -= size;
                });
                this._areas
                    .filter(a => a.sizeUser && !isNaN(a.sizeUser))
                    .forEach(a => a.size = Number(a.sizeUser));
            }
            else {
                const size = Number((100 / this._areas.length).toFixed(3));
                this._areas.forEach(a => a.size = size);
            }
        }
        else if (totalSize === 0 && this._areas.length === 1) {
            this._areas[0].size = 100;
        }
        else {
            this._areas.forEach(a => a.size = Number(a.sizeUser));
        }
        this.refreshStyleSizes();
        this.cdRef.markForCheck();
    }
    refreshStyleSizes() {
        const f = this.gutterSize * this.nbGutters / this._areas.length;
        this._areas.forEach(a => a.component.setStyle('flex-basis', `calc( ${a.size}% - ${f}px )`));
    }
    dragEvent(event, start, areaA, areaB) {
        if (!this.isDragging) {
            return;
        }
        const end = {
            x: event.screenX,
            y: event.screenY
        };
        this.drag(start, end, areaA, areaB);
    }
    drag(start, end, areaA, areaB) {
        const offsetPixel = (this.direction === 'horizontal') ? (start.x - end.x) : (start.y - end.y);
        const newSizePixelA = this.areaAsize - offsetPixel;
        const newSizePixelB = this.areaBsize + offsetPixel;
        const minPercentA = areaA.minPixel ? (areaA.minPixel + 5) / this.containerSize * 100 : 0;
        const minPercentB = areaB.minPixel ? (areaB.minPixel + 5) / this.containerSize * 100 : 0;
        let newSizePercentA = newSizePixelA / this.containerSize * 100;
        let newSizePercentB = newSizePixelB / this.containerSize * 100;
        if (newSizePercentA <= minPercentA) {
            newSizePercentA = minPercentA;
            newSizePercentB = areaA.size + areaB.size - minPercentA;
        }
        else if (newSizePercentB <= minPercentB) {
            newSizePercentB = minPercentB;
            newSizePercentA = areaA.size + areaB.size - minPercentB;
        }
        else {
            newSizePercentA = Number(newSizePercentA.toFixed(3));
            newSizePercentB = Number((areaA.size + areaB.size - newSizePercentA).toFixed(3));
        }
        areaA.size = newSizePercentA;
        areaB.size = newSizePercentB;
        this.refreshStyleSizes();
        this.notify('progress');
    }
    stopDragging() {
        if (!this.isDragging) {
            return;
        }
        this._areas.forEach(a => a.component.unlockEvents());
        // eslint-disable-next-line no-loops/no-loops
        while (this.eventsDragFct.length > 0) {
            const fct = this.eventsDragFct.pop();
            if (fct) {
                fct();
            }
        }
        this.containerSize = 0;
        this.areaAsize = 0;
        this.areaBsize = 0;
        this.isDragging = false;
        this.notify('end');
    }
    notify(type) {
        const data = this._areas.map(a => a.size);
        switch (type) {
            case 'start':
                return this.dragStart.emit(data);
            case 'progress':
                return this.dragProgress.emit(data);
            case 'end':
                return this.dragEnd.emit(data);
            default:
                return null;
        }
    }
}
DejaSplitterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaSplitterComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
DejaSplitterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.3", type: DejaSplitterComponent, selector: "deja-splitter", inputs: { direction: "direction", width: "width", height: "height", gutterSize: "gutterSize", disabled: "disabled" }, outputs: { dragStart: "dragStart", dragProgress: "dragProgress", dragEnd: "dragEnd" }, host: { properties: { "style.flex-direction": "this.styleFlexDirection", "style.width": "this.styleWidth", "style.height": "this.styleHeight" } }, usesOnChanges: true, ngImport: i0, template: "<ng-content></ng-content>\n<ng-template ngFor let-area [ngForOf]=\"areas\" let-index=\"index\" let-last=\"last\">\n    <split-gutter *ngIf=\"last === false\"\n                  [order]=\"index*2+1\"\n                  [direction]=\"direction\"\n                  [size]=\"gutterSize\"\n                  [disabled]=\"disabled\"\n                  (mousedown)=\"startDragging($event, index*2+1)\"\n                  (touchstart)=\"startDragging($event, index*2+1)\">\n\n    </split-gutter>\n</ng-template>", styles: ["deja-splitter{display:flex;flex-wrap:nowrap;justify-content:flex-start}deja-splitter split-gutter{flex:0 0 10px;background-position:50%;background-repeat:no-repeat}deja-splitter split-area{flex-grow:0;flex-shrink:0;height:100%;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: SplitGutterDirective, selector: "split-gutter", inputs: ["order", "direction", "size", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaSplitterComponent, decorators: [{
            type: Component,
            args: [{ changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, selector: 'deja-splitter', template: "<ng-content></ng-content>\n<ng-template ngFor let-area [ngForOf]=\"areas\" let-index=\"index\" let-last=\"last\">\n    <split-gutter *ngIf=\"last === false\"\n                  [order]=\"index*2+1\"\n                  [direction]=\"direction\"\n                  [size]=\"gutterSize\"\n                  [disabled]=\"disabled\"\n                  (mousedown)=\"startDragging($event, index*2+1)\"\n                  (touchstart)=\"startDragging($event, index*2+1)\">\n\n    </split-gutter>\n</ng-template>", styles: ["deja-splitter{display:flex;flex-wrap:nowrap;justify-content:flex-start}deja-splitter split-gutter{flex:0 0 10px;background-position:50%;background-repeat:no-repeat}deja-splitter split-area{flex-grow:0;flex-shrink:0;height:100%;overflow:hidden}\n"] }]
        }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { direction: [{
                type: Input
            }], width: [{
                type: Input
            }], height: [{
                type: Input
            }], gutterSize: [{
                type: Input
            }], dragStart: [{
                type: Output
            }], dragProgress: [{
                type: Output
            }], dragEnd: [{
                type: Output
            }], styleFlexDirection: [{
                type: HostBinding,
                args: ['style.flex-direction']
            }], styleWidth: [{
                type: HostBinding,
                args: ['style.width']
            }], styleHeight: [{
                type: HostBinding,
                args: ['style.height']
            }], disabled: [{
                type: Input
            }] } });

/*
 *  @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
 */
/**
 * Directive representing a panel in a Splitter Component
 */
class SplitAreaDirective {
    /**
     * Constructor
     */
    constructor(elementRef, renderer, split) {
        this.elementRef = elementRef;
        this.renderer = renderer;
        this.split = split;
        this._order = null;
        this._size = null;
        this._minSizePixel = 0;
        this.eventsLockFct = [];
    }
    /**
     * Order position of the current area
     */
    set order(value) {
        const v = coerceNumberProperty(value);
        this._order = !isNaN(v) ? v : null;
        this.split.updateArea(this, this._order, this._size, this._minSizePixel);
    }
    /**
     * Size in percent of the current area
     */
    set size(value) {
        const v = coerceNumberProperty(value);
        this._size = !isNaN(v) ? v : null;
        this.split.updateArea(this, this._order, this._size, this._minSizePixel);
    }
    /**
     * Min size in percent of the current area
     */
    set minSizePixel(value) {
        const v = coerceNumberProperty(value);
        this._minSizePixel = (!isNaN(v) && v > 0) ? v : 0;
        this.split.updateArea(this, this._order, this._size, this._minSizePixel);
    }
    /**
     * Lifecycle hook that is called after data-bound properties of a directive are initialized.
     */
    ngOnInit() {
        this.split.addArea(this, this._order, this._size, this._minSizePixel);
    }
    /**
     * Lock the events
     */
    lockEvents() {
        this.eventsLockFct.push(this.renderer.listen(this.elementRef.nativeElement, 'selectstart', () => false));
        this.eventsLockFct.push(this.renderer.listen(this.elementRef.nativeElement, 'dragstart', () => false));
    }
    /**
     * Unlock the events
     */
    unlockEvents() {
        // eslint-disable-next-line no-loops/no-loops
        while (this.eventsLockFct.length > 0) {
            const fct = this.eventsLockFct.pop();
            if (fct) {
                fct();
            }
        }
    }
    /**
     * Set a style for the current area
     * @param key style key
     * @param value style value
     */
    setStyle(key, value) {
        void (value === null || value === undefined ? this.renderer.removeStyle(this.elementRef.nativeElement, key) : this.renderer.setStyle(this.elementRef.nativeElement, key, value));
    }
    /**
     * Lifecycle hook that is called when a directive, pipe or service is destroyed.
     */
    ngOnDestroy() {
        this.split.removeArea(this);
    }
}
SplitAreaDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: SplitAreaDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DejaSplitterComponent }], target: i0.ɵɵFactoryTarget.Directive });
SplitAreaDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.1.3", type: SplitAreaDirective, selector: "split-area", inputs: { order: "order", size: "size", minSizePixel: "minSizePixel" }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: SplitAreaDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'split-area'
                }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: DejaSplitterComponent }]; }, propDecorators: { order: [{
                type: Input
            }], size: [{
                type: Input
            }], minSizePixel: [{
                type: Input
            }] } });

/*
 *  @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 DejaSplitterModule {
}
DejaSplitterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaSplitterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
DejaSplitterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.1.3", ngImport: i0, type: DejaSplitterModule, declarations: [DejaSplitterComponent,
        SplitAreaDirective,
        SplitGutterDirective], imports: [CommonModule], exports: [DejaSplitterComponent,
        SplitAreaDirective,
        SplitGutterDirective] });
DejaSplitterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaSplitterModule, imports: [CommonModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.3", ngImport: i0, type: DejaSplitterModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        DejaSplitterComponent,
                        SplitAreaDirective,
                        SplitGutterDirective
                    ],
                    exports: [
                        DejaSplitterComponent,
                        SplitAreaDirective,
                        SplitGutterDirective
                    ],
                    imports: [
                        CommonModule
                    ]
                }]
        }] });

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

export { DejaSplitterComponent, DejaSplitterModule, SplitAreaDirective, SplitGutterDirective };
//# sourceMappingURL=deja-js-component-splitter.mjs.map
