import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {
  geoJSON, GeoJSON, icon, LatLng, latLng, Map, point, marker, polyline, tileLayer,
  LatLngBoundsExpression, latLngBounds
} from 'leaflet';
import {VttTraceWsService} from './vtt-trace-ws.service';
import {Feature, LineString, MultiLineString, Point} from 'geojson';
import {VttTraceFormNewTraceComponent} from './vtt-trace.formNewTraceComponent';


// Utilise la librairie ngx-leaflet
// https://www.asymmetrik.com/ngx-leaflet-tutorial-angular-cli/
// https://github.com/Asymmetrik/ngx-leaflet
// Voir aussi la doc de Leaflet
// https://leafletjs.com/reference-1.3.0.html
// et le projet exemple ngx-leaflet

@Component({
  selector: 'app-vtt-trace',
  templateUrl: './vtt-trace.component.html',
  styleUrls: ['./vtt-trace.component.css'],
  providers: [VttTraceWsService, VttTraceFormNewTraceComponent]
})

export class VttTraceComponent implements OnInit {
  map: Map;
  zoom: number;
  center: LatLng;
  latitude: number;
  longitude: number;

  // Open Street Map and Open Cycle Map definitions
  LAYER_OCM = {
    id: 'opencyclemap',
    name: 'Open Cycle Map',
    enabled: true,
    layer: tileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: 'Open Cycle Map'
    })
  };
  LAYER_OSM = {
    id: 'openstreetmap',
    name: 'Open Street Map',
    enabled: false,
    layer: tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: 'Open Street Map'
    })
  };

  geoJSON = {
    id: 'geoJSON',
    name: 'Geo JSON Polygon',
    enabled: true,
    layer: geoJSON(
      null,
      {style: () => ({color: '#ff7800'})})
  };

  // Values to bind to Leaflet Directive
  layersControlOptions = {position: 'bottomright'};
  layersControl = {
    baseLayers: {
      'Open Street Map': this.LAYER_OSM.layer,
      'Open Cycle Map': this.LAYER_OCM.layer
    },
    overlays: {
      'GeoJSON': this.geoJSON.layer
    }
  };

  /*
   * This is a specification of the leaflet options
   * The reason to duplicate this object is so we can easily render it to the template
   */
  optionsSpec: {
    layers: any[],
    zoom: number,
    center: number[]
  } = {
    layers: [
      {
        url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
        maxZoom: 18,
        attribution: 'Open Street Map'
      }
    ],
    zoom: 5,
    center: [46, 2]
  };


  // Définitions des layers et options bindés en input avec la map et initialisés avec le contenu de la structure optionSpec
  layers = [];
  options = {
    layers: this.optionsSpec.layers.map((l) => {
      return tileLayer(l.url, {maxZoom: l.maxZoom, attribution: l.attribution});
    }),
    zoom: this.optionsSpec.zoom,
    center: latLng(this.optionsSpec.center[0], this.optionsSpec.center[1])
  };

  featuresCollection: Array<GeoJSON.Feature<Point>> = [];

 constructor(private vttTraceWs: VttTraceWsService, private changeDetector: ChangeDetectorRef) {}

  ngOnInit(): void {
  this.getMarkersObs();
  console.log(this.options);
  console.log(this.geoJSON);
  console.log(this.layers);
  console.log(this.layersControl);
  console.log(this.layersControlOptions);
}

  // TODO: à voir si utile et pe l'utiliser avec onMapReady
  // pour obtenir qqch de plus propre et mieux initialisé?
  onMapReady(map: Map): void {
  this.map = map;
}

  private getMarkersObs(): void {
  this.vttTraceWs.gettVttRandosDescFromServerObs()
    .subscribe((response: Array<string>) => {
      response.forEach(x => {
        const json = JSON.parse(x);
        this.addMarker(json);
        this.featuresCollection.push(json);
      });
    });
}

  addMarker(feature: Feature<Point>): void {
  const newMarker = marker(
    [feature.geometry.coordinates[0], feature.geometry.coordinates[1]],
    {
      icon: icon({
        iconSize: [25, 41],
        iconAnchor: [13, 41],
        iconUrl: 'assets/marker-icon.png',
        shadowUrl: 'assets/marker-shadow.png',
        popupAnchor: [0, -45] // point from which the popup should open relative to the iconAnchor
      }),
      title: '' + feature.properties.fichier
    }
  );

  console.log(feature.properties.fichier);
  newMarker.bindPopup(feature.properties.name).openPopup();
  newMarker.on('click', this.markerOnClick, this);
  this.layers.push(newMarker);
}

  markerOnClick(e): boolean {
  const attributes = e.sourceTarget.options;

  this.addTrace(attributes.title);
  // TODO utiliser plutôt une méthode fitBounds afin de zoomer au niveau le plus fin autour de la trace
  //this.centerAndZoom(e.sourceTarget._latlng.lat, e.sourceTarget._latlng.lng, 9);

  // But, it will if we tell Angular to detect changes
  // See doc API on zone changes: https://github.com/Asymmetrik/ngx-leaflet#api
  this.changeDetector.detectChanges();

  return true;
}

  /**
 * ajout d'une trace à la map, dans le tableau de layers
 *
 * TODO: reset layer fonctionne mais doit impérativement avoir réussi à charger la trace demandée avant de tout éffacer
 * autrement la carte se retrouve vide this.resetLayers();
 * How to refresh automaticaly the map???
 * this._onResize();
 * this.geoJSON.layer.addEventParent(geoJSON.);
 * @param {string} fileName
 * @returns {boolean}
 */
addTrace(fileName: string): boolean {

  console.log(this.geoJSON.layer)
  this.geoJSON.layer.clearLayers();

  this.vttTraceWs.getTraceFromFile(fileName)
    .subscribe(data => {
      const featureCollection: GeoJSON.FeatureCollection<Point | LineString | MultiLineString> = data;
      this.geoJSON.layer.addData(featureCollection.features[0].geometry)
      //console.log(`featureCollection: ${featureCollection}`);
      console.log(featureCollection.features[0].geometry.coordinates);

      var coords: number[][]= featureCollection.features[0].geometry.coordinates as number[][];
      var latlngs = coords.map(x => latLng(x[1], x[0]))
      // console.log(latlngs);
      this.map.fitBounds(latLngBounds(latlngs), {
        padding: point(24, 24),
        maxZoom: 12,
        animate: true
      });
    });
  return true;
}

}


