/*
* Copyright (c) 2013 Bundesamt by Kartographie und Geodäsie.
* See license.txt in the BKG WebMap distribution or repository for the
* full text of the license.
*
* Author: Dirk Thalheim
*/
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Protocol.js
* @requires OpenLayers/Format/GeoJSON.js
* @requires OpenLayers/Request.js
* @requires BKGWebMap/Util.js
* @requires BKGWebMap/Protocol.js
*/
/**
* @classdesc Basisklasse für Interaktion mit Ortssuche des BKGs basierend auf der OpenSearch-Schnittstelle.<br/>
* Das Geokodierungs-Protokoll kann für die Dienste gdz_ortssuche, gdz_geokodierung und gdz_geokodierung_bund verwendet
* werden. Es werden zwei Suchanfragen unterstützt:
* <ul>
* <li>suggest: Vorschlagssuche für Autovervollständigung</li>
* <li>geocode: Objektsuche inkl. Geometrien</li>
* </ul>
*
* @constructor BKGWebMap.Protocol.Geokodierung
* @param {object} options - Optionen für Protokoll
* @param {string} options.url - URL des Suchdienstes
* @param {string} options.srs - Georeferenzierung für Suchergebnisse
* @param {OpenLayers.Bounds} options.bounds - Räumliche Einschränkung der Suche
* @param {string} options.maxSuggestTerms - Maximale Anzahl der Ergebnisse bei Vorschlagssuche
*/
BKGWebMap.Protocol.Geokodierung = OpenLayers.Class({
/**
* URL des Suchdienstes
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type string
*/
url: null,
/**
* Projektion für Koordinaten.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type string
*/
srs: null,
/**
* Räumliche Einschränkung für Suchanfragen.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type OpenLayers.Bounds
*/
bounds: null,
/**
* Maximale Anzahl an Vorschlägen
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type int
*/
maxSuggestTerms : 20,
/**
* Parser für Features.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type OpenLayers.Format
*/
featureParser: new OpenLayers.Format.GeoJSON(),
/**
* Parser für Suggestions.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type OpenLayers.Format
*/
suggestionParser: new OpenLayers.Format.JSON(),
/**
* Autocomplete cache.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type object
*/
cache : {},
/**
* Callback für Feature-Updates. Akzeptiert als Parameter zwei Arrays: features und suggestions.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type function
*/
updateCallback: null,
/**
* Zeigt an, ob das Protokoll autocomplete unterstützt.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @type boolean
*/
canAutocomplete: true,
initialize: function (options) {
OpenLayers.Util.extend(this, options);
},
destroy: function() {
if(this.featureParser) {
this.featureParser.destroy();
this.featureParser = null;
}
if(this.suggestionParser) {
this.suggestionParser.destroy();
this.suggestionParser = null;
}
},
/**
* Leert den Suggest-Cache
* @memberOf BKGWebMap.Protocol.Geoindex
*/
clearCache: function() {
this.cache = {};
},
/**
* Führt eine Vorschlagssuche aus.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {string} term - Suchterm
* @param {object} options - Response-Handling-Optionen
* @param {function} options.callback
* @param {object} options.scope
* @return {BKGWebMap.Protocol.Response}
*/
suggest: function( term, options ) {
var response = new BKGWebMap.Protocol.Response({ requestType: 'suggest', data: term });
// Falls im Cache vorhanden, dann diesen verwenden
if ( term in this.cache ) {
response.code = OpenLayers.Protocol.Response.SUCCESS;
response.suggestions = this.cache[term];
if(options.callback) options.callback.call(options.scope, response);
return response;
}
// URL für Suggest
var url = this.url + '/suggest.json';
// Parameter
var params = {
query : term,
count : this.maxSuggestTerms
};
if(this.bounds) {
params.bbox = this.bounds.toBBOX(null, false);
params.srsName = this.srs;
}
// Request ausführen
response.request = OpenLayers.Request.GET({
url: url,
params: params,
callback: this.createCallback(this.handleResponse, response, options)
});
return response;
},
/**
* Führt die Ortssuche aus.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {string} term - Suchterm
* @param {object} options - Response-Handling-Optionen
* @param {function} options.callback
* @param {object} options.scope
* @return {BKGWebMap.Protocol.Response}
*/
geocode: function( term, options ) {
var response = new BKGWebMap.Protocol.Response({ requestType: 'geocode', data: term });
// URL für Geocode
var url = this.url + '/geosearch.json';
// set the params
var params = {
query : term,
srsName : this.srs
};
if(this.bounds) {
params.bbox = this.bounds.toBBOX(null, false);
}
response.request = OpenLayers.Request.GET({
url: url,
params: params,
callback: this.createCallback(this.handleResponse, response, options)
});
return response;
},
/**
* Allgemeine Antwortauswertung.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {BKGWebMap.Protocol.Response} response - Responseobjekt
* @param {object} options - Response-Handling-Optionen
*/
handleResponse: function(response, options) {
var request = response.request;
if(request.status >= 200 && request.status < 300) {
// success
switch (response.requestType) {
case 'geocode':
this.parseGeocodeResponse(request, response);
break;
case 'suggest':
this.parseSuggestResponse(request, response);
break;
}
response.code = (response.features || response.suggestions) ?
OpenLayers.Protocol.Response.SUCCESS :
OpenLayers.Protocol.Response.FAILURE;
} else {
// failure
response.code = OpenLayers.Protocol.Response.FAILURE;
}
if(options.callback)
options.callback.call(options.scope, response);
},
/**
* Wertet die Antowrt einer Geocode-Anfrage aus.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {XMLHttpRequest} request
* @param {BKGWebMap.Protocol.Response} response
*/
parseGeocodeResponse: function(request, response) {
if ( request.responseText.length == 0 ) return;
response.features = this.featureParser.read(request.responseText, null);
this.updateDataModel(response.features);
},
/**
* Aktualisiert das Datenmodell. Hierbei wird sichergestellt, dass das bbox-Attribut eine Geometrie wird.
*
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {Array<OpenLayers.Feature.Vector>} features - Die FeatureCollection
*/
updateDataModel: function(features) {
var featureParser = this.featureParser;
BKGWebMap.Util.each(features, function(index, feature) {
if(feature.attributes.bbox)
feature.attributes.bbox = featureParser.parseGeometry(feature.attributes.bbox);
});
},
/**
* Wertet die Antowrt einer Suggest-Anfrage aus.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {XMLHttpRequest} request
* @param {BKGWebMap.Protocol.Response} response
*/
parseSuggestResponse: function(request, response) {
if ( request.responseText.length == 0 ) return;
var data = this.suggestionParser.read(request.responseText, null);
if(!data) return;
response.suggestions = BKGWebMap.Util.map(
function( item ) { return { label: item.highlighted, value: item.suggestion }; },
data
);
this.cache[response.data] = response.suggestions;
},
/**
* Erzeugt eine Funktion, die gegebene Funktion mit den Argumenten anwendet.
*
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {function} method - Zielfunktion
* @param {BKGWebMap.Protocol.Response} response - Das Protokoll-Response-Objekt
* @param {object} options - weitere Optionen für die Protokoll-Methode
* @return {function} die neue Wrapper-Funktion
*/
createCallback: function(method, response, options) {
return OpenLayers.Function.bind(function() { method.apply(this, [response, options]); }, this);
},
/**
* Bricht einen laufenden Request ab. Das Response-Objekt muss von diesem Protokoll stammen.
* @memberOf BKGWebMap.Protocol.Geokodierung
* @param {BKGWebMap.Protocol.Response} response - Das Protokoll-Response-Objekt
*/
abort: function(response) {
if (response && response.request) {
response.request.abort();
}
},
CLASS_NAME: "BKGWebMap.Protocol.Geokodierung"
});