var addSearch = function(map) {

  // Initialize the location marker
  var element = $('<div class="marker"></div>');
  var popup = new ol.Overlay({
    positioning:'bottom-center',
    element: element 
  });
  map.addOverlay(popup);

  // Detection of coordinate
  var isCoordinates =  function(extent, query) {
    var DMSDegree = '[0-9]{1,2}[°|º]\\s*';
    var DMSMinute = '[0-9]{1,2}[\'|′]';
    var DMSSecond = '(?:\\b[0-9]+(?:\\.[0-9]*)?|\\.' +
      '[0-9]+\\b)("|\'\'|′′|″)';
    var DMSNorth = '[N]';
    var DMSEast = '[E]';
    var regexpDMSN = new RegExp(DMSDegree +
      '(' + DMSMinute + ')?\\s*' +
      '(' + DMSSecond + ')?\\s*' +
      DMSNorth, 'g');
    var regexpDMSE = new RegExp(DMSDegree +
      '(' + DMSMinute + ')?\\s*' +
      '(' + DMSSecond + ')?\\s*' +
      DMSEast, 'g');
    var regexpDMSDegree = new RegExp(DMSDegree, 'g');
    var regexpCoordinate = new RegExp(
      '([\\d\\.\']+)[\\s,]+([\\d\\.\']+)');

    var position;
    var valid = false;

    var matchDMSN = query.match(regexpDMSN);
    var matchDMSE = query.match(regexpDMSE);
    if (matchDMSN && matchDMSN.length == 1 &&
      matchDMSE && matchDMSE.length == 1) {
      var northing = parseFloat(matchDMSN[0].
        match(regexpDMSDegree)[0].
          replace('°' , '').replace('º' , ''));
      var easting = parseFloat(matchDMSE[0].
        match(regexpDMSDegree)[0].
        replace('°' , '').replace('º' , ''));
      var minuteN = matchDMSN[0].match(DMSMinute) ?
        matchDMSN[0].match(DMSMinute)[0] : '0';
      northing = northing +
        parseFloat(minuteN.replace('\'' , '').
          replace('′' , '')) / 60;
      var minuteE = matchDMSE[0].match(DMSMinute) ?
        matchDMSE[0].match(DMSMinute)[0] : '0';
      easting = easting +
        parseFloat(minuteE.replace('\'' , '').
          replace('′' , '')) / 60;
      var secondN =
        matchDMSN[0].match(DMSSecond) ?
        matchDMSN[0].match(DMSSecond)[0] : '0';
      northing = northing + parseFloat(secondN.replace('"' , '')
        .replace('\'\'' , '').replace('′′' , '')
        .replace('″' , '')) / 3600;
      var secondE = matchDMSE[0].match(DMSSecond) ?
        matchDMSE[0].match(DMSSecond)[0] : '0';
      easting = easting + parseFloat(secondE.replace('"' , '')
        .replace('\'\'' , '').replace('′′' , '')
        .replace('″' , '')) / 3600;
      position = ol.proj.transform([easting, northing],
            'EPSG:4326', 'EPSG:21781');
      if (ol.extent.containsCoordinate(
        extent, position)) {
        valid = true;
      }
    }

    var match =
      query.match(regexpCoordinate);
    if (match && !valid) {
      var left = parseFloat(match[1].replace('\'', ''));
      var right = parseFloat(match[2].replace('\'', ''));
      position =
        [left > right ? left : right,
          right < left ? right : left];
      if (ol.extent.containsCoordinate(
          extent, position)) {
        valid = true;
      } else {
        position = ol.proj.transform(position,
          'EPSG:2056', 'EPSG:21781');
        if (ol.extent.containsCoordinate(
            extent, position)) {
          valid = true;
        } else {
          position =
            [left < right ? left : right,
              right > left ? right : left];
          position = ol.proj.transform(position,
            'EPSG:4326', 'EPSG:21781');
          if (ol.extent.containsCoordinate(
            extent, position)) {
            valid = true;
          }
        }
      }
    }
    return valid ?
      [Math.round(position[0] * 1000) / 1000,
      Math.round(position[1] * 1000) / 1000] : undefined;
  };

  // Initialize the suggestion engine
  var mySource = new Bloodhound({
    limit: 30,
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
    queryTokenizer: function(query) {
      var center = isCoordinates(map.getView().getProjection().getExtent(), query);
      if (center) {
        map.getView().setCenter(center);
        popup.setPosition(center);
      }
      return Bloodhound.tokenizers.whitespace;
    },
    remote: {
      url: '//api3.geo.admin.ch/rest/services/api/SearchServer?searchText=%QUERY&type=locations',
      filter: function(locations) {   
        return locations.results;
      }
    }
  });
  
  // This kicks off the loading and processing of local and prefetch data,
  // the suggestion engine will be useless until it is initialized
  mySource.initialize();
  
  // Initialize typeahead input
  $('#searchTypeAhead').typeahead(null, {
    name: 'locations',
    displayKey: function(location) {
      return location.attrs.label.replace('<b>', '').replace('</b>', '');
    },
    source: mySource.ttAdapter(),
    templates: {
      suggestion: function(location) {
        return '<p>' + location.attrs.label + '</p>' ;
      } 
    }                                      
  });
  
  var parseExtent = function(stringBox2D) {
    var extent = stringBox2D.replace('BOX(', '').replace(')', '').replace(',', ' ').split(' ');
    return $.map(extent, parseFloat);
  };
  
  // When a result is selected.
  $('#searchTypeAhead').on('typeahead:selected', function(evt, location, suggName) {
    var originZoom = {
      address: 10,
      parcel: 10,
      sn25: 8,
      feature: 7
    };
    var view = map.getView();
    var origin = location.attrs.origin;
    var extent = [0, 0, 0, 0];
    if (location.attrs.geom_st_box2d) {
      extent = parseExtent(location.attrs.geom_st_box2d);
    } else if (location.attrs.x && location.attrs.y) {
      var x = location.attrs.y;
      var y = location.attrs.x;
      extent = [x, y, x, y]; 
    }
  
    if (originZoom.hasOwnProperty(origin)) {
      var zoom = originZoom[origin];
      var center = [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];
      view.setZoom(zoom);
      view.setCenter(center);
      popup.setPosition(center);
    } else {
      popup.setPosition(undefined);
      view.fitExtent(extent, map.getSize());
    }
  });

};
