/**
 * @license
 * Copyright Endlessjs. All Rights Reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 */
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
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 __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Injectable } from '@angular/core';
import { Location } from '@angular/common';
import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs';
import { share } from 'rxjs/operators';
import { isFragmentContain, isFragmentEqual, isUrlPathContain, isUrlPathEqual } from './url-matching-helpers';
var itemClick$ = new Subject();
var addItems$ = new ReplaySubject(1);
var navigateHome$ = new ReplaySubject(1);
var getSelectedItem$ = new ReplaySubject(1);
var itemSelect$ = new ReplaySubject(1);
var itemHover$ = new ReplaySubject(1);
var submenuToggle$ = new ReplaySubject(1);
var collapseAll$ = new ReplaySubject(1);
// TODO: check if we need both URL and LINK
/**
 *
 *
 * Menu Item options example
 * @stacked-example(Menu Link Parameters, menu/menu-link-params.component)
 *
 *
 */
var ElMenuItem = /** @class */ (function () {
    function ElMenuItem() {
        /**
         * Item is selected when partly or fully equal to the current url
         * @type {string}
         */
        this.pathMatch = 'full';
    }
    /**
     * @returns item parents in top-down order
     */
    ElMenuItem.getParents = function (item) {
        var parents = [];
        var parent = item.parent;
        while (parent) {
            parents.unshift(parent);
            parent = parent.parent;
        }
        return parents;
    };
    ElMenuItem.isParent = function (item, possibleChild) {
        return possibleChild.parent
            ? possibleChild.parent === item || this.isParent(item, possibleChild.parent)
            : false;
    };
    return ElMenuItem;
}());
export { ElMenuItem };
// TODO: map select events to router change events
// TODO: review the interface
/**
 *
 *
 * Menu Service. Allows you to listen to menu events, or to interact with a menu.
 * @stacked-example(Menu Service, menu/menu-service.component)
 *
 *
 */
