import { ElementRef } from '@angular/core';
import { ChartDataPoint } from './../model/ChartDataPoint.model';
import { ChartsFeatureState, ChartsState } from './../store/charts.reducers';
import { Subscription } from 'rxjs';
import { Component, OnInit, Input, ViewChild, OnDestroy } from '@angular/core';
import { ChartsService } from '../charts.service';
import { Chart } from '../model/Chart.model';
import { Store } from '@ngrx/store';
import * as ChartJS from 'chart.js'


@Component({
  selector: 'app-chart',
  templateUrl: './chart.component.html',
  styleUrls: ['./chart.component.scss']
})
export class ChartComponent implements OnInit, OnDestroy {

  @Input() chart: Chart;
  @ViewChild("canvas") canvas: ElementRef;

  loaded: boolean = false;
  error: boolean = false;

  private chartObject: any;

  private storeSubscription: Subscription;
  
  private colors: string[] = [
    "#F44336", 
    "#E91E63",
    "#9C27B0",
    "#673AB7",
    "#2196F3",
    "#03A9F4",
    "#00BCD4",
    "#009688",
    "#8BC34A",
    "#CDDC39",
    "#FFEB3B",
    "#FFC107",
    "#FF5722",
    "#795548",
    "#9E9E9E",
    "#607D8B"
  ];
  private currentColorIndex = Math.floor(Math.random() * this.colors.length);

  constructor(private chartsService: ChartsService, private store: Store<ChartsFeatureState>) { }

  ngOnInit() {
    this.storeSubscription = this.store.select('charts').subscribe(
      (state: ChartsState) => {
        if (!this.chartObject){
          let chartData: ChartDataPoint[] = state.chartsData.get(this.chart.id);
          if (chartData === undefined){
            this.chartsService.requestChartData(this.chart.id);
          }
          if (chartData === null){
            this.error = true;
          }
          if (chartData){
            let chartType: String = this.chart.type.name.toLocaleLowerCase();
            chartType = chartType === "bar" ? "horizontalBar" : chartType;
            chartType = chartType === "column" ? "bar" : chartType;
            let adjustedChartData: any = this.adjustChartData(chartType, chartData);
            let options = {
              animation: {
                duration: 0
              },
              responsive: true,
              legend: {
                  display: chartType === "pie"
              }
            }
            if (chartType !== "pie"){
              options['scales'] = {
                xAxes: [{
                  scaleLabel: {
                    display: true,
                    labelString: this.chart.chartData.x.label
                  }
                }],
                yAxes: [{
                  scaleLabel: {
                    display: true,
                    labelString: this.chart.chartData.y.label
                  }
                }]
              }
            }
            this.loaded = true;
            this.chartObject = new ChartJS.Chart(this.canvas.nativeElement, {
              type: <string>chartType,
              data: adjustedChartData,
              options: options
            });
          }
        }
      }
    );
  }

  ngOnDestroy(){
    this.storeSubscription.unsubscribe();
  }

   private adjustChartData(chartType: String, chartData: ChartDataPoint[]){
    chartData = chartData.map((point: ChartDataPoint) => { 
      return new ChartDataPoint(
        point.x && point.x.hasOwnProperty("label") ? point.x.label : point.x,
        point.y && point.y.hasOwnProperty("label") ? point.y.label : point.y,
        point.z && point.z.hasOwnProperty("label") ? point.z.label : point.z
      ); 
    });
    switch(chartType){
      case "horizontalBar": //bar
        return {
          datasets: [{
            data: chartData.map((point: ChartDataPoint) => point.x),
            backgroundColor: chartData.map(() => this.nextColor()),
          }],
          labels: chartData.map((point: ChartDataPoint) => point.y)
        }
      case "bar": //column
        return {
          datasets: [{
            data: chartData.map((point: ChartDataPoint) => point.y),
            backgroundColor: chartData.map(() => this.nextColor()),
          }],
          labels: chartData.map((point: ChartDataPoint) => point.x)
        }
      case "line":
        return {
          datasets: [{
            data: chartData.map((point: ChartDataPoint) => point.y),
            backgroundColor: this.nextColor(),
            borderColor: this.nextColor(),
            fill: false
          }],
          labels: chartData.map((point: ChartDataPoint) => point.x)
        }
      case "pie":
        return {
          datasets: [{
            data: chartData.map((point: ChartDataPoint) => point.y),
            backgroundColor: chartData.map(() => this.nextColor()),
          }],
          labels: chartData.map((point: ChartDataPoint) => point.x)
        }
      case "bubble": 
        return {
          datasets: [{
            data: chartData.map((point: ChartDataPoint) => {
              return {
                x: point.x,
                y: point.y,
                r: point.z
              }
            }),
            backgroundColor: chartData.map(() => this.nextColor()),
          }]
        }
      default:
        return chartData;
    }
  }

  private nextColor(){
    this.currentColorIndex++;
    if (this.currentColorIndex >= this.colors.length)
      this.currentColorIndex = 0;
    return this.colors[this.currentColorIndex];
  }

}
