import { Subject, BehaviorSubject, Observable } from 'rxjs';
import { Injectable, NgModule, Directive, ElementRef, Input, HostListener, HostBinding, Output, EventEmitter, Component, defineInjectable } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faCoffee, faPlus, faEdit, faMinus, faTimes, faCheck, faArrowDown } from '@fortawesome/free-solid-svg-icons';
import { TranslateService, TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { HttpClient, HttpClientModule } from '@angular/common/http';

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class NgxTreeService {
    constructor() {
        this.treeStorage = [];
        this.onDragStart = new Subject();
        this.onDragEnter = new Subject();
        this.onDragLeave = new Subject();
        this.onDrop = new Subject();
        this.onDrag = new Subject();
        this.onAllowDrop = new Subject();
        this.onDragEnd = new Subject();
        this.onAddItem = new Subject();
        this.onRenameItem = new Subject();
        this.onStartRenameItem = new Subject();
        this.onFinishRenameItem = new Subject();
        this.onStartDeleteItem = new Subject();
        this.onFinishDeleteItem = new Subject();
        this.onCancelDeleteItem = new Subject();
        this.config = new BehaviorSubject(null);
        this.language = new BehaviorSubject('');
        this.defaultLanguage = 'ru';
        // set default config
        this.defaultConfig = {
            language: 'ru',
            showActionButtons: true,
            showAddButtons: true,
            showRenameButtons: true,
            showDeleteButtons: true,
            showRootActionButtons: true,
            enableExpandButtons: true,
            enableDragging: true,
            rootTitle: 'Root',
            validationText: 'Enter valid name',
            minCharacterLength: 1,
            setItemsAsLinks: false,
            setFontSize: 16,
            setIconSize: 14
        };
    }
    /*
        get data and set it on observable.
        if data = null set empty data array
      */
    /**
     * @param {?} item
     * @return {?}
     */
    getLocalData(item) {
        /** @type {?} */
        const data = new Observable((/**
         * @param {?} observer
         * @return {?}
         */
        observer => {
            this.treeStorage = item;
            if (this.treeStorage && this.treeStorage !== null) {
                this.checkTreeLength();
                observer.next(this.treeStorage);
            }
            else {
                this.treeStorage = JSON.parse('[]');
                observer.next(this.treeStorage);
            }
        }));
        return data;
    }
    /*
       Element finder, it`s find element by id in tree.
       Returns: finded element, parent array.
       Watch out, this is recursive method.
      */
    /**
     * @private
     * @param {?} list
     * @param {?} id
     * @param {?=} parent
     * @return {?}
     */
    elementFinder(list, id, parent) {
        for (const item of list) {
            if (item.id === id) {
                this.findingResults = {
                    foundItem: item,
                    itemsList: list
                };
                if (parent) {
                    this.findingResults.parentItem = parent;
                }
                break;
            }
            else {
                if (item.children.length > 0) {
                    this.elementFinder(item.children, id, item);
                }
            }
        }
    }
    /*
       Add new item to tree.
       Its accepts 'type' for detect add root element or children.
       Emit onAddItem Subject.
      */
    /**
     * @param {?} id
     * @param {?} name
     * @param {?=} parent
     * @return {?}
     */
    addNewItem(id, name, parent) {
        /** @type {?} */
        let pos = 1;
        if (parent && parent.children.length !== 0) {
            /** @type {?} */
            const parentPrevChildren = parent.children.length - 1;
            /** @type {?} */
            const newItemPosition = parent.children[parentPrevChildren].options.position + 1;
            pos = newItemPosition;
        }
        /** @type {?} */
        const createObj = {
            id,
            name,
            options: {
                position: pos,
                edit: true
            },
            children: []
        };
        if (parent != null) {
            this.elementFinder(this.treeStorage, parent ? parent.id : null);
            this.findingResults && this.findingResults.foundItem.children.push(createObj);
        }
        else {
            this.treeStorage.push(createObj);
        }
        /** @type {?} */
        const eventEmit = {
            element: createObj,
            parent: parent ? this.findingResults.foundItem : 'root'
        };
        this.onAddItem.next(eventEmit);
        this.clearAction();
    }
    /*
       Delete element.
       It`s accepts 'id' for find item on tree.
       Emit onStartDeleteItem Subject before delete.
       Emit onFinishDeleteItem Subject after submit delete.
       Emit onCancelDeleteItem Subject after on cancel delete.
      */
    /**
     * @param {?} id
     * @return {?}
     */
    deleteItem(id) {
        this.elementFinder(this.treeStorage, id);
        /** @type {?} */
        const eventEmit = {
            element: this.findingResults.foundItem,
            parent: this.findingResults.parentItem || 'root'
        };
        this.onStartDeleteItem.next(eventEmit);
        /** @type {?} */
        let text;
        if (this.findingResults.foundItem.name) {
            text = `Do you really want to delete '${this.findingResults.foundItem.name}'?`;
        }
        else {
            text = `Cancel creating a new item?`;
        }
        if (confirm(text)) {
            this.onFinishDeleteItem.next(eventEmit);
            /** @type {?} */
            const i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem);
            this.findingResults.itemsList.splice(i, 1);
        }
        else {
            this.onCancelDeleteItem.next(eventEmit);
        }
        this.clearAction();
        this.checkTreeLength();
    }
    /*
       Trigger start rename element.
       It`s accepts 'name' and 'id' for find item on tree and set the name.
       Emit onRenameItem Subject.
      */
    /**
     * @param {?} element
     * @return {?}
     */
    startRenameItem(element) {
        this.elementFinder(this.treeStorage, element.id);
        // event emit
        /** @type {?} */
        const eventEmit = {
            element: this.findingResults.foundItem,
            parent: this.findingResults.parentItem || 'root'
        };
        this.onStartRenameItem.next(eventEmit);
    }
    /*
       Rename element.
       It`s accepts 'name' and 'id' for find item on tree and set the name.
       Emit onRenameItem Subject.
      */
    /**
     * @param {?} name
     * @param {?} id
     * @return {?}
     */
    finishRenameItem(name, id) {
        this.elementFinder(this.treeStorage, id);
        // code
        this.findingResults.foundItem.name = name;
        this.findingResults.foundItem.options.edit = false;
        // event emit
        /** @type {?} */
        const eventEmit = {
            element: this.findingResults.foundItem,
            parent: this.findingResults.parentItem || 'root'
        };
        this.onFinishRenameItem.next(eventEmit);
        this.clearAction();
    }
    /*
       Event: ondragstart;
       On start dragging find element my id and set option currentlyDragging true.
      */
    /**
     * @param {?} eventObj
     * @return {?}
     */
    startDragging(eventObj) {
        this.switchDropButton(true, this.treeStorage);
        this.onDragStart.next(eventObj);
    }
    /*
       Event: ondrag;
       Trigger dragging element
      */
    /**
     * @param {?} eventObj
     * @return {?}
     */
    onDragProcess(eventObj) {
        this.onDrag.next(eventObj);
    }
    /*
       Event: ondragend;
       detect end of drag action
      */
    /**
     * @param {?} eventObj
     * @return {?}
     */
    dragEndAction(eventObj) {
        this.removeDestenationBorders(this.treeStorage);
        this.switchDropButton(false, this.treeStorage);
        this.onDragEnd.next(eventObj);
    }
    /*
        Event: enterdropzone;
        Entering drop zone for styling items.
      */
    /**
     * @param {?} eventObj
     * @return {?}
     */
    enterDropZone(eventObj) {
        this.onDragEnter.next(eventObj);
    }
    /*
        Event: dragover;
        Detect hover on dropable elements
      */
    /**
     * @param {?} eventObj
     * @return {?}
     */
    onDragOver(eventObj) {
        /** @type {?} */
        const el = ((/** @type {?} */ (eventObj.target)));
        if (el && el.id !== this.isDragging.id) {
            /** @type {?} */
            const elementHalfHeight = eventObj.event.toElement.offsetHeight / 2;
            if (eventObj.event.offsetY < elementHalfHeight) {
                el.options.destenationBottom = false;
                el.options.destenationTop = true;
            }
            else {
                el.options.destenationBottom = true;
                el.options.destenationTop = false;
            }
            this.onAllowDrop.next(eventObj);
        }
    }
    /*
        Event: leavedropzone;
        Leave drop zone for restyling items.
      */
    /**
     * @param {?} eventObj
     * @return {?}
     */
    leaveDropZone(eventObj) {
        this.removeDestenationBorders(this.treeStorage);
        this.onDragLeave.next(eventObj);
    }
    /*
        Event: ondrop;
        Its use where draggable item drop not on allowed for drop zone:
        set item option currentlyDragging false.
        return false.
     */
    /**
     * @param {?} eventObj
     * @return {?}
     */
    onDropItem(eventObj) {
        if (eventObj.target) {
            /** @type {?} */
            const elementHalfHeight = eventObj.event.toElement.offsetHeight / 2;
            if (eventObj.event.offsetY < elementHalfHeight) {
                this.changeItemPosition(eventObj.target, 'up');
            }
            else {
                this.changeItemPosition(eventObj.target, 'down');
            }
            this.onDrop.next(eventObj);
        }
        else {
            /** @type {?} */
            const dropZoneId = parseInt(eventObj.event.target.getAttribute('data-id'), null);
            this.elementFinder(this.treeStorage, this.isDragging.id);
            /** @type {?} */
            const i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem);
            /** @type {?} */
            const copyItem = this.findingResults.itemsList.splice(i, 1)[0];
            this.elementFinder(this.treeStorage, dropZoneId);
            this.findingResults.foundItem.children.push(copyItem);
            // this.sortTree();
            eventObj.target = this.findingResults.foundItem;
            this.onDrop.next(eventObj);
        }
        this.removeDestenationBorders(this.treeStorage);
        this.switchDropButton(false, this.treeStorage);
        this.clearAction();
        setTimeout((/**
         * @return {?}
         */
        () => {
            this.checkTreeLength();
        }));
    }
    /*
        change position of items
        need set direction before use
      */
    /**
     * @private
     * @param {?} el
     * @param {?} direction
     * @return {?}
     */
    changeItemPosition(el, direction) {
        setTimeout((/**
         * @return {?}
         */
        () => {
            this.elementFinder(this.treeStorage, this.isDragging.id);
            /** @type {?} */
            const i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem);
            /** @type {?} */
            const copyItem = this.findingResults.itemsList.splice(i, 1)[0];
            // end test
            /** @type {?} */
            const positionTarget = el.options.position;
            this.elementFinder(this.treeStorage, el.id);
            if (direction === 'up') {
                for (const items of this.findingResults.itemsList) {
                    if (items.options.position >= positionTarget) {
                        items.options.position = items.options.position + 1;
                        copyItem.options.position = positionTarget;
                    }
                }
            }
            else {
                for (const items of this.findingResults.itemsList) {
                    if (items.options.position <= positionTarget) {
                        items.options.position = items.options.position - 1;
                    }
                }
            }
            copyItem.options.position = positionTarget;
            this.findingResults.itemsList.push(copyItem);
            this.sortTree();
        }));
    }
    // get position of item
    /**
     * @param {?} item
     * @return {?}
     */
    getItemPosition(item) {
        this.elementFinder(this.treeStorage, item.id);
        /** @type {?} */
        let position = this.findingResults.itemsList.indexOf(this.findingResults.foundItem);
        return ++position;
    }
    // sort tree byposition
    /**
     * @return {?}
     */
    sortTree() {
        this.sortElements(this.treeStorage);
    }
    // part of sortTree()
    /**
     * @private
     * @param {?} tree
     * @return {?}
     */
    sortElements(tree) {
        tree.sort(this.compate);
        for (const item of tree) {
            if (item.children.length > 0) {
                this.sortElements(item.children);
            }
        }
    }
    // part of sortTree()
    /**
     * @private
     * @param {?} a
     * @param {?} b
     * @return {?}
     */
    compate(a, b) {
        if (a.options.position < b.options.position) {
            return -1;
        }
        if (a.options.position > b.options.position) {
            return 1;
        }
        return 0;
    }
    // clear selectedElement && isDragging from element finder.
    /**
     * @return {?}
     */
    clearAction() {
        this.findingResults = null;
    }
    /**
     * @private
     * @param {?} data
     * @return {?}
     */
    removeDestenationBorders(data) {
        for (const item of data) {
            item.options.destenationBottom = false;
            item.options.destenationTop = false;
            if (item.children.length > 0) {
                this.removeDestenationBorders(item.children);
            }
        }
    }
    /**
     * @private
     * @param {?} bool
     * @param {?} data
     * @return {?}
     */
    switchDropButton(bool, data) {
        for (const el of data) {
            el.options.showActionButtons = !bool;
            if (el.id !== this.isDragging.id) {
                el.options.showDropChildZone = bool;
            }
            if (el.children.length > 0) {
                this.switchDropButton(bool, el.children);
            }
        }
    }
    /**
     * @return {?}
     */
    checkTreeLength() {
        if (!this.treeStorage || !this.treeStorage[0] || !this.treeStorage[0].options) {
            // this.treeStorage[0].options = {} as TreeItemOptions;
            return;
        }
        if (this.treeStorage.length < 2) {
            this.treeStorage[0].options.showDeleteButton = false;
        }
        else {
            for (const el of this.treeStorage) {
                if (el && el.options) {
                    el.options.showDeleteButton = true;
                }
            }
        }
    }
}
NgxTreeService.decorators = [
    { type: Injectable, args: [{
                providedIn: 'root'
            },] }
];
/** @nocollapse */
NgxTreeService.ctorParameters = () => [];
/** @nocollapse */ NgxTreeService.ngInjectableDef = defineInjectable({ factory: function NgxTreeService_Factory() { return new NgxTreeService(); }, token: NgxTreeService, providedIn: "root" });

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class NgxTreeParentComponent {
    /**
     * @param {?} treeService
     * @param {?} fb
     */
    constructor(treeService, fb) {
        this.treeService = treeService;
        this.fb = fb;
        this.userConfig = {
            language: 'ru',
            showActionButtons: true,
            showAddButtons: true,
            showRenameButtons: true,
            showDeleteButtons: true,
            showRootActionButtons: true,
            enableExpandButtons: true,
            enableDragging: true,
            rootTitle: 'Root',
            options: {
                edit: false
            },
            validationText: 'Enter valid name',
            minCharacterLength: 1,
            setItemsAsLinks: false,
            setFontSize: 16,
            setIconSize: 14
        };
        this.ondragstart = new EventEmitter();
        this.ondragenter = new EventEmitter();
        this.ondragleave = new EventEmitter();
        this.ondrop = new EventEmitter();
        this.onallowdrop = new EventEmitter();
        this.ondragend = new EventEmitter();
        this.onadditem = new EventEmitter();
        this.onStartRenameItem = new EventEmitter();
        this.onFinishRenameItem = new EventEmitter();
        this.onStartDeleteItem = new EventEmitter();
        this.onFinishDeleteItem = new EventEmitter();
        this.onCancelDeleteItem = new EventEmitter();
        this.enableSubscribers();
        this.createForm();
    }
    /**
     * @param {?} config
     * @return {?}
     */
    set config(config) {
        // seal config
        Object.seal(this.userConfig);
        try {
            // if config it`s pass
            this.setConfig(config);
            this.treeService.config.next(this.userConfig);
        }
        catch (error) {
            // if config invalid
            this.treeService.config.next(this.treeService.defaultConfig);
        }
    }
    /**
     * @param {?} language
     * @return {?}
     */
    set language(language) {
        /** @type {?} */
        const _language = (language && typeof language === 'string') ? language : this.treeService.defaultLanguage;
        this.current_language = language;
        this.treeService.language.next(_language);
    }
    /**
     * @param {?} item
     * @return {?}
     */
    set treeData(item) {
        // get user tree data
        this.getTreeData(item);
    }
    /**
     * @param {?} changes
     * @return {?}
     */
    ngOnChanges(changes) {
        console.log("changes");
        console.log(changes);
    }
    // set user config
    /**
     * @param {?} config
     * @return {?}
     */
    setConfig(config) {
        for (const key of Object.keys(config)) {
            this.setValue(key, config);
        }
        this.renameForm.patchValue({
            name: this.userConfig.rootTitle
        });
    }
    // set value to keys of config
    /**
     * @param {?} item
     * @param {?} config
     * @return {?}
     */
    setValue(item, config) {
        this.userConfig[item] = config[item];
    }
    // subscribe to all events and emit them to user.
    /**
     * @return {?}
     */
    enableSubscribers() {
        this.treeService.onDrop.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.ondrop.emit(event);
        }));
        this.treeService.onDragStart.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.ondragstart.emit(event);
        }));
        this.treeService.onAllowDrop.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.onallowdrop.emit(event);
        }));
        this.treeService.onDragEnd.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.ondragend.emit(event);
        }));
        this.treeService.onAddItem.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.onadditem.emit(event);
        }));
        this.treeService.onStartRenameItem.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.onStartRenameItem.emit(event);
        }));
        this.treeService.onFinishRenameItem.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.onFinishRenameItem.emit(event);
        }));
        this.treeService.onStartDeleteItem.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.onStartDeleteItem.emit(event);
        }));
        this.treeService.onFinishDeleteItem.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.onFinishDeleteItem.emit(event);
        }));
        this.treeService.onCancelDeleteItem.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.onCancelDeleteItem.emit(event);
        }));
        this.treeService.onDragEnter.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.ondragenter.emit(event);
        }));
        this.treeService.onDragLeave.subscribe((/**
         * @param {?} event
         * @return {?}
         */
        (event) => {
            this.ondragleave.emit(event);
        }));
    }
    // get tree data from treeService.
    /**
     * @param {?} userTree
     * @return {?}
     */
    getTreeData(userTree) {
        this.treeService.getLocalData(userTree).subscribe((/**
         * @param {?} tree
         * @return {?}
         */
        (tree) => {
            this.treeView = tree;
            setTimeout((/**
             * @return {?}
             */
            () => {
                this.treeService.sortTree();
            }));
        }), (/**
         * @param {?} error
         * @return {?}
         */
        (error) => {
            console.log("getTreeData error: ");
            console.log(error);
        }));
    }
    // create edit form
    /**
     * @return {?}
     */
    createForm() {
        this.renameForm = this.fb.group({
            name: [this.userConfig.rootTitle || '', [
                    Validators.required,
                    Validators.minLength(this.userConfig.minCharacterLength)
                ]],
        });
    }
    /**
     * @return {?}
     */
    enableRootRenameMode() {
        this.userConfig.options.edit = true;
    }
    /**
     * @param {?} name
     * @return {?}
     */
    submitAdd(name) {
        /** @type {?} */
        const d = `${new Date().getFullYear()}${new Date().getDay()}${new Date().getTime()}`;
        /** @type {?} */
        const elemId = parseInt(d, null);
        this.treeService.addNewItem(elemId, name, null);
    }
    /**
     * @return {?}
     */
    submitRootRename() {
        if (this.renameForm.valid) {
            this.showError = false;
            this.userConfig.rootTitle = this.renameForm.value.name;
            this.userConfig.options.edit = false;
        }
        else {
            this.showError = true;
        }
    }
    /**
     * @return {?}
     */
    ngAfterViewInit() { }
}
NgxTreeParentComponent.decorators = [
    { type: Component, args: [{
                selector: 'asd-ngx-tree-lib',
                template: "<div id='threeWrapper' *ngIf=\"treeView\" [style.font-size.px]='userConfig.setFontSize'>\n    <div class='root-title d-inline-flex pos-relative' *ngIf=\"!userConfig.options.edit;else onEdit\">\n      <div class='root-text'>\n        {{userConfig.rootTitle | translate}}\n      </div>\n      \n      <div class='d-flex buttons-bar' *ngIf=\"userConfig.showActionButtons && userConfig.showRootActionButtons\">\n        <div class='d-flex'>\n          <button class=\"tree-btn add-btn\" *ngIf=\"userConfig.showAddButtons\" (click)=\"submitAdd(null)\">\n            <fa-icon icon=\"plus\" [style.font-size.px]='userConfig.setIconSize'></fa-icon>\n          </button>\n        </div>\n        <div class='d-flex'>\n          <button class=\"tree-btn edit-btn\" *ngIf=\"userConfig.showRenameButtons\" (click)=\"enableRootRenameMode()\">\n            <fa-icon icon=\"edit\" [style.font-size.px]='userConfig.setIconSize'></fa-icon>\n          </button>\n        </div>\n      </div>\n    </div>\n    <ng-template #onEdit>\n      <div class='d-inline-flex'>\n        <form [formGroup]=\"renameForm\" class='d-flex' (submit)='submitRootRename()'>\n          <input type=\"text\" class='input-rename' formControlName=\"name\" libAutoFocus=\"true\" [style.font-size.px]='userConfig.setFontSize'>\n        </form>\n        <div class='d-flex'>\n          <button class='tree-btn submit-btn' (click)='submitRootRename()'>\n            <fa-icon icon=\"check\" [style.font-size.px]='userConfig.setIconSize'></fa-icon>\n          </button>\n          <div class='error-edit-wrap' *ngIf=\"showError\">\n            {{userConfig.validationText}}\n          </div>\n        </div>\n      </div>\n    </ng-template>\n    <div class='tree-child'>\n      <div class=\"tree-content-main\">\n          <lib-ngx-tree-children [setItem]=\"clild\" *ngFor='let clild of treeView'></lib-ngx-tree-children>\n      </div>\n    </div>\n  </div>\n"
            }] }
];
/** @nocollapse */
NgxTreeParentComponent.ctorParameters = () => [
    { type: NgxTreeService },
    { type: FormBuilder }
];
NgxTreeParentComponent.propDecorators = {
    ondragstart: [{ type: Output }],
    ondragenter: [{ type: Output }],
    ondragleave: [{ type: Output }],
    ondrop: [{ type: Output }],
    onallowdrop: [{ type: Output }],
    ondragend: [{ type: Output }],
    onadditem: [{ type: Output }],
    onStartRenameItem: [{ type: Output }],
    onFinishRenameItem: [{ type: Output }],
    onStartDeleteItem: [{ type: Output }],
    onFinishDeleteItem: [{ type: Output }],
    onCancelDeleteItem: [{ type: Output }],
    config: [{ type: Input }],
    language: [{ type: Input }],
    treeData: [{ type: Input }]
};

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class NgxTreeChildrenComponent {
    /**
     * @param {?} treeService
     * @param {?} fb
     * @param {?} tr
     */
    constructor(treeService, fb, tr) {
        this.treeService = treeService;
        this.fb = fb;
        this.tr = tr;
    }
    // get item from parent component
    /**
     * @param {?} data
     * @return {?}
     */
    set setItem(data) {
        this.element = data;
        this.itemOptions = {
            href: '#',
            hidden: false,
            hideChildren: false,
            position: this.treeService.getItemPosition(this.element),
            draggable: true,
            edit: false,
            showActionButtons: true,
            currentlyDragging: false,
            destenationTop: false,
            destenationBottom: false,
            disabled: false,
            showExpandButton: true,
            showDeleteButton: true
        };
        if (this.element.options) {
            this.setOptions(this.element.options);
            this.element.options = this.itemOptions;
        }
        else {
            this.element.options = this.itemOptions;
        }
        // enable subscribers
        this.enableSubscribers();
        // create form
        this.createForm();
    }
    // enable subscribe to config
    /**
     * @return {?}
     */
    enableSubscribers() {
        this.treeService.config.subscribe((/**
         * @param {?} config
         * @return {?}
         */
        (config) => {
            if (config !== null) {
                this.config = config;
            }
            else {
                this.config = this.treeService.defaultConfig;
            }
            if (this.element.options.draggable) {
                this.element.options.draggable = this.config.enableDragging;
            }
        }));
        this.treeService.language.subscribe((/**
         * @param {?} language
         * @return {?}
         */
        (language) => {
            if (language !== '') {
                this.language = language;
            }
            else {
                this.language = this.treeService.defaultLanguage;
            }
        }));
    }
    /**
     * @param {?} strings
     * @return {?}
     */
    getTitleFromLocalized(strings) {
        /** @type {?} */
        const empty = this.tr.instant('dashboard.empty');
        /** @type {?} */
        let res = empty;
        if (typeof strings === 'string' || typeof strings === 'number') {
            return strings.toString();
        }
        if (!Array.isArray(strings)) {
            return res;
        }
        strings.forEach((/**
         * @param {?} value
         * @return {?}
         */
        value => {
            if (value.language === this.language) {
                res = value.value;
            }
        }));
        return res;
    }
    // set options to item
    /**
     * @param {?} options
     * @return {?}
     */
    setOptions(options) {
        for (const key of Object.keys(options)) {
            this.setValue(key, options);
        }
    }
    // set value to options keys
    /**
     * @param {?} item
     * @param {?} options
     * @return {?}
     */
    setValue(item, options) {
        this.itemOptions[item] = options[item];
    }
    // create edit form
    /**
     * @return {?}
     */
    createForm() {
        this.renameForm = this.fb.group({
            name: [this.element.name || '', [
                    Validators.required,
                    Validators.minLength(this.config.minCharacterLength)
                ]],
        });
    }
    /*
        Event: onStartRenameItem;
        Enable rename mode in element
        Call onStartRenameItem() from tree service.
      */
    /**
     * @param {?} element
     * @return {?}
     */
    enableRenameMode(element) {
        element.options.edit = true;
        this.treeService.startRenameItem(element);
    }
    /*
        Event: onadditem;
        Generate id by new Date() by 'full year + day + time'.
        Call addNewItem() from tree service.
      */
    /**
     * @param {?} name
     * @param {?} item
     * @return {?}
     */
    submitAdd(name, item) {
        /** @type {?} */
        const d = `${new Date().getFullYear()}${new Date().getDay()}${new Date().getTime()}`;
        /** @type {?} */
        const elemId = parseInt(d, null);
        this.treeService.addNewItem(elemId, name, item);
        this.element.options.hideChildren = false;
    }
    /*
        Event: onFinishRenameItem;
        Check is form valid.
        Call addNewItem() from tree service.
      */
    /**
     * @param {?} item
     * @return {?}
     */
    submitRename(item) {
        if (this.renameForm.valid) {
            this.showError = false;
            this.treeService.finishRenameItem(this.renameForm.value.name, item.id);
            this.element.options.edit = false;
        }
        else {
            this.showError = true;
        }
    }
    /*
        Events:
        onStartDeleteItem,
        onFinishDeleteItem,
        onCancelDeleteItem.
        Check is item edit, then if name empty delete item.
        Call deleteItem() from tree service.
      */
    /**
     * @param {?} item
     * @return {?}
     */
    onSubmitDelete(item) {
        if (!this.element.options.edit) {
            this.treeService.deleteItem(item.id);
        }
        else {
            if (item.name === null) {
                this.treeService.deleteItem(item.id);
            }
            else {
                this.element.options.edit = false;
            }
        }
    }
    // after view init
    /**
     * @return {?}
     */
    ngAfterViewInit() { }
}
NgxTreeChildrenComponent.decorators = [
    { type: Component, args: [{
                selector: 'lib-ngx-tree-children',
                template: "<div class='tree-child' id={{element.id}} libDragElement [draggableValue]='element.options.draggable' [item]='element' [ngClass]=\"{disabled : element.options.disabled}\">\n  <div *ngIf=\"element && element.options\" class='d-flex'>\n    <div *ngIf='config' [ngClass]=\"{hidden : element.options.hidden}\">\n      <div class='tree-title d-inline-flex pos-relative' [ngClass]=\"{destenationTop : element.options.destenationTop, destenationBottom: element.options.destenationBottom}\" *ngIf=\"!element.options.edit;else onEdit\">\n        <div *ngIf=\"!config.setItemsAsLinks; else link\" [ngClass]=\"{addOpacity : element.options.currentlyDragging}\" libDropElement\n          [item]='element' class='draggable-item'>\n          {{getTitleFromLocalized(element.name) | translate}}\n        </div>\n        <ng-template #link>\n          <div [ngClass]=\"{addOpacity : element.options.currentlyDragging}\" libDropElement\n          [item]='element' class='draggable-item'>\n            <a [href]=\"element.options.href\" class='tree-link'>{{getTitleFromLocalized(element.name) | translate}}</a>\n          </div>\n        </ng-template>\n        <div class='d-flex buttons-bar' *ngIf=\"config.showActionButtons && element.options.showActionButtons && !element.options.disabled\">\n          <div class='d-flex'>\n            <button class=\"tree-btn add-btn\" *ngIf=\"config.showAddButtons\" (click)=\"submitAdd(null, element)\">\n              <fa-icon icon=\"plus\" [style.font-size.px]='config.setIconSize'></fa-icon>\n            </button>\n          </div>\n          <div class='d-flex'>\n            <button class=\"tree-btn edit-btn\" *ngIf=\"config.showRenameButtons\" (click)=\"enableRenameMode(element)\">\n              <fa-icon icon=\"edit\" [style.font-size.px]='config.setIconSize'></fa-icon>\n            </button>\n          </div>\n          <div class='d-flex'>\n            <button class=\"tree-btn delete-btn\" *ngIf=\"config.showDeleteButtons && element.options.showDeleteButton\" (click)=\"onSubmitDelete( element )\">\n              <fa-icon icon=\"times\" [style.font-size.px]='config.setIconSize'></fa-icon>\n            </button>\n          </div>\n        </div>\n        <div class='child-drop-place' [attr.data-id]='element.id'  libDropElement *ngIf='element.options.showDropChildZone && !element.options.disabled'>\n          <fa-icon icon=\"arrow-down\" [style.font-size.px]='config.setIconSize'></fa-icon>\n        </div>\n        <div class='show-hide-switch' *ngIf=\"config.enableExpandButtons && element.options.showExpandButton && element.children.length > 0 && !element.options.disabled\">\n          <div *ngIf=\"element.options.hideChildren; else visible\">\n            <button class='tree-btn show-btn' (click)='element.options.hideChildren = false'>\n              <fa-icon icon=\"plus\" [style.font-size.px]='config.setIconSize'></fa-icon>\n            </button>\n          </div>\n          <ng-template #visible>\n            <button class='tree-btn hide-btn' (click)='element.options.hideChildren = true'>\n              <fa-icon icon=\"minus\" [style.font-size.px]='config.setIconSize'></fa-icon>\n            </button>\n          </ng-template>\n        </div>\n      </div>\n      <ng-template #onEdit>\n        <div class='tree-title d-inline-flex'>\n          <form [formGroup]=\"renameForm\" class='d-flex' (submit)='submitRename(element)'>\n            <input type=\"text\" class='input-rename' formControlName=\"name\" libAutoFocus=\"true\" [style.font-size.px]='config.setFontSize'>\n          </form>\n          <div class='d-flex'>\n            <button class='tree-btn submit-btn' (click)='submitRename(element)'>\n              <fa-icon icon=\"check\" [style.font-size.px]='config.setIconSize'></fa-icon>\n            </button>\n            <button class='tree-btn delete-btn' (click)='onSubmitDelete(element)'>\n              <fa-icon icon=\"times\" [style.font-size.px]='config.setIconSize'></fa-icon>\n            </button>\n            <div class='error-edit-wrap' *ngIf=\"showError\">\n              {{config.validationText}}\n            </div>\n          </div>\n        </div>\n      </ng-template>\n      <div class=\"tree-content\" *ngIf=\"element.children && !element.options.hideChildren\">\n        <lib-ngx-tree-children [setItem]=\"child\" *ngFor='let child of element.children'></lib-ngx-tree-children>\n      </div>\n    </div>\n  </div>\n</div>\n"
            }] }
];
/** @nocollapse */
NgxTreeChildrenComponent.ctorParameters = () => [
    { type: NgxTreeService },
    { type: FormBuilder },
    { type: TranslateService }
];
NgxTreeChildrenComponent.propDecorators = {
    setItem: [{ type: Input }]
};

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class AutoFocusDirective {
    /**
     * @param {?} el
     */
    constructor(el) {
        this.el = el;
        this.focus = true;
    }
    /**
     * @return {?}
     */
    ngOnInit() {
        if (this.focus) {
            window.setTimeout((/**
             * @return {?}
             */
            () => {
                this.el.nativeElement.focus();
            }));
        }
    }
    /**
     * @param {?} condition
     * @return {?}
     */
    set autofocus(condition) {
        console.log("autofocus condition");
        console.log(condition);
        this.focus = condition !== false;
    }
}
AutoFocusDirective.decorators = [
    { type: Directive, args: [{
                selector: '[libAutoFocus]'
            },] }
];
/** @nocollapse */
AutoFocusDirective.ctorParameters = () => [
    { type: ElementRef }
];
AutoFocusDirective.propDecorators = {
    autofocus: [{ type: Input }]
};

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class DragElementsDirective {
    /**
     * @param {?} el
     * @param {?} treeService
     */
    constructor(el, treeService) {
        this.el = el;
        this.treeService = treeService;
    }
    /**
     * @return {?}
     */
    get draggable() {
        return this.draggableValue;
    }
    /*
            Event: ondragstart;
            Set item as dragging and call startDragging() from tree service.
            Emit OnDragStart on tree service.
        */
    /**
     * @param {?} event
     * @return {?}
     */
    onDragStart(event) {
        console.log("onDragStart (dragstart)");
        console.log(event);
        console.log("this.item");
        console.log(this.item);
        if (!event['dataTransfer']) {
            event['dataTransfer'] = {};
        }
        event['dataTransfer']['dropEffect'] = 'mobe';
        /** @type {?} */
        const eventObj = {
            event,
            target: this.item
        };
        this.treeService.isDragging = this.item;
        this.treeService.lastExpandState = this.item.options.hideChildren;
        this.item.options.hideChildren = true;
        this.item.options.currentlyDragging = true;
        // call service func
        this.treeService.startDragging(eventObj);
        event.stopPropagation();
    }
    /*
            Event: onDrag;
            trigger drag items and call onDragProcess() from tree service.
            Emit OnDrag on tree service.
        */
    /**
     * @param {?} event
     * @return {?}
     */
    onDrag(event) {
        console.log("onDrag (drag)");
        console.log(event);
        console.log("this.item");
        console.log(this.item);
        /** @type {?} */
        const eventObj = {
            event,
            target: this.item
        };
        this.treeService.onDragProcess(eventObj);
    }
    /*
            Event: ondragend;
            Call dragEndAction() from tree service.
            Emit OnDragEnd on tree service.
        */
    /**
     * @param {?} event
     * @return {?}
     */
    onDragEnd(event) {
        console.log("onDragEnd (dragend)");
        console.log(event);
        console.log("this.item");
        console.log(this.item);
        /** @type {?} */
        const eventObj = {
            event,
            target: this.item
        };
        this.item.options.hideChildren = this.treeService.lastExpandState;
        this.item.options.currentlyDragging = false;
        this.treeService.dragEndAction(eventObj);
        event.stopPropagation();
    }
}
DragElementsDirective.decorators = [
    { type: Directive, args: [{
                selector: '[libDragElement]'
            },] }
];
/** @nocollapse */
DragElementsDirective.ctorParameters = () => [
    { type: ElementRef },
    { type: NgxTreeService }
];
DragElementsDirective.propDecorators = {
    item: [{ type: Input }],
    draggableValue: [{ type: Input }],
    draggable: [{ type: HostBinding, args: ['draggable',] }],
    onDragStart: [{ type: HostListener, args: ['dragstart', ['$event'],] }],
    onDrag: [{ type: HostListener, args: ['drag', ['$event'],] }],
    onDragEnd: [{ type: HostListener, args: ['dragend', ['$event'],] }]
};

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
class DropElementsDirective {
    /**
     * @param {?} el
     * @param {?} treeService
     */
    constructor(el, treeService) {
        this.el = el;
        this.treeService = treeService;
        this.drop = new EventEmitter();
    }
    /*
            Event: onallowdrop;
            Call onDragOver() from tree service.
            Emit onAllowDrop on tree service.
        */
    /**
     * @param {?} event
     * @return {?}
     */
    onDragOver(event) {
        /** @type {?} */
        const eventObj = {
            event,
            target: this.item
        };
        this.treeService.onDragOver(eventObj);
        event.preventDefault();
    }
    /*
            Event: ondrop;
            Call onDropItem() from tree service.
            Emit OnDrop on tree service.
        */
    /**
     * @param {?} event
     * @return {?}
     */
    onDrop(event) {
        /** @type {?} */
        const dragItem = this.treeService.isDragging;
        /** @type {?} */
        const eventObj = {
            event,
            target: this.item
        };
        dragItem.options.hideChildren = this.treeService.lastExpandState;
        dragItem.options.currentlyDragging = false;
        if (dragItem !== eventObj.target) {
            this.treeService.onDropItem(eventObj);
        }
        event.preventDefault();
    }
    /*s
        Event: ondragenter;
        Detect event where draggable element enter in drop zone.
        Call enterDropZone() from tree service.
        Emit onDragEnter.
        */
    /**
     * @param {?} event
     * @return {?}
     */
    onDragEnter(event) {
        /** @type {?} */
        const eventObj = {
            event,
            target: this.item
        };
        this.treeService.enterDropZone(eventObj);
    }
    /*
            Event: ondragleave;
            Detect event where draggable element leave drop zone.
            Call leaveDropZone() from tree service.
            Emit onDragLeave.
        */
    /**
     * @param {?} event
     * @return {?}
     */
    onDragLeave(event) {
        // emit events
        /** @type {?} */
        const eventObj = {
            event,
            target: this.item
        };
        // code
        this.treeService.leaveDropZone(eventObj);
    }
}
DropElementsDirective.decorators = [
    { type: Directive, args: [{
                selector: '[libDropElement]'
            },] }
];
/** @nocollapse */
DropElementsDirective.ctorParameters = () => [
    { type: ElementRef },
    { type: NgxTreeService }
];
DropElementsDirective.propDecorators = {
    item: [{ type: Input }],
    drop: [{ type: Output }],
    onDragOver: [{ type: HostListener, args: ['dragover', ['$event'],] }],
    onDrop: [{ type: HostListener, args: ['drop', ['$event'],] }],
    onDragEnter: [{ type: HostListener, args: ['dragenter', ['$event'],] }],
    onDragLeave: [{ type: HostListener, args: ['dragleave', ['$event'],] }]
};

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/**
 * @param {?} http
 * @return {?}
 */
