/*
* 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/Format/GeoJSON.js
* @requires OpenLayers/Request.js
* @requires OpenLayers/Protocol.js
* @requires BKGWebMap/Util.js
* @requires BKGWebMap/Protocol.js
*/
/**
* @classdesc Basisklasse für Interaktion mit Ortssuche des BKG <br/>
* Das Geoindex Protokoll ist verantwortlich für die Interaktion mit dem Suchdienst Geoindex. Es werden im Wesentlichen
* zwei Suchanfragen unterstützt:
* <ul>
* <li>suggest: Vorschlagssuche für Autovervollständigung</li>
* <li>geocode: Objektsuche inkl. Geometrien</li>
* </ul>
*
* @constructor BKGWebMap.Protocol.Geoindex
* @param {object} options - Optionen für Protokoll
* @param {string} options.string - URL des Suchdienstes
* @param {string} options.srsName - 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.Geoindex = OpenLayers.Class({
/**
* URL des Suchdienstes
* @memberOf BKGWebMap.Protocol.Geoindex
* @type string
*/
url: null,
/**
* Projektion für Koordinaten.
* @memberOf BKGWebMap.Protocol.Geoindex
* @type string
*/
srs: null,
/**
* Räumliche Einschränkung für Suchanfragen.
* @memberOf BKGWebMap.Protocol.Geoindex
* @type OpenLayers.Bounds
*/
bounds: null,
/**
* Maximale Anzahl an Vorschlägen
* @memberOf BKGWebMap.Protocol.Geoindex
* @type int
*/
maxSuggestTerms : 10,
/**
* Parser für Features.
* @memberOf BKGWebMap.Protocol.Geoindex
* @type OpenLayers.Format
*/
featureParser: new OpenLayers.Format.GeoJSON(),
/**
* Autocomplete cache.
* @memberOf BKGWebMap.Protocol.Geoindex
* @type object
*/
cache : {},
/**
* Callback für Feature-Updates. Akzeptiert als Parameter zwei Arrays: features und suggestions.
* @memberOf BKGWebMap.Protocol.Geoindex
* @type function
*/
updateCallback: null,
/**
* Zeigt an, ob das Protokoll autocomplete unterstützt.
* @memberOf BKGWebMap.Protocol.Geoindex
* @type boolean
*/
canAutocomplete: true,
initialize: function (options) {
OpenLayers.Util.extend(this, options);
},
destroy: function() {
if(this.featureParser) {
this.featureParser.destroy();
this.featureParser = null;
}
},
getBBOX: function() {
return this.bounds.toBBOX(null, false) + ',' + this.srs;
},
/**
* Leert den Suggest-Cache
* @memberOf BKGWebMap.Protocol.Geoindex
*/
clearCache: function() {
this.cache = {};
},
/**
* Führt eine Vorschlagssuche aus.
* @memberOf BKGWebMap.Protocol.Geoindex
* @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 = BKGWebMap.Protocol.Response.SUCCESS;
response.suggestions = this.cache[term];
if(options.callback) options.callback.call(options.scope, response);
return response;
}
var params = {
request: "GetSuggestion",
query : term,
maxResults : this.maxSuggestTerms,
highlight : 1
};
if(this.bounds) {
params.bbox = this.getBBOX();
}
// request
response.request = OpenLayers.Request.GET({
url: this.url,
params: params,
callback: this.createCallback(this.handleResponse, response, options)
});
return response;
},
/**
* Führt die Ortssuche aus.
* @memberOf BKGWebMap.Protocol.Geoindex
* @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 });
// set the params
var params = {
request: "GetFeature",
query : term,
srsName : this.srs
};
if(this.bounds) {
params.bbox = this.getBBOX();
}
response.request = OpenLayers.Request.GET({
url: this.url,
params: params,
callback: this.createCallback(this.handleResponse, response, options)
});
return response;
},
/**
* Allgemeine Antwortauswertung.
* @memberOf BKGWebMap.Protocol.Geoindex
* @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.Geoindex
* @param {XMLHttpRequest} request
* @param {BKGWebMap.Protocol.Response} response
*/
parseGeocodeResponse: function(request, response) {
if ( request.responseText.length == 0 ) {
return;
}
var features = this.featureParser.read(request.responseText, null);
if(!features) {
return;
}
this.updateDataModel(features);
response.suggestions = BKGWebMap.Util.grep(features, function(value){ return value.attributes.type == 'MeintenSie';});
response.features = BKGWebMap.Util.grep(features, function(value){ return value.attributes.type != 'MeintenSie';});
},
/**
* Wertet die Antowrt einer Suggest-Anfrage aus.
* @memberOf BKGWebMap.Protocol.Geoindex
* @param {XMLHttpRequest} request
* @param {BKGWebMap.Protocol.Response} response
*/
parseSuggestResponse: function(request, response) {
if ( request.responseText.length == 0 ) {
return;
}
var data = new OpenLayers.Format.JSON().read(request.responseText, null);
if(!data || !data.suggestions) {
return;
}
response.suggestions = BKGWebMap.Util.map( function( item ) {
return { label: item, value: item.replace(/<\/?B>/g,"") };
}, data.suggestions );
this.cache[response.data] = response.suggestions;
},
/**
* Aktualisiert das Datenmodell entsprechend den neuen Geokodierungsdiensten.
* @memberOf BKGWebMap.Protocol.Geoindex
* @param {Array<OpenLayers.Feature.Vector>} features - Die FeatureCollection
*/
updateDataModel: function(features) {
BKGWebMap.Util.each(features, function(index, feature) {
if(feature.geometry == undefined)
return;
feature.attributes.bbox = feature.geometry;
feature.geometry = feature.geometry.getCentroid();
feature.attributes.text = feature.attributes.fulltext;
feature.attributes.typ = feature.attributes.type;
});
},
/**
* Erzeugt eine Funktion, die gegebene Funktion mit den Argumenten anwendet.
*
* @memberOf BKGWebMap.Protocol.Geoindex
* @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.Geoindex
* @param {BKGWebMap.Protocol.Response} response - Das Protokoll-Response-Objekt
*/
abort: function(response) {
if (response && response.request) {
response.request.abort();
}
},
CLASS_NAME: "BKGWebMap.Protocol.Geoindex"
});