/*
 * Copyright (C) 2018 Robert Bosch GmbH Copyright (C) 2018 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import {
  AfterViewInit,
  Component,
  ComponentRef,
  ContentChild,
  ElementRef,
  EventEmitter,
  HostBinding,
  Injector,
  Input,
  NgZone,
  OnChanges,
  OnDestroy,
  OnInit,
  Output,
  SimpleChanges,
  ViewChild,
} from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { fromEvent, merge, Observable, of, Subject } from 'rxjs';
import { debounceTime, delay, distinctUntilChanged, filter, map, startWith, takeUntil } from 'rxjs/operators';
import { BOSCH_BREAKPOINTS } from '../../core/core-configuration/bosch-breakpoints';
import { BciSharedIntl } from '../shared-intl';
import { CommandbarActionsComponent } from './actions/actions.component';
import { CommandbarButtonComponent } from './button/commandbar-button.component';
import { CommandbarInlinefiltersComponent } from './inlinefilters/commandbar-inlinefilters.component';
import { CommandbarItemVisibilityService } from './item/commandbar-item-visibility.service';
import { CommandbarItemComponent } from './item/commandbar-item.component';
import {
  COMMANDBAR_OPTIONSMENU_DATA,
  CommandbarOptionsmenuComponent,
} from './optionsmenu/commandbar-optionsmenu.component';
import { CommandbarOptionsmenuConfig } from './optionsmenu/commandbar-optionsmenu.model';
import { CommandbarQuickfiltersComponent } from './quickfilters/commandbar-quickfilters.component';
import { MatToolbar } from '@angular/material/toolbar';
import { CommandbarAddMenuComponent, CommandbarAddMenuItem, COMMANDBAR_ADDMENU_DATA } from './addmenu';
import { BooleanInput, coerceBooleanProperty } from "@angular/cdk/coercion";

@Component({
  selector: 'bci-commandbar',
  templateUrl: './commandbar.component.html',
  styleUrls: ['./commandbar.component.scss'],
  providers: [CommandbarItemVisibilityService],
})
export class CommandbarComponent implements OnInit, OnDestroy, AfterViewInit, OnChanges {
  

  @HostBinding('class.active') @Input() active = false;

  /**
   * Number of matched / shown items
   */
  @Input() itemCount: number;

  /**
   * Number of selected items
   */
  @Input() selectedItemCount: number;

  /**
   * Flag to indicate whether the search-box is being displayed
   */
  @Input() showSearch = true;

  /**
   * Flag to indicate whether the search-box has a tooltip showing the same content as
   * the {@link BciSharedIntl#search search placeholder}. This is useful in case
   * the placeholder is longer then a word and describes complex search behavior. Default
   * is `false`.
   */
  @Input() get showSearchTooltip() {
    return this._showSearchTooltip;
  }

  set showSearchTooltip(value: BooleanInput) {
    this._showSearchTooltip = coerceBooleanProperty(value);
  }

  private _showSearchTooltip = false;

  /**
   * Flag to indicate whether the filter-icon is being displayed
   */
  @Input() showFilter = false;

  /**
   * Flag to indicate whether the sort-icon is being displayed
   */
  @Input() showSort = false;

  /**
   * Flag to indicate whether the sort-icon is active (descending)
   */
  @Input() sortDirection = -1;

  /**
   * Flag to indicate whether the add button is being displayed
   */
  @Input() showAdd = false;

  /**
   * Optional payload for the add button that will be displayed in a tooltip
   */
  @Input() addButtonPayload: CommandbarAddMenuItem[];

  /**
   * Optional tooltip to describe the add button action.
   */
  @Input() addButtonTooltip = '';

  /**
   * Flag to indicate whether the add button is disabled.
   */
  @Input() disableAddButton = false;

  /**
   * Integer value to display the number of selected Filters
   */
  @Input() filterCount = 0;

  /**
   * Event to get notified when any filter has changed
   */
  @Input() filterCountChange: Observable<void>;

  /**
   * Input parameter to make the filter-icon configurable from superordinated components
   */
  @Input() sortIcon = 'Bosch-Ic-sort-alphabetically';

  /**
   * Input parameter to activate additional margin to the left (16px) if needed for the add button
   */
  @Input() additionalAddBtnMargin = false;

  /**
   * indicator to override the search field breakpoint
   * default is false
   * if activated it makes it possible for the search field to stay visible below 480px width of the commandbar
   */
  @Input() get overrideSearchFieldBreakpoint() {
    return this._overrideSearchFieldBreakpoint;
  }

  set overrideSearchFieldBreakpoint(value: BooleanInput) {
    this._overrideSearchFieldBreakpoint = coerceBooleanProperty(value);
  }

  private _overrideSearchFieldBreakpoint = false;

  /**
   * The event emitter which propagates the text value of the search-box to subordinated components
   */
  @Output() search = new EventEmitter<string>();

  /**
   * The event emitter which propagates the click-event on the filter-icon to superordinated components
   */
  @Output() clickFilter = new EventEmitter();

  /**
   * The event emitter which propagates the click-event on the sort-icon to superordinated components
   */
  @Output() clickSort = new EventEmitter();

  /**
   * The event emitter which propagates the click-event on the add button to superordinated components
   */
  @Output() clickAdd = new EventEmitter();

  /**
   * Subject being used to search immediately
   */
  submitSearch = new Subject<string>();

  searchForm: FormGroup;
  displayItemCount = true;
  displaySearchbarFullspace = false;
  displayForSmallScreen = false;
  displayInlineFilters = true;
  displayQuickFilters = true;
  displayMenuButton = true;
  displayFillSpace = true;
  displayActions = true;
  displayFilter = true;
  displaySort = true;
  focusedSearchInput: boolean;
  hiddenActiveFilters = 0;
  hasHiddenFilters = false;
  tooltipText: string;
  filterOrSortButtonVisible: boolean;
  filterButtonVisibleCache: boolean;
  sortButtonVisibleCache: boolean;
  
  isMobile$: Observable<boolean>;
  /**
   * references the commadbar filter button element shown in the command bar
   */
  @ViewChild('commandbarFilterButton', { read: CommandbarItemComponent })
  commandbarFilterButton: CommandbarItemComponent;
  /**
   * refernces the commandbar fillSpace element shown between the actions and sort+filter buttons
   */
  @ViewChild('fillSpace', { read: ElementRef }) fillSpaceElement: ElementRef;

  /**
   * refernces the commandbar toolbar element
   */
  @ViewChild(MatToolbar, { read: ElementRef, static: false }) toolbarElement: ElementRef;

  /**
   * references the `bci-commandbar-inlinefilters` element shown in the command bar
   */
  @ContentChild(CommandbarInlinefiltersComponent, { static: true })
  private commandbarInlinefiltersElement: CommandbarInlinefiltersComponent;
  /**
   * references the `bci-commandbar-quickfilters` element shown in the command bar
   */
  @ContentChild(CommandbarQuickfiltersComponent, { static: true })
  private commandbarQuickfiltersElement: CommandbarQuickfiltersComponent;
  /**
   * references the `bci-commandbar-actions` element shown in the command bar
   */
  @ContentChild(CommandbarActionsComponent, { static: true })
  private commandbarActionsComponent: CommandbarActionsComponent;
  /**
   * references the options menu button shown in the command bar
   */
  @ViewChild('commandbarOptionsMenu', { read: ElementRef, static: true }) private commandbarOptionsMenu: ElementRef;
  /**
   * references the commandbar sort button element shown in the command bar
   */
  @ViewChild('commandbarSortButton', { read: CommandbarItemComponent })
  commandbarSortButton: CommandbarItemComponent;

  /**
   * reference to the commandbar add button
   */
  @ViewChild('commandbarAddBtn', { read: ElementRef, static: true }) private commandbarAddBtn: ElementRef;

  private componentDestroyed$ = new Subject<void>();
  private resizeObserver: ResizeObserver;
  private containerWidth: number;
  private fillWidth = 0;
  private commandbarElements = [];
  private commandbarElementsReversed = [];
  private moreOptionsRef: OverlayRef;
  private moreOptionsComponent: ComponentRef<CommandbarOptionsmenuComponent>;
  private readonly COMMAND_BAR_EXTRA_SMALL = BOSCH_BREAKPOINTS.XS;
  private readonly fillMinWidth = 1;  
  checkScreenSize = (): boolean => document.body.offsetWidth < 480;

  constructor(
    public intl: BciSharedIntl,
    private fb: FormBuilder,
    private overlay: Overlay,
    private injector: Injector,
    private ngZone: NgZone
  ) {
    this.createSearchForm();
  }

  /**
   * String Input for pre-populating the search field
   */
  @Input()
  set searchTerm(value: string) {
    this.searchForm.controls.search.setValue(value);
    // trigger search immediately (alternative would be to used delay/timeout 0 to put after form field validation logic)
    this.searchSubmit();
  }

  ngOnInit(): void {
    this.displayFilter = this.showFilter;
    this.displaySort = this.showSort;

    this.filterOrSortButtonVisible = this.showFilter || this.showSort;
    this.filterButtonVisibleCache = this.showFilter;
    this.sortButtonVisibleCache = this.showSort;

    merge(
      this.submitSearch,
      of(this.searchForm.controls.search.value as string).pipe(
        filter((value) => value !== undefined && value.length > 0)
      ),
      this.searchForm.controls.search.valueChanges.pipe(takeUntil(this.componentDestroyed$), debounceTime(300))
    )
      .pipe(
        map((value) => (!!value ? value.trim() : value)),
        distinctUntilChanged()
      )
      .subscribe((searchString) => this.search.emit(searchString));
    if (this.filterCountChange) {
      this.filterCountChange.pipe(delay(100)).subscribe(() => {
        this.countHiddenActiveFilters();
        if (this.showSort || this.showFilter) {
          this.ngZone.run(() => this.setCustomStylingIfSortAndFilterAreNotDisplayed());
        }
      });
    }

    const screenSizeChanged$ = fromEvent(window, 'resize').pipe(map(this.checkScreenSize));
    this.isMobile$ = screenSizeChanged$.pipe(startWith(this.checkScreenSize()));
  }

  searchSubmit() {
    this.submitSearch.next(this.searchForm.controls.search.value);
  }

  removeFilter() {
    this.searchForm.controls.search.setValue('');
    this.searchSubmit();
  }

  ngOnDestroy() {
    this.componentDestroyed$.next();
    this.componentDestroyed$.complete();
    this.resizeObserver.disconnect();
  }

  ngOnChanges(changes: SimpleChanges) {
    if(changes.selectedItemCount)
    this.tooltipText = this.selectedItemCount ? (this.selectedItemCount + '/'+ (this.itemCount > -1 && this.itemCount + ' items')) : (this.itemCount > -1 && this.itemCount + 'items');
  }

  // start observing resizes only when all view elements are initialized
  ngAfterViewInit() {
    this.setAvailableCommandbarComponents();
    this.observeResizeChanges();
  }

  // show big search bar and hide all other buttons

  filter() {
    if (this.moreOptionsRef && this.moreOptionsRef.hasAttached()) {
      this.moreOptionsRef.dispose();
    }
    this.clickFilter.emit();
  }

  /**
   * To set styling in mobile view between search bar and add icon if no filters exist
   * @returns boolean
   */
  updateSearchStyling() {
    return (this.displayForSmallScreen && !this.displayInlineFilters && !this.displayQuickFilters &&
    !this.showFilter && !this.showSort && !this.displayActions && this.showAdd)
  }

  // hide big search bar and show other buttons if possible

  sort() {
    if (this.moreOptionsRef && this.moreOptionsRef.hasAttached()) {
      this.moreOptionsRef.dispose();
    }
    this.clickSort.emit();
  }

  // show big search bar and hide all other buttons
  // when in small screen mode
  searchbarClick() {
    if (this.shouldShowSmallSearchbar) {
      this.displayFillSpace = false;
      this.displaySearchbarFullspace = true;
      this.displayItemCount = false;
      this.displayMenuButton = false;
    }
  }

  // hide big search bar and show other buttons if possible
  searchbarClickOutside() {
    this.displayFillSpace = true;
    this.displaySearchbarFullspace = false;
    this.displayItemCount = true;
    this.displayMenuButton = true;
  }

  // handle what happens when user clicks on more options button
  openOptionsMenu() {
    const positionStrategy = this.overlay
      .position()
      .flexibleConnectedTo(this.commandbarOptionsMenu)
      .withPush(false)
      .withPositions([
        {
          originX: 'center',
          offsetX: 15,
          originY: 'bottom',
          overlayX: 'end',
          overlayY: 'top',
          panelClass: !this.showAdd ? 'bci-commandbar-options-menu-bottom': 'bci-commandbar-options-menu-bottom-with-Add',
        },
        {
          originX: 'center',
          offsetX: 15,
          originY: 'top',
          overlayX: 'end',
          overlayY: 'bottom',
          panelClass: !this.showAdd ? 'bci-commandbar-options-menu-top': 'bci-commandbar-options-menu-top-with-Add',
        },
      ]);
      
    this.moreOptionsRef = this.overlay.create({
      hasBackdrop: true,
      backdropClass: 'cdk-overlay-transparent-backdrop',
      positionStrategy,
      scrollStrategy: this.overlay.scrollStrategies.reposition(),
    });
    this.moreOptionsRef.backdropClick().subscribe(() => {
      this.moreOptionsRef.dispose();
      this.handleItemHiding();
    });

    this.injectMoreOptionsItems();
  }

  // Provided external method to close the more options tooltip
  closeOptionsMenu() {
    if (this.moreOptionsRef && this.moreOptionsRef.hasAttached()) {
      this.moreOptionsRef.dispose();
      this.handleItemHiding();
    }
  }

  onAdd() {
    if (!this.addButtonPayload || !this.addButtonPayload.length) {
      this.clickAdd.emit(null);
    } else {
      const positionStrategy = this.overlay
        .position()
        .flexibleConnectedTo(this.commandbarAddBtn)
        .withPush(false)
        .withPositions([
          {
            originX: 'center',
            offsetX: 20,
            originY: 'bottom',
            offsetY: 16,
            overlayX: 'end',
            overlayY: 'top',
            panelClass: ['bci-commandbar-options-menu-bottom', 'bci-commandbar-add-menu'],
          },
          {
            originX: 'center',
            offsetX: 20,
            originY: 'top',
            offsetY: -16,
            overlayX: 'end',
            overlayY: 'bottom',
            panelClass: ['bci-commandbar-options-menu-top', 'bci-commandbar-add-menu'],
          },
        ]);

      const addMenuRef = this.overlay.create({
        hasBackdrop: true,
        backdropClass: 'cdk-overlay-transparent-backdrop',
        positionStrategy,
        scrollStrategy: this.overlay.scrollStrategies.reposition(),
      });
      addMenuRef.backdropClick().subscribe(() => {
        addMenuRef.dispose();
      });

      const portalInjector = Injector.create({
        providers: [{ provide: COMMANDBAR_ADDMENU_DATA, useValue: this.addButtonPayload }],
        parent: this.injector,
      });

      const optionsMenuPortal = new ComponentPortal(CommandbarAddMenuComponent, null, portalInjector);

      addMenuRef.attach(optionsMenuPortal).instance.closeOptionsMenu.subscribe((type: string) => {
        this.clickAdd.emit(type);
        addMenuRef.dispose();
      });
    }
  }

  // Determines if the passed element is overflowing its bounds,
  // either vertically or horizontally.
  // Will temporarily modify the "overflow" style to detect this
  // if necessary.
  isTextOverflow(el: HTMLElement): boolean {
    const curOverflow = el.style.overflow;

    if (!curOverflow || curOverflow === "visible")
      el.style.overflow = "hidden";

    const isTextOverflow = el.clientWidth < el.scrollWidth
      || el.clientHeight < el.scrollHeight;

    el.style.overflow = curOverflow;
    return isTextOverflow;
  }

  private get shouldShowSmallSearchbar(): boolean {
    return this.containerWidth <= this.COMMAND_BAR_EXTRA_SMALL;
  }

  private hostSizeChanged(containerWidth: number) {
    this.containerWidth = containerWidth;

    const overriddenBreakpoint = this.getOverriddenBreakpoint();

    // show/hide search field overridden breakpoint
    if (this.overrideSearchFieldBreakpoint) {
      if (this.overrideSearchFieldBreakpoint && containerWidth <= overriddenBreakpoint) {
        this.hideSearchField();
      } else {
        this.searchbarClickOutside();
        this.showSearchField();
      }
      return;
    }

    // show/hide search field default
    if (containerWidth <= this.COMMAND_BAR_EXTRA_SMALL && !this.overrideSearchFieldBreakpoint) {
      this.hideSearchField();
    } else {
      this.searchbarClickOutside();
      this.showSearchField();
    }
  }
  
  /**
   * determines which breakpoint is to use
   * default is 380 if only the search field is shown
   * if the add button or the option menu is shown the breakpoint is 400
   * if the add button and the option menu are shown the breakpoint is 480
   * @returns breakpoint value in pixel
   */
  private getOverriddenBreakpoint(): number {
    if(this.displayMenuButton && this.hasHiddenFilters && this.showAdd) {
      return this.COMMAND_BAR_EXTRA_SMALL;
    }
    if (this.showAdd || (this.displayMenuButton && this.hasHiddenFilters)) {
      return this.COMMAND_BAR_EXTRA_SMALL - 80;
    }
    return this.COMMAND_BAR_EXTRA_SMALL - 100;
  }

  /**
   * sets configuration to hide search field on a width below 480px
   */
  private hideSearchField() {
    this.displayForSmallScreen = true;
    this.displayInlineFilters = false;
    this.displayQuickFilters = false;
    this.displayActions = false;
    this.displayFilter = false;
    this.displaySort = false;
  }
  
  /**
   * sets configuration to show search field on a width higher than 480px
   */
  private showSearchField() {
    this.displayForSmallScreen = false;
    this.displaySearchbarFullspace = false;
    this.displayInlineFilters = true;
    this.displayQuickFilters = true;
    this.displayActions = true;
    this.displayFilter = true;
    this.displaySort = true;
  }

  private observeResizeChanges() {
    this.resizeObserver = new ResizeObserver((entries) => {
      window.requestAnimationFrame(() => {
        entries.forEach((entry) => {
          // act when parent container is changing it's size
          if (entry.target === this.toolbarElement.nativeElement) {
            this.ngZone.run(() => {
              // update the data of the component 
              this.hasHiddenElements();  
            }); 
            this.hostSizeChanged(entry.contentRect.width);
            this.handleItemHiding();
          }
          if (entry.target === this.fillSpaceElement.nativeElement) {
            if (this.moreOptionsRef && this.moreOptionsRef.hasAttached()) {
              return;
            }
            this.ngZone.run(() => {
              // update the data of the component 
              this.hasHiddenElements();  
            }); 
            this.handleItemHiding();
          }
        });
      });
    });
    
    // observe when parent container is changing it's size
    this.resizeObserver.observe(this.toolbarElement.nativeElement);
    this.resizeObserver.observe(this.fillSpaceElement.nativeElement);
  }

  private handleItemHiding() {
    this.fillWidth = this.fillSpaceElement.nativeElement.offsetWidth;
    if (this.fillWidth >= this.fillMinWidth) {
      const visibleElement = this.getFirstAvailableElement(false);
      if (visibleElement) {
        if (visibleElement instanceof CommandbarButtonComponent && this.fillWidth > visibleElement.elementWidth) {
          visibleElement.render = true;
          this.handleMoreOptionsItemInjectionOnResize();
          visibleElement.triggerChangeDetection();
        } else if (!(visibleElement instanceof CommandbarButtonComponent)) {
          visibleElement.updateView(this.fillWidth);
        }
      }
    }
    this.fillWidth = this.fillSpaceElement.nativeElement.offsetWidth;
    if (this.fillWidth < this.fillMinWidth) {
      let visibleElement = this.getFirstAvailableElement(true);
      while (this.fillWidth < this.fillMinWidth && visibleElement) {
        if (visibleElement instanceof CommandbarButtonComponent) {
          visibleElement.render = false;
          this.handleMoreOptionsItemInjectionOnResize();
          visibleElement.triggerChangeDetection();
        } else if (!(visibleElement instanceof CommandbarButtonComponent)) {
          visibleElement.updateView(this.fillWidth);
        }
        visibleElement = this.getFirstAvailableElement(true);
        this.fillWidth = this.fillSpaceElement.nativeElement.offsetWidth;
      }
    }

    if (this.hasHiddenFilters) {
      this.countHiddenActiveFilters();
      if (this.showSort || this.showFilter) {
        this.ngZone.run(() => this.setCustomStylingIfSortAndFilterAreNotDisplayed());
      }
    } else if (!this.hasHiddenFilters) {
      if (this.moreOptionsRef && this.moreOptionsRef.hasAttached()) {
        this.moreOptionsRef.dispose();
      }
    }
  }

  private countHiddenActiveFilters() {
    this.hiddenActiveFilters = 0;
    if (this.commandbarFilterButton && !this.commandbarFilterButton.render) {
      this.hiddenActiveFilters = this.filterCount;
    }
    if (this.commandbarQuickfiltersElement && this.commandbarQuickfiltersElement.hiddenItems.length) {
      this.commandbarQuickfiltersElement.hiddenItems.forEach((hiddenItem) => {
        const button: HTMLButtonElement =
          hiddenItem.template.elementRef.nativeElement.parentElement.firstElementChild.firstElementChild;
        if (button && button.classList.contains('commandbar-button-active')) {
          this.hiddenActiveFilters = this.hiddenActiveFilters + 1;
        }
      });
    }
    if (this.commandbarSortButton && !this.commandbarSortButton.render) {
      const sortButtonClassList: DOMTokenList =
        this.commandbarSortButton.template.elementRef.nativeElement.parentElement.classList;
      if (sortButtonClassList.contains('commandbar-button-active')) {
        this.hiddenActiveFilters++;
      }
    }
    if (this.commandbarInlinefiltersElement && this.commandbarInlinefiltersElement.hiddenItems.length) {
      this.commandbarInlinefiltersElement.hiddenItems.forEach((hiddenItem) => {
        if (hiddenItem.active) {
          this.hiddenActiveFilters++;
        }
      });
    }
  }

  /**
   * activates custom styling class if sort and filter buttons are not available
   * the custom styling adds a gap between group search and filters and chips (if they follow the group)
   */
  private setCustomStylingIfSortAndFilterAreNotDisplayed() {
    if (!this.showSort && !this.showFilter) {
      return;
    }

    this.filterButtonVisibleCache = this.commandbarFilterButton?.render;
    this.sortButtonVisibleCache = this.commandbarSortButton?.render;
    if (!this.commandbarFilterButton?.render &&
      !this.commandbarSortButton?.render &&
      this.commandbarFilterButton?.render === this.filterButtonVisibleCache &&
      this.commandbarSortButton?.render === this.sortButtonVisibleCache) {
      this.filterOrSortButtonVisible = false;
    } else if (
      this.commandbarFilterButton?.render === this.filterButtonVisibleCache &&
      this.commandbarSortButton?.render === this.sortButtonVisibleCache
    ) {
      this.filterOrSortButtonVisible = true;
    }
  }

  private getFirstAvailableElement(visible: boolean) {
    if (visible) {
      return this.commandbarElements.find(
        (elem) =>
          (elem instanceof CommandbarButtonComponent && elem.render) ||
          (!(elem instanceof CommandbarButtonComponent) && elem.hasVisibleItems())
      );
    } else {
      return this.commandbarElementsReversed.find(
        (elem) =>
          (elem instanceof CommandbarButtonComponent && !elem.render) ||
          (!(elem instanceof CommandbarButtonComponent) && elem.hasHiddenItems())
      );
    }
  }

  private handleMoreOptionsItemInjectionOnResize() {
    if (this.moreOptionsRef && this.moreOptionsRef.hasAttached()) {
      this.moreOptionsRef.detachBackdrop();
      this.moreOptionsRef.detach();
      this.injectMoreOptionsItems();
    }
  }

  private injectMoreOptionsItems() {
    const portalInjector = Injector.create({
      providers: [{ provide: COMMANDBAR_OPTIONSMENU_DATA, useValue: this.getInjectableCommandbarElements() }],
      parent: this.injector,
    });
    const optionsMenuPortal = new ComponentPortal(CommandbarOptionsmenuComponent, null, portalInjector);
    this.moreOptionsComponent = this.moreOptionsRef.attach(optionsMenuPortal);
    this.moreOptionsComponent.instance.closeOptionsMenu.subscribe(() => this.closeOptionsMenu());
  }

  private getInjectableCommandbarElements(): CommandbarOptionsmenuConfig {
    const data: CommandbarOptionsmenuConfig = {};
    if (this.containerWidth <= this.COMMAND_BAR_EXTRA_SMALL) {
      // when in small screen mode show all elements in the tooltip
      if (this.commandbarInlinefiltersElement) {
        data.inlineFilters = this.commandbarInlinefiltersElement.items.toArray();
      }
      if (this.commandbarQuickfiltersElement) {
        data.quickFilters = this.commandbarQuickfiltersElement.items.toArray();
      }
      if (this.commandbarActionsComponent) {
        data.actions = this.commandbarActionsComponent.items.toArray();
      }
      if (this.commandbarSortButton) {
        data.sort = this.commandbarSortButton;
      }
      if (this.commandbarFilterButton) {
        data.filter = this.commandbarFilterButton;
      }
    } else {
      // when in normal screen mode pick only the hidden items for the tooltip
      if (this.commandbarInlinefiltersElement) {
        data.inlineFilters = this.commandbarInlinefiltersElement.hiddenItems;
      }
      if (this.commandbarQuickfiltersElement) {
        data.quickFilters = this.commandbarQuickfiltersElement.hiddenItems;
      }
      if (this.commandbarActionsComponent) {
        data.actions = this.commandbarActionsComponent.hiddenItems;
      }
      if (this.commandbarSortButton && !this.commandbarSortButton.render) {
        data.sort = this.commandbarSortButton;
      }
      if (this.commandbarFilterButton && !this.commandbarFilterButton.render) {
        data.filter = this.commandbarFilterButton;
      }
    }
    return data;
  }

  private createSearchForm() {
    this.searchForm = this.fb.group({
      search: '',
    });
  }

  private setAvailableCommandbarComponents() {
    if (this.commandbarActionsComponent) {
      this.commandbarElements.push(this.commandbarActionsComponent);
    }
    if (this.commandbarSortButton) {
      this.commandbarElements.push(this.commandbarSortButton);
    }
    if (this.commandbarFilterButton) {
      this.commandbarElements.push(this.commandbarFilterButton);
    }
    if (this.commandbarQuickfiltersElement) {
      this.commandbarElements.push(this.commandbarQuickfiltersElement);
    }
    if (this.commandbarInlinefiltersElement) {
      this.commandbarElements.push(this.commandbarInlinefiltersElement);
    }
    this.commandbarElementsReversed = this.commandbarElements.slice().reverse();
  }

  hasHiddenElements() {
    this.hasHiddenFilters = 
    (
      (!!this.commandbarInlinefiltersElement && !!this.commandbarInlinefiltersElement.hiddenItems.length) ||
      (!!this.commandbarQuickfiltersElement && !!this.commandbarQuickfiltersElement.hiddenItems.length) ||
      (!!this.commandbarActionsComponent && !!this.commandbarActionsComponent.hiddenItems.length) ||
      (this.showSort && !!this.commandbarSortButton && !this.commandbarSortButton.render) ||
      (this.showFilter && !!this.commandbarFilterButton && !this.commandbarFilterButton.render)
    );
  }
}
