import { Component, OnChanges, Input, Output, EventEmitter, ElementRef, SimpleChanges, HostListener } from '@angular/core';
import { SafeResourceUrl, DomSanitizer, SafeStyle } from '@angular/platform-browser';
import { NgxGalleryAction } from '../ngx-gallery-action.model';
import { NgxGalleryHelperService } from '../ngx-gallery-helper.service';
import { NgxGalleryOrder } from '../ngx-gallery-order.model';

@Component({
  selector: 'ngx-gallery-thumbnails',
  templateUrl: './ngx-gallery-thumbnails.component.html',
  styleUrls: ['./ngx-gallery-thumbnails.component.scss']
})
export class NgxGalleryThumbnailsComponent implements OnChanges {

  thumbnailsLeft: string;
  thumbnailsMarginLeft: string;
  mouseenter: boolean;
  remainingCountValue: number;

  minStopIndex = 0;

  @Input() images: string[] | SafeResourceUrl[];
  @Input() links: string[];
  @Input() labels: string[];
  @Input() linkTarget: string;
  @Input() columns: number;
  @Input() rows: number;
  @Input() arrows: boolean;
  @Input() arrowsAutoHide: boolean;
  @Input() margin: number;
  @Input() selectedIndex: number;
  @Input() clickable: boolean;
  @Input() swipe: boolean;
  @Input() size: string;
  @Input() arrowPrevIcon: string;
  @Input() arrowNextIcon: string;
  @Input() moveSize: number;
  @Input() order: number;
  @Input() remainingCount: boolean;
  @Input() lazyLoading: boolean;
  @Input() actions: NgxGalleryAction[];

  @Output() onActiveChange = new EventEmitter();

  private index = 0;

  constructor(private sanitization: DomSanitizer, private elementRef: ElementRef,
      private helperService: NgxGalleryHelperService) {}

  ngOnChanges(changes: SimpleChanges): void {
      if (changes['selectedIndex']) {
          this.validateIndex();
      }

      if (changes['swipe']) {
          this.helperService.manageSwipe(this.swipe, this.elementRef,
          'thumbnails', () => this.moveRight(), () => this.moveLeft());
      }

      if (this.images) {
          this.remainingCountValue = this.images.length - (this.rows * this.columns);
      }
  }

  @HostListener('mouseenter') onMouseEnter() {
      this.mouseenter = true;
  }

  @HostListener('mouseleave') onMouseLeave() {
      this.mouseenter = false;
  }

  reset(index: number): void {
      this.selectedIndex = index;
      this.setDefaultPosition();

      this.index = 0;
      this.validateIndex();
  }

  getImages(): string[] | SafeResourceUrl[] {
      if (!this.images) {
          return [];
      }

      if (this.remainingCount) {
          return this.images.slice(0, this.rows * this.columns);
      } 
      else if (this.lazyLoading && this.order != NgxGalleryOrder.Row) {
          let stopIndex = 0;

          if (this.order === NgxGalleryOrder.Column) {
              stopIndex = (this.index + this.columns + this.moveSize) * this.rows;
          }
          else if (this.order === NgxGalleryOrder.Page) {
              stopIndex = this.index + ((this.columns * this.rows) * 2);
          }

          if (stopIndex <= this.minStopIndex) {
              stopIndex = this.minStopIndex;
          } else {
              this.minStopIndex = stopIndex;
          }

          return this.images.slice(0, stopIndex);
      } 
      else {
          return this.images;
      }
  }

  handleClick(event: Event, index: number): void {
      if (!this.hasLink(index)) {
          this.selectedIndex = index;
          this.onActiveChange.emit(index);

          event.stopPropagation();
          event.preventDefault();
      }
  }

  hasLink(index: number): boolean {
      if (this.links && this.links.length && this.links[index]) return true;
  }

  moveRight(): void {
      if (this.canMoveRight()) {
          this.index += this.moveSize;
          let maxIndex = this.getMaxIndex() - this.columns;

          if (this.index > maxIndex) {
              this.index = maxIndex;
          }

          this.setThumbnailsPosition();
      }
  }

  moveLeft(): void {
      if (this.canMoveLeft()) {
          this.index -= this.moveSize;

          if (this.index < 0) {
              this.index = 0;
          }

          this.setThumbnailsPosition();
      }
  }

  canMoveRight(): boolean {
      return this.index + this.columns < this.getMaxIndex() ? true : false;
  }

  canMoveLeft(): boolean {
      return this.index !== 0 ? true : false;
  }

