<template>
    <div style="position: relative">
        <!-- <Map className="h-36" :center="state.center" :zoom="state.zoom"> // map component content </Map> -->
        <div :id="mapId" class="map-container mapDesktop rounded">
            <ZoomControlComponent ref="zoom" :mapId="mapId"></ZoomControlComponent>
            <DrawControlComponent ref="draw" :mapId="mapId" :southWest="southWest" :northEast="northEast"></DrawControlComponent>
        </div>
    </div>
</template>

<script lang="ts">
import { EventEmitter } from './EventEmitter';
import { Component, Vue, Prop, Ref } from 'vue-facing-decorator';
// import type { Coverage } from '@/Dataset';
// import { Map, Control, MapOptions, LatLngBoundsExpression, tileLayer, latLng, latLngBounds, FeatureGroup } from 'leaflet';
import { Map } from 'leaflet/src/map/index';
import { Control } from 'leaflet/src/control/Control';
import { LatLngBoundsExpression, toLatLngBounds } from 'leaflet/src/geo/LatLngBounds';
import { toLatLng } from 'leaflet/src/geo/LatLng';
import { tileLayerWMS } from 'leaflet/src/layer/tile/TileLayer.WMS';
import { Attribution } from 'leaflet/src/control/Control.Attribution';
// import { Attribution } from 'leaflet';
// import { FeatureGroup } from 'leaflet/src/layer/FeatureGroup';

import { MapOptions } from './MapOptions';
import { LayerOptions, LayerMap } from './LayerOptions';
import { MapService } from '@/Stores/map.service';
import ZoomControlComponent from './zoom.component.vue';
import DrawControlComponent from './draw.component.vue';
import { Coverage } from '@/Dataset';
import { canvas } from 'leaflet/src/layer/vector/Canvas';
import { svg } from 'leaflet/src/layer/vector/SVG';

Map.include({
    // @namespace Map; @method getRenderer(layer: Path): Renderer
    // Returns the instance of `Renderer` that should be used to render the given
    // `Path`. It will ensure that the `renderer` options of the map and paths
    // are respected, and that the renderers do exist on the map.
    getRenderer: function (layer) {
        // @namespace Path; @option renderer: Renderer
        // Use this specific instance of `Renderer` for this path. Takes
        // precedence over the map's [default renderer](#map-renderer).
        var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;

        if (!renderer) {
            renderer = this._renderer = this._createRenderer();
        }

        if (!this.hasLayer(renderer)) {
            this.addLayer(renderer);
        }
        return renderer;
    },

    _getPaneRenderer: function (name) {
        if (name === 'overlayPane' || name === undefined) {
            return false;
        }

        var renderer = this._paneRenderers[name];
        if (renderer === undefined) {
            renderer = this._createRenderer({ pane: name });
            this._paneRenderers[name] = renderer;
        }
        return renderer;
    },

    _createRenderer: function (options) {
        // @namespace Map; @option preferCanvas: Boolean = false
        // Whether `Path`s should be rendered on a `Canvas` renderer.
        // By default, all `Path`s are rendered in a `SVG` renderer.
        return (this.options.preferCanvas && canvas(options)) || svg(options);
    },
});

const DEFAULT_BASE_LAYER_NAME = 'BaseLayer';
// const DEFAULT_BASE_LAYER_URL = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
const DEFAULT_BASE_LAYER_ATTRIBUTION = '&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors';

@Component({
    name: 'MapComponent',
    components: {
        ZoomControlComponent,
        DrawControlComponent,
    },
})
export default class MapComponent extends Vue {
    /**
     * A map with the given ID is created inside this component.
     * This ID can be used the get the map instance over the map cache service.
     */
    @Prop()
    public mapId: string;

    /**
     * The corresponding leaflet map options (see: https://leafletjs.com/reference-1.3.4.html#map-option)
     */
    @Prop()
    public mapOptions: MapOptions;

    @Prop()
    public coverage: Coverage;

    // markerService: MarkerService
    /**
     * Bounds for the map
     */
    @Prop({ default: null })
    public fitBounds: LatLngBoundsExpression;

    /**
     * Describes the the zoom control options (see: https://leafletjs.com/reference-1.3.4.html#control-zoom)
     */
    @Prop()
    public zoomControlOptions: Control.ZoomOptions;

    @Prop()
    public baseMaps: LayerMap;

    @Ref('zoom') private zoom: ZoomControlComponent;
    @Ref('draw') private draw: DrawControlComponent;

