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

import { Component, Input, HostBinding, ElementRef, Output, EventEmitter, HostListener } from '@angular/core';
import { SafeStyle, DomSanitizer } from '@angular/platform-browser';

import { ResizeHandlePosition, ResizeHandleSizeChangedEvent } from './resize-handle.model';

/**
 * The `<bci-resize-handle>` component.
 * It adds a resize handle icon to the parent container, that let's you change it's width by dragging the icon.
 */
@Component({
  selector: 'bci-resize-handle',
  template: `<div class="resize-handle"></div>`,
  styleUrls: ['./resize-handle.component.scss'],
})
export class ResizeHandleComponent {
  /** It binds the position style based on the resize handle given position. */
  @HostBinding('style')
  get myStyle(): SafeStyle {
    let style = '';
    switch (this.position) {
      case ResizeHandlePosition.Left:
        style = 'left: 0; top: 0';
        break;
      case ResizeHandlePosition.Right:
        style = 'right: 0; top: 0';
        break;
    }
    return this.sanitizer.bypassSecurityTrustStyle(style);
  }

  /**
   * It sets the position of the resize handle: left, right.
   * @default: 'right'
   */
  @Input()
  position: ResizeHandlePosition = ResizeHandlePosition.Right;

  /**
   * It sets an offset on the initial size.
   * @default: 0
   */
  @Input()
  offset = 0;

  /**
   * It sets a minimum size, handle cannot go lower than this value.
   * To disable this feature, leave it undefined.
   * @default: undefined
   */
  @Input()
  minSize: number;

  /**
   * It sets a maximum size, handle cannot go higher than this value.
   * To disable this feature, leave it undefined.
   * @default: undefined
   */
  @Input()
  maxSize: number;

  /** The event emitter to propagate the size changed event */
  @Output()
  sizeChanged = new EventEmitter<ResizeHandleSizeChangedEvent>();

  private moving = false;
  private widthOnDragStart: number;
  private startX: number;

  constructor(private sanitizer: DomSanitizer, private elRef: ElementRef) {}

  @HostListener('mousedown', ['$event'])
  @HostListener('touchstart', ['$event'])
  onStart(startEvent: any) {
    if (startEvent.cancelable) {
      startEvent.preventDefault();
    }
    this.moving = true;
    this.startX = startEvent.touches ? startEvent.changedTouches[0].pageX : startEvent.pageX;
    this.widthOnDragStart = this.elRef.nativeElement.parentElement.offsetWidth + this.offset;
  }

  @HostListener('document:mousemove', ['$event'])
  @HostListener('document:touchmove', ['$event'])
  onMove(moveEvent: any) {
    if (!this.moving) {
      return;
    }
    let xDirection = 0;
    switch (this.position) {
      case ResizeHandlePosition.Left:
        xDirection = -1;
        break;
      case ResizeHandlePosition.Right:
        xDirection = 1;
        break;
    }
    const pageX = moveEvent.touches ? moveEvent.changedTouches[0].pageX : moveEvent.pageX;
    const newWidth = this.widthOnDragStart + xDirection * (pageX - this.startX);

    if (this.minSize !== undefined && newWidth < this.minSize) {
      return;
    }
    if (this.maxSize !== undefined && newWidth > this.maxSize) {
      return;
    }

    switch (this.position) {
      case ResizeHandlePosition.Left:
        this.sizeChanged.emit({ value: newWidth });
        break;
      case ResizeHandlePosition.Right:
        this.sizeChanged.emit({ value: newWidth });
        break;
    }
  }

  @HostListener('document:mouseup')
  @HostListener('document:touchend')
  @HostListener('document:touchcancel')
  onEnd() {
    this.moving = false;
  }
}
