import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import Map from 'ol/map';
import View from 'ol/view';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import Style from 'ol/style/style';
import Icon from 'ol/style/Icon';
import Feature from 'ol/Feature';
import Point from 'ol/geom/point';
import proj from 'ol/proj';
import olControl from 'ol/control';
import olInteraction from 'ol/interaction';

const olMap = (containers) => {
    let i = 0;
    for (const mapEl of containers) {
        i = i + 1;
        const mapElId = 'olmap-' + i;
        const args = {
            zoom: mapEl.getAttribute('data-zoom') ? parseInt(mapEl.getAttribute('data-zoom')) : 17,
            lat: parseFloat(mapEl.getAttribute('data-lat')),
            lng: parseFloat(mapEl.getAttribute('data-lng')),
            markerIcon: '/static/images/marker.svg',
            centermarkerIcon: true, // set true if center of the marker should be centered to point
            grayScale: false,
            scrollWheel: false
        };
        mapEl.setAttribute('id', mapElId);

        if (args.lat && args.lng) {
            // create open street map layer
            const osmLayer = new TileLayer({
                source: new OSM()
            });

            // apply grayscale
            if (args.grayScale) {
                osmLayer.addEventListener('postcompose', (event) => {
                    greyscale(event.context);
                });
            }

            // create map
            const coord = proj.fromLonLat([args.lng, args.lat]);
            const map = new Map({
                target: mapElId,
                layers: [osmLayer],
                view: new View({
                    center: coord,
                    zoom: args.zoom
                }),
                controls: olControl.defaults({
                    rotate: false,
                    attribution: false
                }),
                interactions: olInteraction.defaults({
                    mouseWheelZoom: args.scrollWheel
                })
            });

            // create marker and set marker icon
            const marker = new Feature({
                geometry: new Point(coord)
            });

            if (args.markerIcon) {
                const markerStyle = {
                    crossOrigin: 'anonymous',
                    src: args.markerIcon
                };
                if (!args.centermarkerIcon) {
                    markerStyle.anchor = [0.5, 1];
                    markerStyle.anchorXUnits = 'fraction';
                    markerStyle.anchorYUnits = 'fraction';
                }
                marker.setStyle(
                    new Style({
                        image: new Icon(markerStyle)
                    })
                );
            }

            const vectorSource = new VectorSource({
                features: [marker]
            });

            const markerVectorLayer = new VectorLayer({
                source: vectorSource
            });

            map.addLayer(markerVectorLayer);

            mapEl.addEventListener('resize', () => {
                setTimeout(() => {
                    map.updateSize();
                }, 200);
            });
        }
    };
};

// grayscale to every pixel in canvas
const greyscale = (context) => {
    const canvas = context.canvas;
    const width = canvas.width;
    const height = canvas.height;

    const imageData = context.getImageData(0, 0, width, height);
    const data = imageData.data;

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        // CIE luminance for the RGB
        let v = 0.2126 * r + 0.7152 * g + 0.0722 * b;
        // Show white color instead of black color while loading new tiles:
        if (v === 0.0) v = 255.0;
        data[i] = v; // Red
        data[i + 1] = v; // Green
        data[i + 2] = v; // Blue
        data[i + 3] = 255; // Alpha
    }
    context.putImageData(imageData, 0, 0);
};

export { olMap };