    // services:
    mapService = MapService();

    southWest;
    northEast;

    /**
     * Informs when initialization is done with map id.
     */
    public onMapInitializedEvent: EventEmitter<string> = new EventEmitter<string>();

    public map!: Map;
    // protected drawnItems!: FeatureGroup<any>;

    // @Prop({ type: Object })
    // geolocation: Coverage;

    mounted(): void {
        this.initMap();
    }

    unmounted() {
        this.map.off('zoomend zoomlevelschange');
    }

    // @Emit(this.onMapInitializedEvent)
    protected initMap(): void {
        // let map: Map = (this.map = this.mapService.getMap(this.mapId));

        let map: Map = (this.map = new Map(this.mapId, this.mapOptions));
        this.mapService.setMap(this.mapId, map);
        map.scrollWheelZoom.disable();

        // return this.mapId;
        //    this.$emit("onMapInitializedEvent", this.mapId);
        this.onMapInitializedEvent.emit(this.mapId);
        this.addBaseMap();

        const attributionControl = new Attribution().addTo(this.map);
        attributionControl.setPrefix(false);

        map.on(
            'Daw.Event.CREATED',
            function (event) {
                // drawnItems.clearLayers();
                // var type = event.type;
                var layer = event.layer;

                // if (type === "rectancle") {
                // layer.bindPopup("A popup!" + layer.getBounds().toBBoxString());
                var bounds = layer.getBounds();
                this.coverage.x_min = bounds.getSouthWest().lng;
                this.coverage.y_min = bounds.getSouthWest().lat;
                // console.log(this.geolocation.xmin);
                this.coverage.x_max = bounds.getNorthEast().lng;
                this.coverage.y_max = bounds.getNorthEast().lat;
                // }

                // drawnItems.addLayer(layer);
            },
            this,
        );

        // Initialise the FeatureGroup to store editable layers
        // let drawnItems = (this.drawnItems = new FeatureGroup());
        // map.addLayer(drawnItems);

        this.map.on('zoomend zoomlevelschange', this.zoom.updateDisabled, this.zoom);

        // if (this.fitBounds) {
        //     this.map.fitBounds(this.fitBounds);
        // }
        if (this.coverage.x_min && this.coverage.y_min) {
            this.southWest = toLatLng(this.coverage.y_min, this.coverage.x_min);
        } else {
            this.southWest = toLatLng(46.5, 9.9);
        }
        if (this.coverage.x_max && this.coverage.y_max) {
            this.northEast = toLatLng(this.coverage.y_max, this.coverage.x_max);
        } else {
            this.northEast = toLatLng(48.9, 16.9);
        } // this.northEast = toLatLng(48.9, 16.9);
        const bounds = toLatLngBounds(this.southWest, this.northEast);
        map.fitBounds(bounds);

        if (this.coverage.x_min && this.coverage.x_max && this.coverage.y_min && this.coverage.y_max) {
            let _southWest;
            let _northEast;
            if (this.coverage.x_min && this.coverage.y_min) {
                _southWest = toLatLng(this.coverage.y_min, this.coverage.x_min);
            }
            if (this.coverage.x_max && this.coverage.y_max) {
                _northEast = toLatLng(this.coverage.y_max, this.coverage.x_max);
            }
            this.draw.drawShape(_southWest, _northEast);
        }
    }

    private addBaseMap(layerOptions?: LayerOptions): void {
        if (this.map) {
            if (!this.baseMaps || this.baseMaps.size === 0) {
                // let bmapgrau = tileLayer('https://{s}.wien.gv.at/basemap/bmapgrau/normal/google3857/{z}/{y}/{x}.png', {
                //         subdomains: ['maps', 'maps1', 'maps2', 'maps3', 'maps4'],
                //         attribution: 'Datenquelle: <a href="http://www.basemap.at/">basemap.at</a>',
                // });
                let osmGgray = tileLayerWMS('https://ows.terrestris.de/osm-gray/service', {
                    format: 'image/png',
                    attribution: DEFAULT_BASE_LAYER_ATTRIBUTION,
                    layers: 'OSM-WMS',
                });
                layerOptions = {
                    label: DEFAULT_BASE_LAYER_NAME,
                    visible: true,
                    layer: osmGgray,
                };
                layerOptions.layer.addTo(this.map);
            }
        }
    }
}
</script>

<style lang="css">
.leaflet-container {
    height: 600px; /* <-- map height */
    width: 100%;
}
.leaflet-pane {
    z-index: 30;
}
</style>
