(function () {
    'use strict';

    var labels = window.h4bsLocalSeo || {};

    function formatCount(template, count) {
        return String(template || '%d locations shown.').replace('%d', String(count));
    }

    function distanceBetween(lat1, lng1, lat2, lng2, unit) {
        var toRadians = function (value) { return value * Math.PI / 180; };
        var earthRadius = unit === 'kilometers' ? 6371 : 3958.8;
        var latitudeDistance = toRadians(lat2 - lat1);
        var longitudeDistance = toRadians(lng2 - lng1);
        var a = Math.sin(latitudeDistance / 2) * Math.sin(latitudeDistance / 2)
            + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2))
            * Math.sin(longitudeDistance / 2) * Math.sin(longitudeDistance / 2);
        return earthRadius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    }

    function initializeLocator(root) {
        var search = root.querySelector('[data-h4-local-search]');
        var radius = root.querySelector('[data-h4-local-radius]');
        var nearMe = root.querySelector('[data-h4-local-near-me]');
        var reset = root.querySelector('[data-h4-local-reset]');
        var status = root.querySelector('[data-h4-local-status]');
        var cards = Array.prototype.slice.call(root.querySelectorAll('[data-h4-local-card]'));
        var unit = root.getAttribute('data-unit') === 'kilometers' ? 'kilometers' : 'miles';
        var origin = null;

        function update() {
            var query = search ? search.value.trim().toLowerCase() : '';
            var maximum = radius ? Number(radius.value) : Infinity;
            var visible = 0;
            cards.forEach(function (card) {
                var matchesText = query === '' || (card.getAttribute('data-search') || '').indexOf(query) !== -1;
                var matchesDistance = true;
                var distance = null;
                var lat = Number(card.getAttribute('data-lat'));
                var lng = Number(card.getAttribute('data-lng'));
                if (origin && Number.isFinite(lat) && Number.isFinite(lng)) {
                    distance = distanceBetween(origin.latitude, origin.longitude, lat, lng, unit);
                    matchesDistance = distance <= maximum;
                }
                card.hidden = !(matchesText && matchesDistance);
                if (!card.hidden) {
                    visible += 1;
                }
                var distanceNode = card.querySelector('[data-h4-local-distance]');
                if (distanceNode) {
                    distanceNode.hidden = distance === null;
                    distanceNode.textContent = distance === null ? '' : distance.toFixed(1) + ' ' + unit;
                }
            });
            if (status) {
                status.textContent = formatCount(visible === 1 ? labels.oneLocation : labels.manyLocations, visible);
            }
            if (reset) {
                reset.hidden = query === '' && !origin;
            }
        }

        if (search) {
            search.addEventListener('input', update);
        }
        if (radius) {
            radius.addEventListener('change', update);
        }
        if (nearMe) {
            nearMe.addEventListener('click', function () {
                if (!navigator.geolocation) {
                    if (status) {
                        status.textContent = labels.locationUnavailable || 'Location access is not available in this browser.';
                    }
                    return;
                }
                nearMe.disabled = true;
                if (status) {
                    status.textContent = labels.findingLocation || 'Finding your location...';
                }
                navigator.geolocation.getCurrentPosition(function (position) {
                    origin = {
                        latitude: position.coords.latitude,
                        longitude: position.coords.longitude
                    };
                    nearMe.disabled = false;
                    update();
                }, function () {
                    nearMe.disabled = false;
                    if (status) {
                        status.textContent = labels.locationDenied || 'Your location could not be used. Search by city or postal code instead.';
                    }
                }, { enableHighAccuracy: false, timeout: 8000, maximumAge: 300000 });
            });
        }
        if (reset) {
            reset.addEventListener('click', function () {
                origin = null;
                if (search) {
                    search.value = '';
                }
                update();
                if (search) {
                    search.focus();
                }
            });
        }
        update();
    }

    function initialize() {
        document.querySelectorAll('[data-h4-local-locator]').forEach(initializeLocator);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initialize);
    } else {
        initialize();
    }
}());