  getThumbnailLeft(index: number): SafeStyle {
      let calculatedIndex;

      if (this.order === NgxGalleryOrder.Column) {
          calculatedIndex = Math.floor(index / this.rows);
      }
      else if (this.order === NgxGalleryOrder.Page) {
          calculatedIndex = (index % this.columns) + (Math.floor(index / (this.rows * this.columns)) * this.columns);
      }
      else if (this.order == NgxGalleryOrder.Row && this.remainingCount) {
          calculatedIndex = index % this.columns;
      }
      else {
          calculatedIndex = index % Math.ceil(this.images.length / this.rows);
      }

      return this.getThumbnailPosition(calculatedIndex, this.columns);
  }

  getThumbnailTop(index: number): SafeStyle {
      let calculatedIndex;

      if (this.order === NgxGalleryOrder.Column) {
          calculatedIndex = index % this.rows;
      }
      else if (this.order === NgxGalleryOrder.Page) {
          calculatedIndex = Math.floor(index / this.columns) - (Math.floor(index / (this.rows * this.columns)) * this.rows);
      }
      else if (this.order == NgxGalleryOrder.Row && this.remainingCount) {
          calculatedIndex = Math.floor(index / this.columns);
      }
      else {
          calculatedIndex = Math.floor(index / Math.ceil(this.images.length / this.rows));
      }

      return this.getThumbnailPosition(calculatedIndex, this.rows);
  }

  getThumbnailWidth(): SafeStyle {
      return this.getThumbnailDimension(this.columns);
  }

  getThumbnailHeight(): SafeStyle {
      return this.getThumbnailDimension(this.rows);
  }

  setThumbnailsPosition(): void {
      this.thumbnailsLeft = - ((100 / this.columns) * this.index) + '%'

      this.thumbnailsMarginLeft = - ((this.margin - (((this.columns - 1)
      * this.margin) / this.columns)) * this.index) + 'px';
  }

  setDefaultPosition(): void {
      this.thumbnailsLeft = '0px';
      this.thumbnailsMarginLeft = '0px';
  }

  canShowArrows(): boolean {
      if (this.remainingCount) {
          return false;
      } else if (this.arrows && this.images && this.images.length > this.getVisibleCount()
          && (!this.arrowsAutoHide || this.mouseenter)) {
          return true;
      } else {
          return false;
      }
  }

  validateIndex(): void {
      if (this.images) {
          let newIndex;

          if (this.order === NgxGalleryOrder.Column) {
              newIndex = Math.floor(this.selectedIndex / this.rows);
          } else {
              newIndex = this.selectedIndex % Math.ceil(this.images.length / this.rows);
          }

          if (this.remainingCount) {
              newIndex = 0;
          }

          if (newIndex < this.index || newIndex >= this.index + this.columns) {
              const maxIndex = this.getMaxIndex() - this.columns;
              this.index = newIndex > maxIndex ? maxIndex : newIndex;

              this.setThumbnailsPosition();
          }
      }
  }

  getSafeUrl(image: string): SafeStyle {
      return this.sanitization.bypassSecurityTrustStyle(this.helperService.getBackgroundUrl(image));
  }

  private getThumbnailPosition(index: number, count: number): SafeStyle {
      return this.getSafeStyle('calc(' + ((100 / count) * index) + '% + '
          + ((this.margin - (((count - 1) * this.margin) / count)) * index) + 'px)');
  }

  private getThumbnailDimension(count: number): SafeStyle {
      if (this.margin !== 0) {
          return this.getSafeStyle('calc(' + (100 / count) + '% - '
              + (((count - 1) * this.margin) / count) + 'px)');
      } else {
          return this.getSafeStyle('calc(' + (100 / count) + '% + 1px)');
      }
  }

  private getMaxIndex(): number {
      if (this.order == NgxGalleryOrder.Page) {
          let maxIndex = (Math.floor(this.images.length / this.getVisibleCount()) * this.columns);

          if (this.images.length % this.getVisibleCount() > this.columns) {
              maxIndex += this.columns;
          }
          else {
              maxIndex += this.images.length % this.getVisibleCount();
          }

          return maxIndex;
      }
      else {
          return Math.ceil(this.images.length / this.rows);
      }
  }

  private getVisibleCount(): number {
      return this.columns * this.rows;
  }

  private getSafeStyle(value: string): SafeStyle {
      return this.sanitization.bypassSecurityTrustStyle(value);
  }
}