class GetLocationForStringCommand implements CommandHasRequest<GetLocationForStringRequest, GetLocationForStringResponse> {

	@Override
	public void execute(GetLocationForStringRequest request, GetLocationForStringResponse response) throws Exception {
		String location = request.getLocation();
		if (null == location) {
			throw new GeomajasException(ExceptionCode.PARAMETER_MISSING, "location");
		}
		String crsString = request.getCrs();
		if (null == crsString) {
			throw new GeomajasException(ExceptionCode.PARAMETER_MISSING, "crs");
		}
		Locale locale = null;
		if (null != request.getLocale()) {
			locale = new Locale(request.getLocale());
		}
		int maxAlternatives = request.getMaxAlternatives();

		Crs crs = geoService.getCrs2(crsString);

		SplitGeocoderStringService splitGeocoderStringService = geocoderInfo.getSplitGeocoderStringService();
		if (null == splitGeocoderStringService) {
			splitGeocoderStringService = defaultSplitGeocoderStringService;
		}
		CombineResultService combineResultService = geocoderInfo.getCombineResultService();
		if (null == combineResultService) {
			combineResultService = defaultCombineResultService;
		}

		List<String> locationList = splitGeocoderStringService.split(location);

		List<GetLocationResult> results = new ArrayList<GetLocationResult>();
		List<GetLocationResult[]> alternatives = new ArrayList<GetLocationResult[]>();
		Pattern namePattern = getShouldUsePattern(request.getServicePattern());
		for (GeocoderService geocoderService : geocoderInfo.getGeocoderServices()) {
			if (shouldUse(namePattern, geocoderService.getName())) {
				GetLocationResult[] result = geocoderService.getLocation(locationList, maxAlternatives, locale);
				if (null != result && result.length > 0) {
					for (GetLocationResult aResult : result) {
						aResult.setGeocoderName(geocoderService.getName());

						CoordinateReferenceSystem sourceCrs = geocoderService.getCrs();
						Envelope envelope = aResult.getEnvelope();

						// point locations needs to converted to an area based on configuration settings
						if (null == envelope) {
							envelope = geocoderUtilService.extendPoint(aResult.getCoordinate(), sourceCrs,
									geocoderInfo.getPointDisplayWidth(), geocoderInfo.getPointDisplayHeight());
						}

						// result needs to be CRS transformed to request CRS
						aResult.setEnvelope(geocoderUtilService.transform(envelope, sourceCrs, crs));
					}
					if (result.length > 1) {
						alternatives.add(result);
					} else {
						results.add(result[0]);
					}
					if (!geocoderInfo.isLoopAllServices()) {
						break;
					}
				}
			}
		}

		response.setLocationFound(false);
		if (!results.isEmpty()) {
			response.setLocationFound(true);

			// combine match strings, default to search string unless we know we can do better
			String matchedLocation = location;
			String geocoderName = null;
			if (results.size() == 1) {
				List<String> matchedStrings = results.get(0).getCanonicalStrings();
				if (null != matchedStrings) {
					matchedLocation = splitGeocoderStringService.combine(matchedStrings);
				}
				geocoderName = results.get(0).getGeocoderName();
			}
			response.setCanonicalLocation(matchedLocation);
			response.setGeocoderName(geocoderName);

			// combine the user data, only when there is just one result
			if (results.size() == 1) {
				response.setUserData(results.get(0).getUserData());
			}

			// combine location envelopes
			Envelope resultEnvelope = combineResultService.combine(results);
			Bbox bbox = dtoConverterService.toDto(resultEnvelope);
			response.setBbox(bbox);
			response.setCenter(new Coordinate(bbox.getX() + bbox.getWidth() / 2, bbox.getY() + bbox.getHeight() / 2));
		} else {
			List<GetLocationForStringAlternative> altList = new ArrayList<GetLocationForStringAlternative>();
			response.setAlternatives(altList);
			for (GetLocationResult[] altArr : alternatives) {
				for (GetLocationResult alt : altArr) {
					if (maxAlternatives > 0 && maxAlternatives <= altList.size()) {
						break;
					}
					GetLocationForStringAlternative one = new GetLocationForStringAlternative();

					String matchedLocation = location;
					List<String> matchedStrings = alt.getCanonicalStrings();
					if (null != matchedStrings) {
						matchedLocation = splitGeocoderStringService.combine(matchedStrings);
					}
					one.setCanonicalLocation(matchedLocation);

					// set additional info data
					one.setGeocoderName(alt.getGeocoderName());
					one.setUserData(alt.getUserData());

					// combine location envelopes
					Bbox bbox = dtoConverterService.toDto(alt.getEnvelope());
					one.setBbox(bbox);
					one.setCenter(
							new Coordinate(bbox.getX() + bbox.getWidth() / 2, bbox.getY() + bbox.getHeight() / 2));

					altList.add(one);
				}
			}
		}

	}

}