var ElMenuService = /** @class */ (function () {
    function ElMenuService() {
    }
    /**
     * Add items to the end of the menu items list
     * @param {List<ElMenuItem>} items
     * @param {string} tag
     */
    ElMenuService.prototype.addItems = function (items, tag) {
        addItems$.next({ tag: tag, items: items });
    };
    /**
     * Collapses all menu items
     * @param {string} tag
     */
    ElMenuService.prototype.collapseAll = function (tag) {
        collapseAll$.next({ tag: tag });
    };
    /**
     * Navigate to the home menu item
     * @param {string} tag
     */
    ElMenuService.prototype.navigateHome = function (tag) {
        navigateHome$.next({ tag: tag });
    };
    /**
     * Returns currently selected item. Won't subscribe to the future events.
     * @param {string} tag
     * @returns {Observable<{tag: string; item: ElMenuItem}>}
     */
    ElMenuService.prototype.getSelectedItem = function (tag) {
        var listener = new BehaviorSubject(null);
        getSelectedItem$.next({ tag: tag, listener: listener });
        return listener.asObservable();
    };
    ElMenuService.prototype.onItemClick = function () {
        return itemClick$.pipe(share());
    };
    ElMenuService.prototype.onItemSelect = function () {
        return itemSelect$.pipe(share());
    };
    ElMenuService.prototype.onItemHover = function () {
        return itemHover$.pipe(share());
    };
    ElMenuService.prototype.onSubmenuToggle = function () {
        return submenuToggle$.pipe(share());
    };
    ElMenuService = __decorate([
        Injectable()
    ], ElMenuService);
    return ElMenuService;
}());
export { ElMenuService };
var ElMenuInternalService = /** @class */ (function () {
    function ElMenuInternalService(location) {
        this.location = location;
    }
    ElMenuInternalService.prototype.prepareItems = function (items) {
        var _this = this;
        var defaultItem = new ElMenuItem();
        items.forEach(function (i) {
            _this.applyDefaults(i, defaultItem);
            _this.setParent(i);
        });
    };
    ElMenuInternalService.prototype.selectFromUrl = function (items, tag, collapseOther) {
        if (collapseOther === void 0) { collapseOther = false; }
        var selectedItem = this.findItemByUrl(items);
        if (selectedItem) {
            this.selectItem(selectedItem, items, collapseOther, tag);
        }
    };
    ElMenuInternalService.prototype.selectItem = function (item, items, collapseOther, tag) {
        if (collapseOther === void 0) { collapseOther = false; }
        var unselectedItems = this.resetSelection(items);
        var collapsedItems = collapseOther ? this.collapseItems(items) : [];
        for (var _i = 0, _a = ElMenuItem.getParents(item); _i < _a.length; _i++) {
            var parent_1 = _a[_i];
            parent_1.selected = true;
            // emit event only for items that weren't selected before ('unselectedItems' contains items that were selected)
            if (!unselectedItems.includes(parent_1)) {
                this.itemSelect(parent_1, tag);
            }
            var wasNotExpanded = !parent_1.expanded;
            parent_1.expanded = true;
            var i = collapsedItems.indexOf(parent_1);
            // emit event only for items that weren't expanded before.
            // 'collapsedItems' contains items that were expanded, so no need to emit event.
            // in case 'collapseOther' is false, 'collapsedItems' will be empty,
            // so also check if item isn't expanded already ('wasNotExpanded').
            if (i === -1 && wasNotExpanded) {
                this.submenuToggle(parent_1, tag);
            }
            else {
                collapsedItems.splice(i, 1);
            }
        }
        item.selected = true;
        // emit event only for items that weren't selected before ('unselectedItems' contains items that were selected)
        if (!unselectedItems.includes(item)) {
            this.itemSelect(item, tag);
        }
        // remaining items which wasn't expanded back after expanding all currently selected items
        for (var _b = 0, collapsedItems_1 = collapsedItems; _b < collapsedItems_1.length; _b++) {
            var collapsedItem = collapsedItems_1[_b];
            this.submenuToggle(collapsedItem, tag);
        }
    };
    ElMenuInternalService.prototype.collapseAll = function (items, tag, except) {
        var collapsedItems = this.collapseItems(items, except);
        for (var _i = 0, collapsedItems_2 = collapsedItems; _i < collapsedItems_2.length; _i++) {
            var item = collapsedItems_2[_i];
            this.submenuToggle(item, tag);
        }
    };
    ElMenuInternalService.prototype.onAddItem = function () {
        return addItems$.pipe(share());
    };
    ElMenuInternalService.prototype.onNavigateHome = function () {
        return navigateHome$.pipe(share());
    };
    ElMenuInternalService.prototype.onCollapseAll = function () {
        return collapseAll$.pipe(share());
    };
    ElMenuInternalService.prototype.onGetSelectedItem = function () {
        return getSelectedItem$.pipe(share());
    };
    ElMenuInternalService.prototype.itemHover = function (item, tag) {
        itemHover$.next({ tag: tag, item: item });
    };
    ElMenuInternalService.prototype.submenuToggle = function (item, tag) {
        submenuToggle$.next({ tag: tag, item: item });
    };
    ElMenuInternalService.prototype.itemSelect = function (item, tag) {
        itemSelect$.next({ tag: tag, item: item });
    };
    ElMenuInternalService.prototype.itemClick = function (item, tag) {
        itemClick$.next({ tag: tag, item: item });
    };
    /**
     * Unselect all given items deeply.
     * @param items array of items to unselect.
     * @returns items which selected value was changed.
     */
    ElMenuInternalService.prototype.resetSelection = function (items) {
        var unselectedItems = [];
        for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
            var item = items_1[_i];
            if (item.selected) {
                unselectedItems.push(item);
            }
            item.selected = false;
            if (item.children) {
                unselectedItems.push.apply(unselectedItems, this.resetSelection(item.children));
            }
        }
        return unselectedItems;
    };
    /**
     * Collapse all given items deeply.
     * @param items array of items to collapse.
     * @param except menu item which shouldn't be collapsed, also disables collapsing for parents of this item.
     * @returns items which expanded value was changed.
     */
    ElMenuInternalService.prototype.collapseItems = function (items, except) {
        var collapsedItems = [];
        for (var _i = 0, items_2 = items; _i < items_2.length; _i++) {
            var item = items_2[_i];
            if (except && (item === except || ElMenuItem.isParent(item, except))) {
                continue;
            }
            if (item.expanded) {
                collapsedItems.push(item);
            }
            item.expanded = false;
            if (item.children) {
                collapsedItems.push.apply(collapsedItems, this.collapseItems(item.children));
            }
        }
        return collapsedItems;
    };
    ElMenuInternalService.prototype.applyDefaults = function (item, defaultItem) {
        var _this = this;
        var menuItem = __assign({}, item);
        Object.assign(item, defaultItem, menuItem);
        item.children && item.children.forEach(function (child) {
            _this.applyDefaults(child, defaultItem);
        });
    };
    ElMenuInternalService.prototype.setParent = function (item) {
        var _this = this;
        item.children && item.children.forEach(function (child) {
            child.parent = item;
            _this.setParent(child);
        });
    };
    /**
     * Find deepest item which link matches current URL path.
     * @param items array of items to search in.
     * @returns found item of undefined.
     */
    ElMenuInternalService.prototype.findItemByUrl = function (items) {
        var _this = this;
        var selectedItem;
        items.some(function (item) {
            if (item.children) {
                selectedItem = _this.findItemByUrl(item.children);
            }
            if (!selectedItem && _this.isSelectedInUrl(item)) {
                selectedItem = item;
            }
            return selectedItem;
        });
        return selectedItem;
    };
    ElMenuInternalService.prototype.isSelectedInUrl = function (item) {
        var exact = item.pathMatch === 'full';
        var link = item.link;
        var isSelectedInPath = exact
            ? isUrlPathEqual(this.location.path(), link)
            : isUrlPathContain(this.location.path(), link);
        if (isSelectedInPath && item.fragment != null) {
            return exact
                ? isFragmentEqual(this.location.path(true), item.fragment)
                : isFragmentContain(this.location.path(true), item.fragment);
        }
        return isSelectedInPath;
    };
    ElMenuInternalService = __decorate([
        Injectable(),
        __metadata("design:paramtypes", [Location])
    ], ElMenuInternalService);
    return ElMenuInternalService;
}());
export { ElMenuInternalService };
//# sourceMappingURL=menu.service.js.map