// from django/contrib/admin/static/admin/js/urlify.js
var LATIN_MAP = {
    'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE',
    'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I',
    'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O',
    'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U',
    'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a',
    'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c',
    'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i',
    'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o',
    'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',
    'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
};

function downcode(string) {
  return string.toLowerCase().replace(/[^A-Za-z0-9\[\] ]/g,function(a){ return LATIN_MAP[a]||a })
};

$(function() {
  var $sidebar = $('#sidebar');
  var is_authenticated = ($('body.authenticated-user').length == 1);
  if (document.getElementById('known-tile-types')) {
    var known_tile_types = JSON.parse(document.getElementById('known-tile-types').textContent);
  }
  var markers_with_no_tiles = new Object();

  /* focus tracking */
  $('input:not([type=checkbox]):not([type=radio]), textarea').focusin(function() {
    $('body').addClass('focus-in');
    $(window).trigger('toodego:map-size');
  }).focusout(function() {
    $('body').removeClass('focus-in');
    $(window).trigger('toodego:map-size');
  });

  /* add & remove tile */
  $('div.cell, div#sidebar').delegate('a.remove-from-dashboard', 'click', function(e) {
    var dashboard = $(this).parents('.dashboardcell');
    var cell = $(this).parents('.cell')[0];
    var link = $(this);
    $.ajax({
      url: $(this).attr('href'),
      success: function(data) {
        if (dashboard.length) {
          /* if the user is on the dashboard, remove tile from screen */
          $(cell).hide({
            duration: 300,
            complete: function() {
              $(cell).remove();
            }
          });
        } else {
          $(link).hide();
          $(link).parent().find('.cell-added').remove();
          var $add_to_dashboard = $('<a class="add-to-dashboard new"></a>');
          $add_to_dashboard.attr('href', data.cell_data.add_url);
          $add_to_dashboard.appendTo($(link).parent());
          $(link).remove();
        }
      }
    });
    e.stopPropagation();
    return false;
  });
  $('div.cell, div#sidebar').delegate('a.add-to-dashboard', 'click', function(e) {
    var link = $(this);
    if (link.hasClass('fake')) {
      var next_uri = $(this).attr('href');
      var $dialog = $('<div id="connect-dialog"><span class="close">×</span>' +
                      "<p>La mise en favori nécessite d'être connecté.</p>" +
                      '<div><a class="pk-button" href="/login/?next=' + next_uri +
                              '">Connectez-vous</a>' +
                      '     <a class="pk-button" href="/connect/register/?next=' + next_uri +
                              '">Créer un compte</a></div>' +
                      "</div>");
      $dialog.on('click', function() {
        $dialog.remove();
      });
      $dialog.appendTo($('body'));
    } else {
      $.ajax({
        url: $(this).attr('href'),
        success: function(data) {
          $(link).hide();
          var $added_info = $('<span class="cell-added">Ajouté à votre tableau de bord</span>');
          $added_info.appendTo($(link).parent());
          setTimeout(function() { $added_info.remove(); }, 3000);
          var $remove_from_dashboard = $('<a class="remove-from-dashboard new"></a>');
          $remove_from_dashboard.attr('href', data.cell_data.remove_url);
          $remove_from_dashboard.appendTo($(link).parent());
          $(link).remove();
        }
      });
    }
    e.stopPropagation();
    return false;
  });

  /* map filters */
  var $filtres_carte = $('#filtres-autour-de-moi, #filtres-carte');
  if ($filtres_carte.length) {
    $filtres_carte.detach().appendTo('.combo-cell-map');
    $('<button class="filter-button">Filtrer</button>').appendTo('#mapsearch form');
  }
  $('#mapsearch .filter-button').on('click', function() {
    $(this).toggleClass('on');
    $filtres_carte.toggle();
    if ($(this).hasClass('on')) {
      var mql = window.matchMedia("(max-width: 1100px)");
      if (mql.matches) {
        $('#sidebar .cell').removeClass('selected');
        $('#sidebar').css('min-height', 0);
      }
    }
    return false;
  });
  $filtres_carte.find('a').on('click', function(ev) {
    var href = $(this).attr('href');
    if (href[0] == '?') { // layer filter
      var layer_slug = href.substr(1);
      var map = $map_widget[0].leaflet_map;
      $(this).toggleClass('on');
      if ($(this).hasClass('on')) {
        if ($filtres_carte.find('a.on').length == 1) {
          // initial filter, disable all
          map.disable_all_layers();
        }
        map.enable_layer(layer_slug);
      } else {
        if ($filtres_carte.find('a.on').length == 0) {
          // no more filter, enable all
          map.enable_all_layers();
        } else {
          map.disable_layer(layer_slug);
        }
      }
      $sidebar.empty();
      $(document).trigger('gnm:new-results');
      $('#mapsearch .filter-button').trigger('click');  // close filter pane
      return false;
    }
    return true;
  });

  /* map/marker tile */
  function map_marker_identifier(slug, marker) {
    return slug + ':' + (
                  marker.feature.properties.gid ||
                  marker.feature.properties.id ||
                  marker.feature.properties.pkgid ||
                  marker.feature.properties.identifiant);
  }

  function map_marker_tile(map, marker_tile_identifier, marker, options) {
    if (!options) options = Object();
    var marker_tile_cache = map.geojson_tile_cache[marker_tile_identifier];
    var $tile = $('[data-leaflet-id="' + marker_tile_identifier + '"]');
    if ($tile.length == 0) {
      $tile = $('<div class="cell" data-leaflet-id="' + marker_tile_identifier + '"><div class="tile">' +
                '<div class="tile-picture"></div>' +
                '<div class="tile-head"><div class="tile-title"><h2></h2><span class="producer"></span></div></div>' +
              ' </div></div>');
    }
    $tile.html(marker_tile_cache.html);
    if ($tile.find('[data-tile-cache]').length == 0) {
      map.geojson_tile_cache[marker_tile_identifier].html = null;
    } else {
      var now = new Date().getTime() / 1000;
      if (options.init) {
        var cache = parseInt($tile.find('[data-tile-cache]').data('tile-cache'));
        map.geojson_tile_cache[marker_tile_identifier].expire = now + cache / (1 + Math.random());
      } else {
        if (map.geojson_tile_cache[marker_tile_identifier].expire > now) {
          map.geojson_tile_cache[marker_tile_identifier].html = null;
        }
      }
    }
    $sidebar.removeClass('empty');
    $sidebar.removeClass('loading');
    $('#empty-map-results').remove();
    if (options.move_first) {
      $tile.detach().prependTo($sidebar);
      $sidebar[0].scrollTop = 0;
    }

    if (options.select) {
      $('#sidebar .cell').removeClass('selected');
      $tile.addClass('selected');
      /* on mobile, increase search zone height to make cell visible */
      var mql = window.matchMedia("(max-width: 1100px)");
      if (mql.matches) {
        $('#sidebar').css('min-height', $tile.height() + 10);
      }
    }

    $tile[0].matching_marker = marker;
    marker.matching_tile = $tile;
    $tile.off('click').on('click', function(ev) {
      if (ev.target.nodeName != 'A') {
        var zoom_level = 18;
        if (map.getZoom() > zoom_level) {
          // no unzooming to avoid clusters reappearing (#26554)
          zoom_level = map.getZoom();
        }
        map.flyTo(marker.getLatLng(), zoom_level);
        $('#sidebar .cell').removeClass('selected');
        $tile.addClass('selected');
      }
      return true;
    });
  }

  /* map search */
  $('.search-page div.cell.map').addClass('loading').on('combo:map-markers-ready', function() {
    $(this).removeClass('loading');
    $('span.layer-fontaine-eau-potable').attr('title', 'Fontaine d’eau potable');
    $('span.layer-fontaine-ornementale').attr('title', 'Fontaine ornementale');
    $('span.layer-borne-fontaine').attr('title', 'Borne fontaine');
  });
  if ($('div.combo-cell-map.leaflet-container').length) {
    $(window).on('resize orientationchange toodego:map-size', function() {
      var mql = window.matchMedia("(max-width: 1100px)");
      if (mql.matches) {
        var new_height = $(window).height() - $('#header').height();
        if (! $('body').hasClass('focus-in')) {
          new_height = new_height - $('#nav').height();
        }
        $('div.combo-cell-map.leaflet-container').height(new_height);
      } else {
        $('div.combo-cell-map.leaflet-container').height('auto');
      }
    }).trigger('toodego:map-size');
  }
  $('.search-page div.cell.map').on('combo:map-feature-prepare', function(ev, info) {
    var geojson_layer_slug = info.geojson_layer.slug;
    if (known_tile_types.indexOf(geojson_layer_slug) == -1) {
      // no tile for those.
      markers_with_no_tiles[geojson_layer_slug] = true;
      return;
    }
    if ($sidebar.length == 0) {
      return;
    }
    info.layer.on('click', function(ev) {
      var marker = info.layer;
      var marker_tile_identifier = map_marker_identifier(geojson_layer_slug, marker);
      var $matching_tile = $('[data-leaflet-id="' + marker_tile_identifier + '"]');
      $('.leaflet-marker-icon.loading').removeClass('loading');
      if ($matching_tile.length) {
        if ($matching_tile.hasClass('selected')) {
          /* second click on same tile */
          var mql = window.matchMedia("(max-width: 1100px)");
          if (mql.matches) {
            $('#sidebar').css('min-height', 0);
            $('#sidebar .cell').removeClass('selected');
          }
          return;
        }
        $('#sidebar .cell').removeClass('selected');
        $matching_tile.addClass('selected');
        var $selected_cell = $('#sidebar .cell.selected');
        if ($selected_cell.prev().length) {
          $selected_cell.prependTo($selected_cell.parent());
          $sidebar[0].scrollTop = 0;
        }
        /* on mobile, increase search zone height to make cell visible */
        var mql = window.matchMedia("(max-width: 1100px)");
        if (mql.matches) {
          $('#sidebar').css('min-height', $selected_cell.height() + 10);
        }
        return;
      }
      /* dynamically load tile and put it first */
      var marker_tile_cache = map.geojson_tile_cache[marker_tile_identifier];
      if (marker_tile_cache && marker_tile_cache.html) {
        var mql = window.matchMedia("(max-width: 1100px)");
        if (mql.matches) {
          map_marker_tile(map, marker_tile_identifier, marker, {init: false, move_first: true});
        } else {
          map_marker_tile(map, marker_tile_identifier, marker, {init: false});
        }
      } else {
        map.geojson_tile_cache[marker_tile_identifier] = Object();
        map.geojson_tile_cache[marker_tile_identifier].loading = true;
        $(marker._icon).addClass('loading');
        $.ajax({
          url: '/api/dashboard/auto-tile/' + geojson_layer_slug + '/',
          data: JSON.stringify(ev.target.feature.properties),
          contentType: 'application/json; charset=utf-8',
          type: 'POST',
          dataType: 'html',
          success: function(html) {
            $(marker._icon).removeClass('loading');
            map.geojson_tile_cache[marker_tile_identifier].html = html;
            map.geojson_tile_cache[marker_tile_identifier].loading = false;
            map_marker_tile(map, marker_tile_identifier, marker, {init: true, move_first: true, select: true});
            return;
          }
        });
      }
    });
  });

  var MAX_DISPLAYED_RESULTS = 5;
  var $map_search_input = $('#mapsearch input');
  var is_autour_de_moi = $('body').hasClass('section-autour-de-moi');
  if ($map_search_input.length) {
    var $map_widget = $('div.combo-cell-map');
    var map = $map_widget[0].leaflet_map;
    var search_timeout_id = null;
    map.q_center_lat = null;
    map.q_center_lng = null;

    function get_distance(lat1, lng1, lat2, lng2) {
        // simplest distance approximation https://www.mkompf.com/gps/distcalc.html
        deglen = 111300;
        x = lat1 - lat2;
        lat = (lat1 + lat2) / 2 * 0.01745;
        y = (lng1 - lng2) * Math.cos(lat1);
        return deglen * Math.sqrt(x * x + y * y);
    }

    function reset_map_query_string() {
      map.query_string = "";
      if (is_autour_de_moi) {
        var center = map.getCenter();
        var distance_q = '&distance=1000';
        map.query_string += distance_q + '&lat=' + center.lat + '&lng=' + center.lng;
        map.q_center_lat = center.lat;
        map.q_center_lng = center.lng;
      }
    }

    function get_mapsearch_query() {
      var query = $('#mapsearch input').val();
      query = query.toLowerCase();
      query = query.replace(/^rue\s/i, '');
      return query;
    }

    function refresh_around_me_query(map) {
      var query = get_mapsearch_query();
      if (query.length < 2) {
        map.query_string = '';
      } else {
        map.query_string = 'q=' + query;
      }
      var center = map.getCenter();
      var collectivity_slugs = JSON.parse(document.getElementById('collectivity-slugs').textContent);
      var distance_q = '&distance=1000';

      for (var i=0; i<collectivity_slugs.length; i++) {
        if (downcode(query).indexOf(collectivity_slugs[i]) != -1) {
          distance_q = '';
          break;
        }
      }
      if (distance_q) {
        map.q_center_lat = center.lat;
        map.q_center_lng = center.lng;
        map.query_string += distance_q + '&lat=' + center.lat + '&lng=' + center.lng;
      }
    }

    function refresh_markers(map) {
      $('.search-page div.cell.map').addClass('loading');
      map.load_geojson_layers();
    }

    $map_search_input.on('change keyup paste search', function(e) {
      var keycode = e.which || e.keyCode;
      if (keycode == 13) {  // enter
        $(this).blur();
        return false;
      }
      if (keycode < 49 /* 0 */ && keycode != 8 /* backspace */ && keycode != 46 /* del */) {
        return false;
      }
      $sidebar.empty();
      clearTimeout(search_timeout_id);
      search_timeout_id = setTimeout(function() {
        var query = get_mapsearch_query();
        var new_geojson_layers = null;
        if (query.length == 0) { // reset view
          reset_map_query_string();
          var initial_zoom = parseInt($map_widget.data('init-zoom'));
          map.setZoom(initial_zoom);
        } else if (query.length < 2) {
          return;  // don't react on short query
        } else {
          map.query_string = 'q=' + query;
          if (is_autour_de_moi) {
            refresh_around_me_query(map);
          }
        }

        if (query) {
          var search_value = $('#mapsearch input').val();
          var _paq = window._paq = window._paq || [];
          if (_paq && typeof(_paq.push) == 'function') {
            _paq.push(['trackSiteSearch', search_value, false, false]);
          }
        }

        search_timeout_id = null;
        refresh_markers(map);
      }, 300);
    });
    $('#mapsearch').on('submit', function() {
      // live search but we trigger the change event to be sure
      $map_search_input.trigger('change');
      track_search($map_search_input.val());
      return false;
    });
    $(map).on('movestart', function() {
      var mql = window.matchMedia("(max-width: 1100px)");
      if (mql.matches) {
        $('#sidebar .cell').removeClass('selected');
        $('#sidebar').css('min-height', 0);
      }
    });
    var map_move_timeout_id = null;
    $(map).on('zoomend moveend', function() {
      if (is_autour_de_moi) {
        /* if map is moved enough, refresh */
        var center = map.getCenter();
        if (map_move_timeout_id) clearTimeout(map_move_timeout_id);
        map_move_timeout_id = setTimeout(function() {
          map_move_timeout_id = null;
          var distance = get_distance(map.q_center_lat, map.q_center_lng, center.lat, center.lng);
          if (distance > 250) {
            refresh_around_me_query(map);
            refresh_markers(map);
          }
        }, 300);
      }
      $(document).trigger('gnm:new-results');
    });

    if (map.geojson_tile_cache === undefined) {
      map.geojson_tile_cache = Object();
    }
    $(document).on('gnm:new-results', function(ev, params) {
      params = params || {};
      if (map.clustered_markers) {
        map.clustered_markers.on('spiderfied', function() {
          $(document).trigger('gnm:new-results', {'loadmore': true});
        });
      }
      if ($sidebar.length == 0) return;
      if (! params.loadmore) {
        $sidebar.addClass('loading');
      }
      var counter = 0;
      var tile_counter = 0;
      var marker_without_tile_counter = 0;
      var cluster_groups = Array();
      $sidebar.find('> div.cell').each(function(idx, tile) {
        // remove out of bounds results
        if (tile.matching_marker == undefined || ! map.getBounds().contains(tile.matching_marker.getLatLng())) {
          if (tile.matching_marker) {
            tile.matching_marker.matching_tile = null;
          }
          $(tile).remove();
        }
      });
      map.each_marker(function(marker) {
          if (! map.hasLayer(marker)) {
            return;
          }
          if (marker.feature.geometry.type != 'Point') {
            return;
          }
          if (! map.getBounds().contains(marker.getLatLng())) {
            return;
          }
          var marker_tile_identifier = map_marker_identifier(this.slug, marker);
          var $tile = $('[data-leaflet-id="' + marker_tile_identifier + '"]');
          if ($tile.length && params.loadmore) {
            return;
          }
          var $marker_icon_html = $(marker.options.icon.options.html);
          var markers_with_no_tiles_list = Object.keys(markers_with_no_tiles);
          for (var i=0; i<markers_with_no_tiles_list.length; i++) {
            if ($marker_icon_html.is('span.layer-' + markers_with_no_tiles_list[i])) {
              marker_without_tile_counter += 1;
              return;
            }
          }

          if (counter > MAX_DISPLAYED_RESULTS) return;
          counter += 1;

          if ($tile.length == 0) {
            $tile = $('<div class="cell" data-leaflet-id="' + marker_tile_identifier + '"><div class="tile placeholder">' +
                      '<div class="tile-picture"></div>' +
                      '<div class="tile-head"><div class="tile-title"><h2></h2><span class="producer"></span></div></div>' +
                    ' </div></div>');
            $tile.appendTo($sidebar);
          }

          var marker_tile_cache = map.geojson_tile_cache[marker_tile_identifier];
          if (marker_tile_cache && marker_tile_cache.loading) {
            // pass
          } else if (marker_tile_cache && marker_tile_cache.html) {
            map_marker_tile(map, marker_tile_identifier, marker, {init: false});
          } else {
            map.geojson_tile_cache[marker_tile_identifier] = Object();
            map.geojson_tile_cache[marker_tile_identifier].loading = true;
            $.ajax({
              url: '/api/dashboard/auto-tile/' + this.slug + '/',
              data: JSON.stringify(marker.feature.properties),
              contentType: 'application/json; charset=utf-8',
              type: 'POST',
              dataType: 'html',
              success: function(html) {
                map.geojson_tile_cache[marker_tile_identifier].html = html;
                map.geojson_tile_cache[marker_tile_identifier].loading = false;
                map_marker_tile(map, marker_tile_identifier, marker, {init: true});
              }
            });
          }
      });
      if (counter == 0) {
        /* remove loading marker if there were no tiles */
        $sidebar.removeClass('loading');
      }
      if (counter == 0 && $('div.cell.map.loading').length == 0) {
        $sidebar.addClass('empty');
        var $empty = $('#empty-map-results');
        if ($empty.length == 0 && $sidebar.find('> div.cell').length == 0 && ! params.loadmore) {
          $empty = $('<p id="empty-map-results"></p>');
          if (marker_without_tile_counter == 0) {
            $empty.text('Aucun résultat dans cette zone.');
          } else {
            $empty.text('');
          }
          $empty.appendTo($sidebar);
        }
      }
    });
    $('div.cell.map').on('combo:map-markers-ready', function() {
      var map_bounds = map.getBounds();
      var found = 0;
      var found_in_padded_bounds = 0;
      var query =  $('#mapsearch input').val();
      map.each_marker(function(marker) {
        found++;
        if (marker.feature.geometry.type == 'Point') {
          if (map_bounds.contains(marker.getLatLng())) {
            found_in_padded_bounds++;;
          }
        }
      });

      if (found_in_padded_bounds) {
        /* don't do anything, just get the markers filtered */
      }
      else if (found && !found_in_padded_bounds) {
        /* no visible marker */
        if (is_autour_de_moi) {
          /* on "autour de moi" page, don't move, just zoom out */
          var min_zoom = parseInt($map_widget.data('min-zoom'));
          if (query.length > 0 && map.getZoom() > min_zoom) {
            // actual query, zoom out, to get more results
            map.setZoom(min_zoom);
          }
        } else {
          map.flyToBounds(map.bounds);
        }
      }
      else {
        /* no markers at all */
      }
      $(document).trigger('gnm:new-results');
    });
    $map_search_input.trigger('change');

    $('div.suggestions span').on('click', function() {
      $map_search_input.val($(this).text()).trigger('change');
    });

    $sidebar.scroll(function() {
      if ($sidebar.scrollTop() + $sidebar.innerHeight() >= $sidebar[0].scrollHeight) {
        if ($sidebar.hasClass('everything-loaded')) {
          return;
        }
        $(document).trigger('gnm:new-results', {'loadmore': true});
      }
    });
  }

  /* map on place pages */
  $('#content').delegate('.is-place div.cell.map', 'gnm:add-marker combo:map-ready', function() {
    var $map_widget = $(this).find('div.combo-cell-map');
    var map = $map_widget[0].leaflet_map;
    var place_type = $(this).parents('.tile').data('place-type');
    if (place_type) {
      var marker = L.divIcon({
          iconAnchor: [0, 0],
          popupAnchor: [5, -45],
          html: '<span class="layer-' + place_type + '"><i class="leaflet-marker-icon"></i></span>'
      });
      var marker_style = document.createElement('style');
      document.head.appendChild(marker_style);
      var style_sheet = marker_style.sheet;
      style_sheet.insertRule('.leaflet-div-icon span.layer-' + place_type + '{' +
              'background-image: url(/assets/maplayer:marker:' + place_type + ');' +
              '}');
      L.marker([$map_widget.data('init-lat'), $map_widget.data('init-lng')], {icon: marker}).addTo(map);
    }
  });
  if ($('#content .is-place div.cell.map').length) {
    var $map_widget = $(this).find('div.combo-cell-map');
    var map = $map_widget[0].leaflet_map;
    if (map !== undefined) {
      map.whenReady(function() {
       $('.is-place div.cell.map').trigger('gnm:add-marker');
      });
    }
  }

  /* section collapsing/expanding */
  $('#columns').delegate('div.group-title', 'click', function() {
    if ($(this).parents('.edit-mode').length) {
      return false;
    }
    var expand = $(this).hasClass('closed');
    var tile = $(this);
    var dashboard_parent = ($(this).parents('.dashboardcell').length == 1);
    while (true) {
      tile = $(tile).next();
      if (tile.length == 0) break;
      if (tile.hasClass('dashboardcell')) {
        tile = $(tile).find('.cell').first();
        dashboard_parent = true;
      }
      if (tile.hasClass('wcscurrentformscell') || tile.hasClass('wcscurrentdraftscell')) {
        /* get inside */
        tile = $(tile).find('.tile');
      }
      if (tile.hasClass('group-title')) {
        break;
      }
      if (! (tile.hasClass('tile') || tile.hasClass('linkcell') || dashboard_parent)) {
        break;
      }
      if (expand) {
        $(tile).removeClass('closed');
      } else {
        $(tile).addClass('closed');
      }
    }
    if (expand) {
      $(this).removeClass('closed');
    } else {
      $(this).addClass('closed');
    }
  });

  /* add service count labels */
  if ($('.dashboardcell').length == 0) {
    $('.group-title').each(function() {
      var $group = $(this);
      var count = 0;
      var tile = $(this);
      while (true) {
        tile = $(tile).next();
        if (tile.length == 0) break;
        if (tile.hasClass('group-title')) {
          break;
        }
        if (! (tile.hasClass('tile') || tile.hasClass('linkcell'))) {
          break;
        }
        count += 1;
      }
      if (count) {
        $(this).find('h2').append(' <span class="count">(' + count + ')</span>');
      }
    });
  }

  /* dashboard ordering */
  $('div.dashboardcell').delegate('div.tile a', 'click', function(e) {
    e.stopPropagation();
  });

  $('.dashboardcell').delegate('div.tile', 'click', function() {
    $(this).parents('.dashboard-content').toggleClass('edit-mode');
    /* remove empty cells from DOM */
    $(this).parents('.dashboard-content').find('.cell').each(function(idx, elem) {
      if ($(elem).find('.tile').length == 0 && ! $(elem).hasClass('group-title')) {
        $(elem).remove();
      }
    });
    return false;
  });

  $('.dashboardcell').delegate('div.group-title span.move-down', 'click', function() {
    var $cell = $($(this).closest('.cell')[0]);
    $cell = $cell.next('.cell');
    $cell.find('span.move-up').trigger('click');
  });

  $('.dashboardcell').delegate('div.cell span.move-up', 'click', function() {
    if ($(this).parents('.edit-mode').length == 0) return;
    var $cell = $($(this).closest('.cell')[0]);
    if ($cell.prev().length == 0) {
      $cell = $cell.next('.cell');
    }
    var tile_bottom_margin = 14 / 2; /* see _tiles.css */
    var cell_height = $cell.height() + tile_bottom_margin;
    var $dashboard_content = $(this).closest('.dashboard-content');
    var $prev_cell = $($cell.prev()[0]);
    var prev_cell_height = $prev_cell.height() + tile_bottom_margin;
    $prev_cell.insertAfter($cell);
    var new_order = $.map($dashboard_content.find('> div'), function(val) { return $(val).data('tile-id'); }).join(',');
    $.ajax({
      url: $dashboard_content.data('dashboard-reorder-url') + '?order=' + new_order,
    });
    $cell.css('transition-duration', '0ms');
    $cell.css('z-index', '100');
    $prev_cell.css('transition-duration', '0ms');
    $cell[0].offsetHeight; /* commit */
    $cell.css('transform', 'translate(0px, ' + prev_cell_height + 'px)');
    $prev_cell.css('transform', 'translate(0px, -' + cell_height + 'px)');
    $cell[0].offsetHeight; /* commit */
    $cell.css('transition-duration', '300ms');
    $prev_cell.css('transition-duration', '300ms');
    $cell[0].offsetHeight; /* commit */
    $cell.css('transform', 'translate(0px, 0)');
    $prev_cell.css('transform', 'translate(0px, 0)');
    setTimeout(function() { $cell.css('z-index', '0'); }, 300);

    return false;
  });

  /* dashboard intertitles */
  $('#add-section').delegate('a', 'click', function() {
    var $dialog_content = $('<div><form><p>Veuillez saisir le nom de la catégorie :</p><input type="text" required></form></div>');
    $dialog_content.find('form').on('submit', function() {
      var title = $dialog_content.find('input').val();
      $.ajax({
        url: '/api/dashboard/auto-tile/group-title/',
        data: JSON.stringify({'text': title}),
        contentType: 'application/json; charset=utf-8',
        type: 'POST',
        dataType: 'html',
        success: function(html, status, jqxhr) {
          var url = jqxhr.getResponseHeader('x-add-to-dashboard-url');
          $.ajax({
            url: url,
            success: function(data) {
              combo_load_cell($('div.dashboardcell'));
              $dialog_content.dialog('destroy');
                    window.scrollTo($('div.dashboardcell').position());
            }
          });
        }
      });
      return false;
    });
    $dialog_content.dialog({
      classes: {'ui-dialog': 'new-intertitle'},
      modal: true,
      title: 'Nouvelle catégorie',
      buttons: [
        {text: 'Annuler', 'class': 'cancel-button', click: function() { $(this).dialog('destroy'); } },
        {text: 'Valider',
         click: function() {
           $dialog_content.find('form').trigger('submit');
         }
        }
      ]
    });
    return false;
  });
  $('.dashboardcell').delegate('div.group-title span.remove', 'click', function() {
    var cell = $(this).parents('.cell')[0];
    $.ajax({
      url: $(this).data('url'),
      success: function(data) {
        $(cell).hide({
          duration: 300,
          complete: function() {
            $(cell).remove();
          }
        });
      }
    });
  });

  /* nearby demands */
  if ($('#nearby-list').length) {
    $(document).on('wcs:maps-ready', function() {
      var $map_widget = $('.qommon-map');
      var map = $map_widget[0].leaflet_map;
      var geojson_data = Array();
      $('#nearby-list div[data-id]').each(function(idx, elem) {
        var feature = {
          type: 'Feature',
          properties: {
            id: $(elem).data('id'),
            counter: $(elem).find('.marker-counter').text()
          },
          geometry: {
            type: 'Point',
            coordinates: [$(elem).data('geoloc-lon'), $(elem).data('geoloc-lat')]
          }
        };
        geojson_data.push(feature);
      });

      $(map).on('zoomend moveend', function() {
        /* filter display of nearby items to match the displayed map area */
        var nearby_list = $('#nearby-list');
        nearby_list.find('> div').hide();
        map.eachLayer(function(layer){
          if (layer instanceof L.Marker && map.getBounds().contains(layer.getLatLng())) {
            if (layer.feature && layer.feature.properties.id) {
              nearby_list.find('[data-id="' + layer.feature.properties.id + '"]').show();
              return;
            }
          }
        });
      });

      if (geojson_data) {
        var geo_json = L.geoJson(geojson_data,
          {
            pointToLayer: function (feature, latlng) {
              marker = L.divIcon({
                                  iconAnchor: [0, 0],
                                  popupAnchor: [5, -45],
                                  html: '<a href="#nearby-' + feature.properties.counter + '">' +
                                         feature.properties.counter + '</a>'
                                 });
              return L.marker(latlng, {icon: marker});
            }
          });
        geo_json.addTo(map);
        $(map).trigger('moveend');
      }

      $('a.plus1').on('click', function() {
        var plus1_url = $(this).data('plus1-url');
        var $dialog = null;
        if (is_authenticated) {
          $dialog = $('<div id="plus1-dialog">' +
                      '<p>Vous allez confirmer le signalement. Vous pouvez ' +
                      'également décider de recevoir un message une fois ' +
                      'celui-ci pris en charge.</p>' +
                      '<label><input type="checkbox">Recevoir un message</input></label>' +
                      '</div>');
        } else {
          $dialog = $('<div id="plus1-dialog">' +
                      '<p>Vous allez confirmer le signalement.</p>' +
                      '</div>');
        }
        $dialog.dialog({
          modal: true,
          buttons: [
                    {text: 'Annuler',
                     'class': 'cancel-button',
                     click: function() {
                       $(this).dialog('destroy');
                     }
                    },
                    {text: 'Confirmer',
                     click: function() {
                       var checked = ($(this).find('[type=checkbox]:checked').length > 0);
                       $.ajax({
                         url: plus1_url,
                         data: JSON.stringify({'checked': checked}),
                         type: 'POST',
                         contentType: 'application/json; charset=utf-8',
                         dataType: 'json',
                         success: function(resp) {
                           $dialog.dialog('destroy');
                           $map_widget.parent().find('[type=hidden]').val('0;0');
                           $('div.buttons button[name=submit]').click();
                         }
                       });
                     }
                    }
                   ],
          close: function() {}
        });
        return false;
      });
    });
  }
  if ($('.signalement-thanks').length) {
    $('div.buttons div.submit-button, div.buttons div.previous-button').hide();
    $('.step-after').remove();
    $('div.buttons div.cancel-button button').text('Continuer').css('margin-right', '0');
  }

  /* photo upload, add a preview */
  $('.file-button.file-image').on('wcs:image-blob', function(ev, file) {
    var $widget = $(this);
    if (file) {
      var reader = new FileReader();
      reader.onload = function(e) {
        $widget[0].style.backgroundImage = 'url(' + e.target.result + ')';
      }
      reader.readAsDataURL(file);
    }
  });

  /* custom checkboxes intertitles for publik notification */
  $('.template-pn-thematiques').each(function(idx, elem) {
    const titles = Array();
    $(elem).find('li label span').each(function(idx, label) {
      const title = $(label).text().split('/')[0];
      if (titles.indexOf(title) == -1) {
        const $title_tag = $('<li class="intertitle"><strong>' + title + '</strong></li>');
        $title_tag.prependTo($(label).parents('li').first());
        titles.push(title);
      }
      $(label).text($(label).text().split('/')[1]);
    });
  });

  /* collectivity selector */
  $('div.mairie-usager').delegate('select#collectivities', 'change', function(a, b) {
    var $selected = $(this).find(':selected');
    if ($selected.data('url')) {
      window.location = $selected.data('url');
    }
  });

  /* notifications */
  $('div.notification').on('click', function() {
    var cell = $(this);
    if ($(cell).hasClass('acked')) {
      if ($(cell).find('h3 a').length) {
        window.location.href = $(cell).find('h3 a').attr('href');
      }
      return false;
    }
    var ack_url = $(this).data('combo-notification-ack-url');
    $.ajax({
         url: ack_url,
         success: function(html) {
           $(cell).removeClass('new').addClass('acked');
           if ($(cell).find('h3 a').length) {
             window.location.href = $(cell).find('h3 a').attr('href');
           }
         }
    });
    return false;
  });
  $('div.notification a.delete').on('click', function(event) {
    var notification = $(this).parents('.notification');
    var forget_url = $(notification).data('combo-notification-forget-url');
    $.ajax({
         url: forget_url,
         success: function(html) {
           $(notification).hide({effect: 'fade', complete: function() { $(this).remove() }});
         }
    });
    return false;
  });

  /* click on "connectez-vous" blocks */
  $('div#connectez-vous').on('click', function() {
    window.location = '/login/';
    return false;
  });

  /* click on "ajouter un service" blocks */
  $('div#ajouter-service').on('click', function() {
    window.location = '/services/';
    return false;
  });

  $('#content').delegate('[data-switch-day-prev]', 'click', function() {
    $(this).parents('.tables').hide().prev().show();
  });

  $('#content').delegate('[data-switch-day-next]', 'click', function() {
    $(this).parents('.tables').hide().next().show();
  });

  $('#cell-filter input').on('focus', function(e) {
    var mql = window.matchMedia("(max-width: 1100px)");
    if (mql.matches) {
      $(window).scrollTop($(this).offset().top);
    }
    return false;
  });
  var visible_cells_counter = 0;
  $('#cell-filter input').on('change keyup paste', function(e) {
    if (e.keyCode == 13) {  // enter
      $(this).blur();
      return false;
    }
    var q = downcode($(this).val());
    visible_cells_counter = 0;
    if (q) {
      $('#columns > .tile, .dashboard-content > div.cell').each(function() {
        var cell_text = downcode($(this).text() + ' ' +
                $(this).find('[data-keywords]').data('keywords') + ' ' +
                $(this)[0].className);
        if (cell_text.search(q) == -1) {
          $(this).hide();
        } else {
          $(this).show();
        }
      });
      $('#columns > .group-title').each(function() {
        var $tile = $(this);
        var has_visible_cells = false;
        while (true) {
          $tile = $tile.next();
          if ($tile.hasClass('filter-empty')) continue;
          if ($tile.length == 0) break;
          if ($tile.hasClass('group-title')) break;
          if ($tile.is(':visible')) {
            has_visible_cells = true;
            visible_cells_counter += 1;
            break;
          }
        }
        if (has_visible_cells) {
          $(this).show();
        } else {
          $(this).hide();
        }
      });
      if (visible_cells_counter) {
        $('#columns > .filter-empty').remove();
      } else {
        if ($('.filter-empty').length == 0) {
          $('<div class="cell grid-1-1 newline filter-empty"><p>Aucun résultat.</p></div>').appendTo($('#columns'));
        }
      }
    } else {
      $('#columns > .tile, .dashboard-content > div.cell').show();
      $('#columns > .group-title').show();
    }
  });
  $('#cell-filter input').on('blur', function(e) {
    var search_value = $(this).val();
    if (search_value) {
      var _paq = window._paq = window._paq || [];
      if (_paq && typeof(_paq.push) == 'function') {
        _paq.push(['trackSiteSearch', search_value, false, visible_cells_counter]);
      }
    }
  });
  $('#cell-filter form').on('submit', function() {
    // live search but we trigger nevertheless
    $(this).find('input[type=search]').trigger('change');
    track_search($(this).find('input[type=search]').val());
    return false;
  });

  $(document).on('combo:cell-loaded', function(ev, elem) {
    /* "your profile" cell */
    var drafts_count = $('.wcscurrentdraftscell .tile').length
    var forms_count = $('.wcscurrentformscell .tile').length
    if ($('.wcscurrentdraftscell .tile.info').length) drafts_count = 0;
    if ($('.wcscurrentformscell .tile.info').length) forms_count = 0;
    $('.drafts-count').text(drafts_count);
    $('.forms-count').text(forms_count);
    if (drafts_count < 2) {
      $('.drafts-count').next().text('brouillon');
    } else {
      $('.drafts-count').next().text('brouillons');
    }
    if (forms_count < 2) {
      $('.forms-count').next().text('demande');
    } else {
      $('.forms-count').next().text('demandes');
    }
    if (drafts_count > 0) {
      $('#drafts-section').show();
    }
    if (forms_count > 0) {
      $('#forms-section').show();
    }
  });

  $('.cell.open-in-new-window a').each(function() {
    $(this).attr('target', '_blank').attr('rel', 'noopener');
  });

  // move backlink to the top
  $('.textcell.backlink').detach().prependTo('#main-content').show();

  // open submenu on click
  $('.menu-mon-compte > a').on('click', function() {
    if ($(this).parent().find('li').length) {
      $('.menu-mon-compte ul').toggleClass('toggled');
      return false;
    } else {
      return true;
    }
  });

  $('.page-connect div.grid-1-3.newline').on('click', function() {
    if ($('div.grid-1-3.active.newline').length) {
      $('div.grid-1-3.active').removeClass('active');
      $('div.grid-1-3').last().addClass('active')
    } else {
      $('div.grid-1-3.active').prev().addClass('active');
      $('div.grid-1-3.active').last().removeClass('active');
    }
  });
  $('.page-connect div.grid-1-3.end-of-line').on('click', function() {
    if ($('div.grid-1-3.active.end-of-line').length) {
      $('div.grid-1-3.active').removeClass('active');
      $('div.grid-1-3').first().addClass('active')
    } else {
      $('div.grid-1-3.active').next().addClass('active');
      $('div.grid-1-3.active').first().removeClass('active');
    }
  });

  function init_gallery_cell() {
    var $gallery = $('.gallerycell');
    if ($gallery.length) {
      var $container = $('#gallery-carrousel');
      var $exit = $container.find('span.exit');
      var $previous = $container.find('span.previous');
      var $next = $container.find('span.next');
      var $gcounter = $container.find('span.counter');
      var $images = [];
      $gallery.find('.image-switch').each(function() {
        $images.push($(this).data('image-large'));
      });
      var $index = 0;
      $('.show-carrousel').on('click', function() {
        var $dialog = $container.dialog({modal: true, width: '96%'});
        $container.parent().css({'background': 'transparent', 'box-shadow': 'none'});
        $container.parent().find('.ui-dialog-titlebar').css({'display': 'none'});
        $index = -1;
        $next.click();
        return false;
      });
      $exit.on('click', function() {
        $container.dialog('close');
      });
      $previous.on('click', function() {
        $index -= 1;
        if ($index == -1 ) $index = $images.length -1;
        $container.css({'background-image': 'url("' + $images[$index] + '")'});
        $gcounter.html(' ' + ($index + 1) + '/' + $images.length);
      });
      $next.on('click', function() {
        $index += 1;
        if ($index == $images.length) $index = 0;
        $container.css({'background-image': 'url("' + $images[$index] + '")'});
        $gcounter.html(' ' + ($index + 1) + '/' + $images.length);
      });
      $(document).on('keyup', function(e) {
        if ($container.is(':visible')) {
          if (e.keyCode == 27) {
            $container.dialog('close');
          } else if (e.keyCode == 39) {
            $next.trigger('click');
          } else if (e.keyCode == 37) {
            $previous.trigger('click');
          }
          return true;
        }
      });
    }
  }
  init_gallery_cell();

  $(document).on('combo:cell-loaded', function(ev, elem) {
    if ($(elem).find('.gallerycell')) {
      init_gallery_cell();
    }
  });

  function init_group_titles_for_a11y() {
   $('.group-title h2').each(function(idx, elem) {
     if ($(elem).find('.a11y-toggle-link').length) return;
     var a = $(elem).append('<a class="a11y-toggle-link" href=""><span class="sr-only">plier/déplier la section</span></a>')
     $(a).on('click', function() {
        if ($(this).parents('.edit-mode').length) {
          return true;
        }
        $(this).parent().trigger('click');
        return false;
     });
   });
  }
  init_group_titles_for_a11y();

  $(document).on('combo:cell-loaded', function(ev, elem) {
    if ($(elem).find('.group-title')) {
      init_group_titles_for_a11y();
    }
  });

  function track_search(q) {
    // keep (anonymised) track of search terms used in internal search fields.
    if (typeof _paq !== 'undefined') {
      _paq.push(['trackSiteSearch', q]);
    }
  }

});
