import { Component, OnInit, ViewChild, ElementRef, NgZone, AfterViewInit } from '@angular/core';
import * as graph3DLib from 'graph3D';
import { GHCIService } from '../../../shared/services/ghci.service';
import { formatJSON, AnimationProps, Zoom3DType, GraphProps, Default_GraphProps, debounce } from './graph3D.helper';
import { TranslateService } from '@ngx-translate/core';
import { TitleCasePipe } from '../../../shared/pipes/titlecase.pipe';

@Component({
  selector: 'graph3d-component',
  templateUrl: './graph3D.component.html',
  styleUrls: ['./graph3D.component.scss'],
  host: {
    '(window:resize)': 'onResize($event)'
  }
})
export class Graph3DComponent implements AfterViewInit {

  private ghciServiceSub: any;

  private translateService: any;
  private titlecasePipe: any;

  @ViewChild('graph3DElement') 
  private graph3DRef: ElementRef;

  graphProps : GraphProps = Default_GraphProps;
  
  animationProps : AnimationProps = {
    visible: false,
    playing: false,
    value: 0,
    speed: 1000
  };
  
  constructor(ghciService: GHCIService, private zone: NgZone, public translate: TranslateService) {
    const self = this;

    // i18n
    this.translateService = translate;
    this.titlecasePipe = new TitleCasePipe();

    this.ghciServiceSub = ghciService.messages.subscribe(
      message => {
        if (message.tipo == "canvas3D") {
          const figures = JSON.parse(formatJSON(message.resultado));
          self.clear();
          graph3DLib.drawFigures(figures);
        } 
        else if (message.tipo == "animacion3D") {
          const frames = message.resultado.map((frame) => JSON.parse(formatJSON(frame)));

          self.clear();

          this.animationProps.visible = true;
          this.animationProps.playing = true;
          this.animationProps.value = 0;

          graph3DLib.initializeAnimation(frames, 
            (value) => this.animationProps.value = value
          );

          graph3DLib.playAnimation();
        }
      }
    )
  }

  ngAfterViewInit() {
    //this.zone.runOutsideAngular(() => {
      graph3DLib.initialize(this.graph3DRef.nativeElement);
    //})
  }

  ngOnDestroy() {
    if (this.ghciServiceSub) {
      this.ghciServiceSub.unsubscribe();
    }
  }

  onActivate() {
    setTimeout(() => {
      this.onResize(null);
    })
  }

  onResize(event){
    const {width, height} = this.graph3DRef.nativeElement.getBoundingClientRect();
      
    if (width > 0 && height > 0) {
      graph3DLib.changeSize({width, height});
    }
  }

  onAnimationChangeSpeed = (value) => {
    this.animationProps.speed = parseInt(value);
    graph3DLib.changeSpeedAnimation(parseInt(value));
  }

  onAnimationTogglePlay = () => {
    if (this.animationProps.playing) {
      graph3DLib.pauseAnimation();
    }
    else {
      graph3DLib.playAnimation();
    }
    
    this.animationProps.playing = !this.animationProps.playing;
  }

  public changeZoomType = (type: Zoom3DType = null) => {
    if (type != null) {
      this.graphProps.zoomType = type;
    } 
    else {
      this.graphProps.zoomType = (this.graphProps.zoomType % 4) + 1;
    }

    graph3DLib.changeZoomType(this.graphProps.zoomType);
  }

  public changeAxesVisibility = () => {
    this.graphProps.showAxes = !this.graphProps.showAxes;
    graph3DLib.showAxes(this.graphProps.showAxes);
  }

  handleAxesRangeDebounced = debounce(function () {
    setTimeout(() =>
      graph3DLib.changeAxesSize(this.graphProps.range)
    );
  }, 500);
  
  public onChangeAxesSize = (v, event) => {
    let value = this.graphProps.range[v];

    const min = parseInt(event.target.min);
    const max = parseInt(event.target.max);

    if (value == null) {
      value = v.search('Min') ? min : max;
      this.graphProps.range[v] = value;
    }

    if (value < min) {
      this.graphProps.range[v] = min;
    } 
    
    if (value > max) {
      this.graphProps.range[v] = max;
    }
    this.handleAxesRangeDebounced();
    //graph3DLib.changeAxesSize(this.graphProps.range)
  }

  public onChangeQuality = () => {
    const value = this.graphProps.quality;

    if (value == null || value <= 1) {
      this.graphProps.quality = 30;
    } 
    else {
      this.graphProps.quality = value;
    }

    graph3DLib.changeOptions({quality: value});
  }

  public zoomIn = () => {
    graph3DLib.changeZoom(true);
  }

  public zoomOut = () => {
    graph3DLib.changeZoom(false);
  }
  
  public clear = () => {
    this.animationProps.visible = false;

    graph3DLib.clear();
  }
  
  public center = () => {
    this.graphProps = Default_GraphProps;

    graph3DLib.reset();
  }

  public getZoom3DTypeName = (type: Zoom3DType) => {
    switch (type) {
      case Zoom3DType.Normal:
        return this.titlecasePipe.transform(this.translateService.get('i18n.object.normal').value);
      case Zoom3DType.XAxis:
        return this.titlecasePipe.transform(this.translateService.get('i18n.object.axis').value) + ' x';
      case Zoom3DType.YAxis:
        return this.titlecasePipe.transform(this.translateService.get('i18n.object.axis').value) + ' y';
      case Zoom3DType.ZAxis:
        return this.titlecasePipe.transform(this.translateService.get('i18n.object.axis').value) + ' z';
    }
  }
}