function HttpLoaderFactory(http) {
    return new TranslateHttpLoader(http, '/assets/i18n/', `.json`);
}
library.add(faCoffee, faPlus, faEdit, faMinus, faTimes, faCheck, faArrowDown);
class NgxTreeLibModule {
}
NgxTreeLibModule.decorators = [
    { type: NgModule, args: [{
                imports: [
                    CommonModule,
                    ReactiveFormsModule,
                    FontAwesomeModule,
                    HttpClientModule,
                    TranslateModule.forRoot({
                        loader: {
                            provide: TranslateLoader,
                            useFactory: HttpLoaderFactory,
                            deps: [HttpClient]
                        }
                    }),
                ],
                declarations: [
                    AutoFocusDirective,
                    DragElementsDirective,
                    DropElementsDirective,
                    NgxTreeParentComponent,
                    NgxTreeChildrenComponent
                ],
                exports: [
                    AutoFocusDirective,
                    DragElementsDirective,
                    DropElementsDirective,
                    NgxTreeParentComponent,
                    NgxTreeChildrenComponent
                ]
            },] }
];

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */

/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */

export { NgxTreeService, NgxTreeParentComponent, NgxTreeChildrenComponent, AutoFocusDirective, DragElementsDirective, DropElementsDirective, HttpLoaderFactory, NgxTreeLibModule };

//# sourceMappingURL=ngx-tree-lib.js.map