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

import { Component, OnInit, AfterContentInit, ContentChildren, QueryList, ElementRef, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { SplitterAreaComponent } from './splitter-area/splitter-area.component';

/**
 * A splitter component that allows areas to resize using a resize handle.
 * The splitter can contain multiple areas, and each one will resize according to surrounding space.
 * This component is a POC. Is subject to changes, use it with care.
 * To be used as `<bci-splitter><bci-splitter-area></bci-splitter-area></bci-splitter>`
 */
@Component({
  selector: 'bci-splitter',
  templateUrl: './splitter.component.html',
  styleUrls: ['./splitter.component.scss'],
})
export class SplitterComponent implements OnInit, AfterContentInit, OnDestroy {
  @ContentChildren(SplitterAreaComponent) private areas: QueryList<SplitterAreaComponent>;
  private componentDestroyed$ = new Subject<void>();

  /** The size of the splitter */
  private sizePx: number;

  constructor(private elRef: ElementRef) {}

  ngOnInit() {
    this.sizePx = this.elRef.nativeElement.offsetWidth;
  }

  ngAfterContentInit() {
    this.setSizeForUnsizedAreas();

    // last area does not have a resize handler
    if (this.areas.length) {
      this.areas.last.hasResizer = false;
    }

    this.resizeNextSiblingArea();
  }

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

  private setSizeForUnsizedAreas() {
    // find unsized areas
    const unsizedAreas = this.areas.filter((a) => a.size === undefined);

    // find sized areas
    const sizedAreas = this.areas.filter((a) => a.size !== undefined);

    // get the sum of unsized areas
    const sum = sizedAreas.reduce((a, b) => a + parseFloat(b.size), 0.0);

    // set the size of unsized areas
    const size = (this.sizePx - sum) / unsizedAreas.length;
    unsizedAreas.forEach((a) => (a.sizePx = size));
  }

  private resizeNextSiblingArea() {
    const _areas = this.areas.toArray();
    _areas.forEach((area, i) => {
      area.resized.pipe(takeUntil(this.componentDestroyed$)).subscribe(() => {
        // get next sibling area
        const nextSiblingArea = _areas[i + 1];

        // find sibling areas size
        const siblingAreasSize = _areas.reduce((sum, el) => {
          if (el !== nextSiblingArea) {
            return sum + parseFloat(el.size);
          } else {
            return sum;
          }
        }, 0.0);

        // set size of the next sibling area
        nextSiblingArea.sizePx = this.sizePx - siblingAreasSize;
      });
    });
  }
}
