(function () {
    'use strict';

    const container = document.getElementById('campground_map');
    if (!container) {
        console.warn('could not find map container');
    }

    const svg = container.childNodes[0];
    svg.remove();

    const latLngBounds = L.latLngBounds([[0, 0], [1192, 1500]]);
    const map = L.map(container, {
        center: latLngBounds.getCenter(),
        minZoom: -2,
        maxZoom: 2,
        zoom: -1,
        scrollWheelZoom: false,
        maxBounds: latLngBounds,
        maxBoundsViscosity: 1.0,
        zoomSnap: 0,
        zoomDelta: 0.5,
        crs: L.CRS.Simple,
    });
    map.fitBounds(latLngBounds);
    L.svgOverlay(svg, latLngBounds).addTo(map);

    // from https://github.com/jkroso/parse-svg-path/
    const parse = (function () {
        'use strict';

        const length = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0}
        const segment = /([astvzqmhlc])([^astvzqmhlc]*)/ig;
        const number = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/ig;

        function parseValues(args) {
            const numbers = args.match(number)
            return numbers ? numbers.map(Number) : []
        }

        return function (path) {
            const data = []
            path.replace(segment, function (_, command, args) {
                let type = command.toLowerCase()
                args = parseValues(args)

                // overloaded moveTo
                if (type === 'm' && args.length > 2) {
                    data.push([command].concat(args.splice(0, 2)))
                    type = 'l'
                    command = command === 'm' ? 'l' : 'L'
                }

                while (true) {
                    if (args.length === length[type]) {
                        args.unshift(command)
                        return data.push(args)
                    }
                    if (args.length < length[type]) throw new Error('malformed path data')
                    data.push([command].concat(args.splice(0, length[type])))
                }
            })
            return data
        }
    })();

    function highlightAccommodation(e) {
        const layer = e.target;
        layer.setStyle({
            color: '#ffe673',
        });
    }

    function resetHighlight(e) {
        const layer = e.target;
        layer.setStyle({
            color: 'transparent',
        });
    }

    function getPath(el) {
        if (!el) {
            return el;
        }
        switch (el.localName) {
            case 'path':
            case 'rect':
                return el;
            case 'g':
                return getPath(el.firstElementChild);
            default:
                console.warn('unhandled element type', el.localName);
                return null
        }
    }

    function getCTM(ctm, el) {
        if (el.localName === 'svg') {
            return ctm;
        }
        const transform = el.getAttribute('transform');
        if (!transform) {
            return getCTM(ctm, el.parentElement);
        }
        const matrix = new DOMMatrix(transform);
        return getCTM(matrix.multiply(ctm), el.parentElement);
    }

    function convertToPoints(path) {
        const ctm = getCTM(new DOMMatrix([1, 0, 0, 1, 0, 0]), path);
        const points = [];
        const p0 = new DOMPoint();

        function setP0(x, y) {
            p0.x = x;
            p0.y = y;
            const p1 = p0.matrixTransform(ctm);
            p0.x = p1.x;
            p0.y = latLngBounds.getNorth() - p1.y;
        }

        switch (path.localName) {
            case 'rect':
                const x = parseFloat(path.getAttribute('x'));
                const y = parseFloat(path.getAttribute('y'));
                const w = parseFloat(path.getAttribute('width'));
                const h = parseFloat(path.getAttribute('height'));
                setP0(x, y);
                points.push([p0.y, p0.x]);
                setP0(x + w, y);
                points.push([p0.y, p0.x]);
                setP0(x + w, y + h);
                points.push([p0.y, p0.x]);
                setP0(x, y + h);
                points.push([p0.y, p0.x]);
                break;
            case 'path':
                const commands = parse(path.getAttribute('d'));
                for (const cmd of commands) {
                    switch (cmd[0]) {
                        case 'M':
                        case 'L':
                            setP0(cmd[1], cmd[2]);
                            break;
                        case 'm':
                        case 'l':
                            p0.x += cmd[1];
                            p0.y -= cmd[2];
                            break;
                        case 'C':
                            setP0(cmd[5], cmd[6]);
                            break;
                        case 'Z':
                        case 'z':
                            continue;
                        default:
                            console.error(cmd);
                    }
                    points.push([p0.y, p0.x]);
                }
                break;
        }
        return points;
    }

    function setupFeatures(prefix, baseURI) {
        for (const campsite of Array.from(container.querySelectorAll(`[id^="${prefix}"]`))) {
            const label = campsite.id.substring(prefix.length);
            if (!label) {
                continue;
            }
            const path = getPath(campsite);
            if (!path) {
                console.warn(campsite, 'has no path');
                continue;
            }

            const points = convertToPoints(path);
            const feature = L.polygon(points, {color: 'transparent'}).addTo(map);
            feature.on({
                mouseover: highlightAccommodation,
                mouseout: resetHighlight,
                click: function () {
                    window.location = `${baseURI}/${label}`;
                },
            })
        }
    }

    const language = document.documentElement.getAttribute('lang');
    setupFeatures('cp_', `/${language}/campsites`);
    setupFeatures('cr_', `/${language}/amenities`);

    const zones = container.querySelector('#zones');
    const zonesOverlay = L.layerGroup();
    for (const path of Array.from(zones.querySelectorAll('path'))) {
        const points = convertToPoints(path);
        const zone = L
            .polygon(points, {color: 'var(--accent)'})
            .bindTooltip(path.getAttribute('aria-label'), {permanent: true})
        ;
        zonesOverlay.addLayer(zone);
    }
    L.control.layers(null, null, {collapsed: false})
        .addOverlay(zonesOverlay, zones.getAttribute('aria-label'))
        .addTo(map)
    ;

    const params = new URLSearchParams(window.location.search);
    if (params.has('zones')) {
        map.addLayer(zonesOverlay);
    }
})();
