# Source: bemap-services/bemap-autocomplete.js

    /**
     * BeNomad BeMap JavaScript API - Autocomplete
     */

    /**
     * @classdesc
     * Base class for Autocomplete.
     * @public
     * @constructor
     * @abstract
     * @param {bemap.Context} context BeMap-JS-API Context. Mandatory.
     * @param {object} options see below the available values.
     */
    bemap.Autocomplete = function(context, options) {
      this.context = context;
      this.geoserver = context.geoserver;

      var opts = options ? options : {};

      if (opts.geoserver) {
        this.geoserver = opts.geoserver;
      }
    };

    /**
     * Generate the BeMap request in URL encoded format.
     * Excute the request by calling the BeMap server and wait the answer.
     * @ppublic
     * @param {bemap.map} map To get coords needed in autocomplete propositions.
     * @param {string} query String to search.
     * @param {function} listener The function to call to get click data.
     */
    bemap.Autocomplete.prototype.query = function(map, query, listener) {
      if (!map) {
        console.error("Map is required!");
      } else {
        var coordinate = map.getCenter()
      }
      var url = bemapMainCtx.getBaseUrl() + 'service/geocoding/autocomplete/1.0?' + bemapMainCtx.getAuthUrlParams();
      var request = {
        "geoserver": this.geoserver,
        "addressDetails": true,
        "coordinate": {
          "longitude": coordinate.getLon(),
          "latitude": coordinate.getLat()
        },
        "place": query
      };
      bemap.ajax('POST', url, request, function(xhr, response) {
        var responseJson = JSON.parse(response);
        var data = [];
        var items = responseJson.items;

        for (var i = 0; i < items.length; i++) {
          var item = items[i];
          var label = item.place.replace(/\|/g, '').replace(/ {2,}/g, ' ');
          data.push({
            value: label,
            label: label,
            item: item
          });
        }
        if (listener) {
          listener(data);
        };
      });
    };

    /**
     * Create the autocomplete event on input with animations if needed
     * @private
     * @param {object} options see below the available values.
     * @param {bemap.map} map Need map to create request.
     * @param {string} id Index of html element or object with html element.
     * @param {function} selectListener the function to call to get data from selected item
     * @param {boolean} animation Show or not animations (need bootstrap to work)
     * @return {boolean} true if selected item
     */
    bemap.Autocomplete.prototype.autocomp = function(options, selectListener) {

      var map = options.map ? options.map : console.error("Map is required");
      var id = options.id ? options.id : console.error("Id is required");
      var animation = options.animation ? options.animation : false;
      var that = this;
      var tag = $(id);
      var parentTag = tag.parent();
      var feedbackTag = $('.form-control-feedback', parentTag);
      if (animation) {
        tag.keyup(function() {
          if ($(this).val() == "") {
            parentTag.parent().removeClass('has-success has-warning');
            feedbackTag.removeClass('glyphicon-ok glyphicon-refresh');
          }
        });
      }
      tag.autocomplete({
        source: function(request, response) {
          if (animation) {
            parentTag.parent().removeClass('has-success').addClass('has-warning');
            feedbackTag.removeClass('glyphicon-ok');
            feedbackTag.addClass('glyphicon-refresh');
          }
          //send request to server to get list of propositions
          that.query(map, request.term, function(data) {
            response(data);
          });
        },
        select: function(event, ui) {
          if (animation) {
            feedbackTag.addClass('glyphicon-refresh-animate');
            parentTag.parent().removeClass('has-warning').addClass('has-success');
            feedbackTag.removeClass('glyphicon-refresh-animate');
            feedbackTag.removeClass('glyphicon-refresh');
            feedbackTag.addClass('glyphicon-ok');
          }

          if (selectListener) {
            selectListener(ui.item.item);
          };
          return true;
        }
      });
    };

    /**
     * Parse data to create marker on map
     * @public
     * @param {bemap.Map} map for creating new marker.
     * @param {bemap.Coordinate} coordinates Array of bemap.Coordinate.
     * @param {object} options see below the available values.
     */
    bemap.Autocomplete.prototype.showOnMap = function(map, coord, options) {

      var opts = options ? options : {};

      var layer = opts.layer ? opts.layer : '';

      if (!coord) {
        console.error("Coordinates are required!");
      }

      var coordinate = coord;
      //map.move(coordinate.longitude, coordinate.latitude, 15);
      var c = new bemap.Coordinate(coordinate.longitude, coordinate.latitude);

      var icon = new bemap.Icon({
        src: opts.src ? opts.src : 'start.svg',
        anchorX: opts.anchorX ? opts.anchorX : 0.25,
        anchorY: opts.anchorY ? opts.anchorY : 1,
        anchorXUnits: opts.anchorXUnits ? opts.anchorXUnits : 'fraction',
        anchorYUnits: opts.anchorYUnits ? opts.anchorYUnits : 'fraction',
        scale: opts.scale ? opts.scale : 1
      });

      if (!bemap.marker) {
        var marker = new bemap.Marker(c, {
          icon: icon
        });
        if (layer) {
          map.addMarker(marker, {
            layer: layer
          });
        }else {
          map.addMarker(marker);
        };
        bemap.marker = marker;
      }
      bemap.marker.setCoordinate(c);
    };