blob: 32982323a7975ff8dbddf0f74e669fd0a89f92f1 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {HttpClient} from "@angular/common/http";
import {Inject, Injectable} from "@angular/core";
import {Actions, createEffect, ofType} from "@ngrx/effects";
import {Action} from "@ngrx/store";
import {Observable, of} from "rxjs";
import {ignoreElements, switchMap} from "rxjs/operators";
import {APP_CONFIGURATION, GeoApiService, IAPIGeographicPositions, IAppConfiguration, WINDOW} from "../../../../core";
import {ILeafletBounds} from "../../../../features/map";
import {catchErrorTo, ignoreError} from "../../../../util/rxjs";
import {EErrorCode, setErrorAction} from "../../../root";
import {openGisAction} from "../../actions";
@Injectable({providedIn: "root"})
export class OpenGisEffect {
public open$ = createEffect(() => this.actions.pipe(
ofType(openGisAction),
switchMap((action) => this.openGis(action.bounds, action.user))
));
/**
* URL Template to connect with GIS.
*/
public gisUrlTemplate = this.configuration.gis.urlTemplate;
/**
* Expected projection format for the given Leaflet coordinates.
*/
public projectionFrom = this.configuration.gis.projectionFrom;
/**
* Expected projection required for the GIS.
*/
public projectionTo = this.configuration.gis.projectionTo;
/**
* Search parameter keys which are transformed in the GIS URL template.
*/
public coordinateKeys: Array<keyof ILeafletBounds> = ["center", "northEast", "northWest", "southEast", "southWest"];
public constructor(
public actions: Actions,
public geoApiService: GeoApiService,
public http: HttpClient,
@Inject(WINDOW) public window: Window,
@Inject(APP_CONFIGURATION) public configuration: IAppConfiguration
) {
}
public openGis(bounds: ILeafletBounds, user: string): Observable<Action> {
return of(bounds).pipe(
switchMap(() => this.transform(this.extractGeographicPositionFromBounds(bounds))),
switchMap((geographicPositions) => {
const gisUrl = this.generateUrl(geographicPositions, user);
return this.http.get(gisUrl, {responseType: "text"}).pipe(ignoreError());
}),
ignoreElements(),
catchErrorTo(setErrorAction({error: EErrorCode.UNEXPECTED}))
);
}
/**
* Extract all required geographic positions from the given Leaflet bounds.
*/
public extractGeographicPositionFromBounds(bounds: ILeafletBounds): IAPIGeographicPositions {
const geographicPositions: IAPIGeographicPositions = {};
this.coordinateKeys.forEach((key) => {
const value = bounds[key];
if (typeof value !== "object") {
return;
}
const tokens = [`{${key}X}`, `{${key}Y}`];
if (tokens.some((token) => this.gisUrlTemplate.indexOf(token) > -1)) {
geographicPositions[key] = {
x: value.lng,
y: value.lat
};
}
});
return geographicPositions;
}
/**
* Transforms a set of geographic positions via an API back end call.
*/
public transform(geographicPositions: IAPIGeographicPositions): Observable<IAPIGeographicPositions> {
return Object.keys(geographicPositions).length > 0 ?
this.geoApiService.transform(geographicPositions, this.projectionFrom, this.projectionTo) :
of(geographicPositions);
}
/**
* Generate the URL to the GIS with a set of given geographic positions.
*/
public generateUrl(geographicPositions: IAPIGeographicPositions, user: string) {
let result = this.gisUrlTemplate;
Object.entries(geographicPositions).forEach(([key, value]) => {
result = result.replace(new RegExp(`{${key}X}`, "g"), "" + value.x);
result = result.replace(new RegExp(`{${key}Y}`, "g"), "" + value.y);
});
result = result.replace(new RegExp(`{user}`, "g"), user);
return result;
}
}