import { BehaviorSubject, merge } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { DataSource } from '@angular/cdk/collections';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { CdkTreeNode, CdkTree, CdkTreeNodeDef, CdkNestedTreeNode, CDK_TREE_NODE_OUTLET_NODE, CdkTreeNodeOutlet, CdkTreeNodePadding, CdkTreeNodeToggle, CdkTreeModule } from '@angular/cdk/tree';
import { ElementRef, Attribute, Input, Directive, IterableDiffers, ViewContainerRef, Inject, Optional, ViewChild, Component, ViewEncapsulation, ChangeDetectionStrategy, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

class NtTreeNestedDataSource extends DataSource {
    constructor() {
        super(...arguments);
        this._data = new BehaviorSubject([]);
    }
    get data() { return this._data.value; }
    set data(value) { this._data.next(value); }
    connect(collectionViewer) {
        return merge(...[collectionViewer.viewChange, this._data])
            .pipe(map(() => this.data));
    }
    disconnect() {
    }
}

class NtTreeFlattener {
    constructor(transformFunction, getLevel, isExpandable, getChildren) {
        this.transformFunction = transformFunction;
        this.getLevel = getLevel;
        this.isExpandable = isExpandable;
        this.getChildren = getChildren;
    }
    _flattenNode(node, level, resultNodes, parentMap) {
        const flatNode = this.transformFunction(node, level);
        resultNodes.push(flatNode);
        if (this.isExpandable(flatNode)) {
            const childrenNodes = this.getChildren(node);
            if (Array.isArray(childrenNodes)) {
                this._flattenChildren(childrenNodes, level, resultNodes, parentMap);
            }
            else {
                childrenNodes.pipe(take(1)).subscribe(children => {
                    this._flattenChildren(children, level, resultNodes, parentMap);
                });
            }
        }
        return resultNodes;
    }
    _flattenChildren(children, level, resultNodes, parentMap) {
        children.forEach((child, index) => {
            let childParentMap = parentMap.slice();
            childParentMap.push(index !== children.length - 1);
            this._flattenNode(child, level + 1, resultNodes, childParentMap);
        });
    }
    flattenNodes(structuredData) {
        let resultNodes = [];
        structuredData.forEach(node => this._flattenNode(node, 0, resultNodes, []));
        return resultNodes;
    }
    expandFlattenedNodes(nodes, treeControl) {
        let results = [];
        let currentExpand = [];
        currentExpand[0] = true;
        nodes.forEach(node => {
            let expand = true;
            for (let i = 0; i <= this.getLevel(node); i++) {
                expand = expand && currentExpand[i];
            }
            if (expand) {
                results.push(node);
            }
            if (this.isExpandable(node)) {
                currentExpand[this.getLevel(node) + 1] = treeControl.isExpanded(node);
            }
        });
        return results;
    }
}
class NtTreeFlatDataSource extends DataSource {
    constructor(treeControl, treeFlattener, initialData = []) {
        super();
        this.treeControl = treeControl;
        this.treeFlattener = treeFlattener;
        this._flattenedData = new BehaviorSubject([]);
        this._expandedData = new BehaviorSubject([]);
        this._data = new BehaviorSubject(initialData);
    }
    get data() { return this._data.value; }
    set data(value) {
        this._data.next(value);
        this._flattenedData.next(this.treeFlattener.flattenNodes(this.data));
        this.treeControl.dataNodes = this._flattenedData.value;
    }
    connect(collectionViewer) {
        const changes = [
            collectionViewer.viewChange,
            this.treeControl.expansionModel.changed,
            this._flattenedData
        ];
        return merge(...changes).pipe(map(() => {
            this._expandedData.next(this.treeFlattener.expandFlattenedNodes(this._flattenedData.value, this.treeControl));
            return this._expandedData.value;
        }));
    }
    disconnect() { }
}

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 __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var NtTreeNodeDirective_1, NtTreeNodeDefDirective_1, NtNestedTreeNodeDirective_1;
let NtTreeNodeDirective = NtTreeNodeDirective_1 = class NtTreeNodeDirective extends CdkTreeNode {
    constructor(_elementRef, _tree, tabIndex) {
        super(_elementRef, _tree);
        this._elementRef = _elementRef;
        this._tree = _tree;
        this._disabled = false;
        this._tabIndex = 0;
        this.role = 'treeitem';
        this.tabIndex = Number(tabIndex) || 0;
    }
    get disabled() { return this._disabled; }
    set disabled(value) { this._disabled = coerceBooleanProperty(value); }
    get tabIndex() { return this.disabled ? -1 : this._tabIndex; }
    set tabIndex(value) { this._tabIndex = value != null ? value : 0; }
};
NtTreeNodeDirective.ctorParameters = () => [
    { type: ElementRef },
    { type: CdkTree },
    { type: String, decorators: [{ type: Attribute, args: ['tabindex',] }] }
];
__decorate([
    Input()
], NtTreeNodeDirective.prototype, "role", void 0);
NtTreeNodeDirective = NtTreeNodeDirective_1 = __decorate([
    Directive({
        selector: 'nt-tree-node, [nt-tree-node]',
        exportAs: 'ntTreeNode',
        inputs: ['disabled', 'tabIndex'],
        host: {
            'class': 'nt-tree-node'
        },
        providers: [{ provide: CdkTreeNode, useExisting: NtTreeNodeDirective_1 }]
    }),
    __param(2, Attribute('tabindex'))
], NtTreeNodeDirective);
let NtTreeNodeDefDirective = NtTreeNodeDefDirective_1 = class NtTreeNodeDefDirective extends CdkTreeNodeDef {
};
__decorate([
    Input('ntTreeNode')
], NtTreeNodeDefDirective.prototype, "data", void 0);
NtTreeNodeDefDirective = NtTreeNodeDefDirective_1 = __decorate([
    Directive({
        selector: '[ntTreeNodeDef]',
        inputs: [
            'when: ntTreeNodeDefWhen'
        ],
        providers: [{ provide: CdkTreeNodeDef, useExisting: NtTreeNodeDefDirective_1 }]
    })
], NtTreeNodeDefDirective);
let NtNestedTreeNodeDirective = NtNestedTreeNodeDirective_1 = class NtNestedTreeNodeDirective extends CdkNestedTreeNode {
    constructor(_elementRef, _tree, _differs, tabIndex) {
        super(_elementRef, _tree, _differs);
        this._elementRef = _elementRef;
        this._tree = _tree;
        this._differs = _differs;
        this._disabled = false;
        this._tabIndex = 0;
        this.tabIndex = Number(tabIndex) || 0;
    }
    get disabled() { return this._disabled; }
    set disabled(value) { this._disabled = coerceBooleanProperty(value); }
    get tabIndex() { return this.disabled ? -1 : this._tabIndex; }
    set tabIndex(value) { this._tabIndex = value != null ? value : 0; }
    ngAfterContentInit() {
        super.ngAfterContentInit();
    }
    ngOnDestroy() {
        super.ngOnDestroy();
    }
};
NtNestedTreeNodeDirective.ctorParameters = () => [
    { type: ElementRef },
    { type: CdkTree },
    { type: IterableDiffers },
    { type: String, decorators: [{ type: Attribute, args: ['tabindex',] }] }
];
__decorate([
    Input('ntNestedTreeNode')
], NtNestedTreeNodeDirective.prototype, "node", void 0);
NtNestedTreeNodeDirective = NtNestedTreeNodeDirective_1 = __decorate([
    Directive({
        selector: 'nt-nested-tree-node, [nt-nested-tree-node]',
        exportAs: 'ntNestedTreeNode',
        host: {
            'class': 'nt-nested-tree-node',
        },
        inputs: ['disabled', 'tabIndex'],
        providers: [
            { provide: CdkNestedTreeNode, useExisting: NtNestedTreeNodeDirective_1 },
            { provide: CdkTreeNode, useExisting: NtNestedTreeNodeDirective_1 }
        ]
    }),
    __param(3, Attribute('tabindex'))
], NtNestedTreeNodeDirective);

var __decorate$1 = (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 __param$1 = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var NtTreeNodeOutletDirective_1;
let NtTreeNodeOutletDirective = NtTreeNodeOutletDirective_1 = class NtTreeNodeOutletDirective {
    constructor(viewContainer, _node) {
        this.viewContainer = viewContainer;
        this._node = _node;
    }
};
NtTreeNodeOutletDirective.ctorParameters = () => [
    { type: ViewContainerRef },
    { type: undefined, decorators: [{ type: Inject, args: [CDK_TREE_NODE_OUTLET_NODE,] }, { type: Optional }] }
];
NtTreeNodeOutletDirective = NtTreeNodeOutletDirective_1 = __decorate$1([
    Directive({
        selector: '[ntTreeNodeOutlet]',
        providers: [
            { provide: CdkTreeNodeOutlet, useExisting: NtTreeNodeOutletDirective_1 }
        ]
    }),
    __param$1(1, Inject(CDK_TREE_NODE_OUTLET_NODE)), __param$1(1, Optional())
], NtTreeNodeOutletDirective);

var __decorate$2 = (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 NtTreeNodePaddingDirective_1;
let NtTreeNodePaddingDirective = NtTreeNodePaddingDirective_1 = class NtTreeNodePaddingDirective extends CdkTreeNodePadding {
};
__decorate$2([
    Input('ntTreeNodePadding')
], NtTreeNodePaddingDirective.prototype, "level", void 0);
__decorate$2([
    Input('ntTreeNodePaddingIndent')
], NtTreeNodePaddingDirective.prototype, "indent", void 0);
NtTreeNodePaddingDirective = NtTreeNodePaddingDirective_1 = __decorate$2([
    Directive({
        selector: '[ntTreeNodePadding]',
        providers: [{ provide: CdkTreeNodePadding, useExisting: NtTreeNodePaddingDirective_1 }]
    })
], NtTreeNodePaddingDirective);

var __decorate$3 = (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 NtTreeNodeToggleDirective_1;
let NtTreeNodeToggleDirective = NtTreeNodeToggleDirective_1 = class NtTreeNodeToggleDirective extends CdkTreeNodeToggle {
    constructor() {
        super(...arguments);
        this.recursive = false;
    }
};
__decorate$3([
    Input('ntTreeNodeToggleRecursive')
], NtTreeNodeToggleDirective.prototype, "recursive", void 0);
NtTreeNodeToggleDirective = NtTreeNodeToggleDirective_1 = __decorate$3([
    Directive({
        selector: '[ntTreeNodeToggle]',
        providers: [{ provide: CdkTreeNodeToggle, useExisting: NtTreeNodeToggleDirective_1 }]
    })
], NtTreeNodeToggleDirective);

var __decorate$4 = (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 NtTreeComponent_1;
let NtTreeComponent = NtTreeComponent_1 = class NtTreeComponent extends CdkTree {
};
__decorate$4([
    ViewChild(NtTreeNodeOutletDirective, { static: true })
], NtTreeComponent.prototype, "_nodeOutlet", void 0);
NtTreeComponent = NtTreeComponent_1 = __decorate$4([
    Component({
        selector: 'nt-tree, [nt-tree]',
        template: `<ng-container ntTreeNodeOutlet></ng-container>`,
        encapsulation: ViewEncapsulation.None,
        changeDetection: ChangeDetectionStrategy.OnPush,
        providers: [
            { provide: CdkTree, useExisting: NtTreeComponent_1 }
        ],
        host: {
            'class': 'nt-tree'
        }
    })
], NtTreeComponent);

var __decorate$5 = (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;
};
const NT_TREE_DIRECTIVES = [
    NtNestedTreeNodeDirective,
    NtTreeNodeDefDirective,
    NtTreeNodePaddingDirective,
    NtTreeNodeToggleDirective,
    NtTreeComponent,
    NtTreeNodeDirective,
    NtTreeNodeOutletDirective
];
let NtTreeModule = class NtTreeModule {
};
NtTreeModule = __decorate$5([
    NgModule({
        imports: [CdkTreeModule, CommonModule],
        exports: NT_TREE_DIRECTIVES,
        declarations: NT_TREE_DIRECTIVES
    })
], NtTreeModule);

export { NtNestedTreeNodeDirective, NtTreeComponent, NtTreeFlatDataSource, NtTreeFlattener, NtTreeModule, NtTreeNestedDataSource, NtTreeNodeDefDirective, NtTreeNodeDirective, NtTreeNodeOutletDirective, NtTreeNodePaddingDirective, NtTreeNodeToggleDirective };
//# sourceMappingURL=tree.js.map
