import { DataSource } from '@angular/cdk/collections';
import { Component, Inject, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { BehaviorSubject, merge, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Project } from '../../../models/project';
import{ Controller } from '../../../models/controller';
import { Template } from '../../../models/template';
import { TemplateService } from '../../../services/template.service';
import { ToasterService } from '../../../services/toaster.service';
import { NonNegativeValidator } from '../../../validators/non-negative-validator';

@Component({
  selector: 'app-template-list-dialog',
  templateUrl: './template-list-dialog.component.html',
  styleUrls: ['./template-list-dialog.component.scss'],
})
export class TemplateListDialogComponent implements OnInit {
  controller:Controller ;
  project: Project;
  templateTypes: string[] = [
    'cloud',
    'ethernet_hub',
    'ethernet_switch',
    'docker',
    'dynamips',
    'vpcs',
    'virtualbox',
    'vmware',
    'iou',
    'qemu',
  ];
  selectedType: string;
  configurationForm: UntypedFormGroup;
  positionForm: UntypedFormGroup;
  templates: Template[];
  filteredTemplates: Template[];
  selectedTemplate: Template;
  searchText: string = '';

  nodeControllers: string[] = ['local', 'vm'];

  constructor(
    public dialogRef: MatDialogRef<TemplateListDialogComponent>,
    private templateService: TemplateService,
    private formBuilder: UntypedFormBuilder,
    @Inject(MAT_DIALOG_DATA) public data: any,
    private toasterService: ToasterService,
    private nonNegativeValidator: NonNegativeValidator
  ) {
    this.controller = data['controller'];
    this.project = data['project'];
    this.configurationForm = this.formBuilder.group({
      numberOfNodes: new UntypedFormControl(1, [ Validators.compose([Validators.required, nonNegativeValidator.get])]),
    });
    this.positionForm = this.formBuilder.group({
      top: new UntypedFormControl(0, Validators.required),
      left: new UntypedFormControl(0, Validators.required),
    });
  }

  ngOnInit() {
    this.templateService.list(this.controller).subscribe((listOfTemplates: Template[]) => {
      this.filteredTemplates = listOfTemplates;
      this.templates = listOfTemplates;
    });
  }

  onNoClick(): void {
    this.dialogRef.close();
  }

  filterTemplates(event) {
    let temporaryTemplates = this.templates.filter((item) => {
      return item.name.toLowerCase().includes(this.searchText.toLowerCase());
    });
    this.filteredTemplates = temporaryTemplates.filter((t) => t.template_type === event.value.toString());
  }

  chooseTemplate(event) {
    this.selectedTemplate = event.value;
    if (
      this.selectedTemplate.template_type === 'cloud' ||
      this.selectedTemplate.template_type === 'ethernet_hub' ||
      this.selectedTemplate.template_type === 'ethernet_switch'
    ) {
      this.selectedTemplate.compute_id = 'local';
    }
    // this.configurationForm.controls['name'].setValue(this.selectedTemplate.default_name_format);
  }

  onAddClick(): void {
    if (!this.selectedTemplate || this.filteredTemplates.length === 0) {
      this.toasterService.error('Please firstly choose template.');
    } else if (!this.positionForm.valid || !this.configurationForm.valid || !this.selectedTemplate.compute_id) {
      this.toasterService.error('Please fill all required fields.');
    } else {
      let x: number = this.positionForm.get('left').value;
      let y: number = this.positionForm.get('top').value;
      if (
        x > this.project.scene_width / 2 ||
        x < -(this.project.scene_width / 2) ||
        y > this.project.scene_height / 2 ||
        y < -this.project.scene_height
      ) {
        this.toasterService.error('Please set correct position values.');
      } else {
        let event: NodeAddedEvent = {
          template: this.selectedTemplate,
          controller: this.selectedTemplate.compute_id,
          // name: this.configurationForm.get('name').value,
          numberOfNodes: this.configurationForm.get('numberOfNodes').value,
          x: x,
          y: y,
        };
        this.dialogRef.close(event);
      }
    }
  }
}

export interface NodeAddedEvent {
  template: Template;
  controller: string;
  name?: string;
  numberOfNodes: number;
  x: number;
  y: number;
}

export class TemplateDatabase {
  dataChange: BehaviorSubject<Template[]> = new BehaviorSubject<Template[]>([]);

  get data(): Template[] {
    return this.dataChange.value;
  }

  constructor(private controller:Controller , private templateService: TemplateService) {
    this.templateService.list(this.controller).subscribe((templates) => {
      this.dataChange.next(templates);
    });
  }
}

export class TemplateDataSource extends DataSource<Template> {
  filterChange = new BehaviorSubject('');

  get filter(): string {
    return this.filterChange.value;
  }
  set filter(filter: string) {
    this.filterChange.next(filter);
  }

  constructor(private templateDatabase: TemplateDatabase) {
    super();
  }

  connect(): Observable<Template[]> {
    const displayDataChanges = [this.templateDatabase.dataChange, this.filterChange];

    return merge(...displayDataChanges).pipe(
      map(() => {
        return this.templateDatabase.data.slice().filter((item: Template) => {
          const searchStr = item.name.toLowerCase();
          return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
        });
      })
    );
  }

  disconnect() {}
}
