All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.ext.vehicleparking.parkapi.ParkAPIUpdater Maven / Gradle / Ivy

package org.opentripplanner.ext.vehicleparking.parkapi;

import com.fasterxml.jackson.databind.JsonNode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.routing.vehicle_parking.VehicleParking;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingState;
import org.opentripplanner.updater.GenericJsonDataSource;
import org.opentripplanner.util.I18NString;
import org.opentripplanner.util.NonLocalizedString;
import org.opentripplanner.util.TranslatedString;

/**
 * Vehicle parking updater class for https://github.com/offenesdresden/ParkAPI format APIs.
 */
abstract class ParkAPIUpdater extends GenericJsonDataSource {

    private static final String JSON_PARSE_PATH = "lots";

    private final String feedId;
    private final Collection staticTags;

    public ParkAPIUpdater(ParkAPIUpdaterParameters parameters) {
        super(parameters.getUrl(), JSON_PARSE_PATH, parameters.getHttpHeaders());
        this.feedId = parameters.getFeedId();
        this.staticTags = parameters.getTags();
    }

    @Override
    protected VehicleParking parseElement(JsonNode jsonNode) {

        var capacity = parseCapacity(jsonNode);
        var availability = parseAvailability(jsonNode);

        I18NString note = null;
        if (jsonNode.has("notes") && !jsonNode.get("notes").isEmpty()) {
            var noteFieldIterator = jsonNode.path("notes").fields();
            Map noteLocalizations = new HashMap<>();
            while (noteFieldIterator.hasNext()) {
                var noteFiled = noteFieldIterator.next();
                noteLocalizations.put(noteFiled.getKey(), noteFiled.getValue().asText());
            }
            note = TranslatedString.getI18NString(noteLocalizations);
        }

        var vehicleParkId = createIdForNode(jsonNode);
        double x = jsonNode.path("coords").path("lng").asDouble();
        double y = jsonNode.path("coords").path("lat").asDouble();

        VehicleParking.VehicleParkingEntranceCreator entrance = builder -> builder
                .entranceId(new FeedScopedId(feedId, vehicleParkId.getId() + "/entrance"))
                .name(new NonLocalizedString(jsonNode.path("name").asText()))
                .x(x)
                .y(y)
                .walkAccessible(true)
                .carAccessible(true);

        var stateText = jsonNode.get("state").asText();
        var state = stateText.equals("closed")
                ? VehicleParkingState.CLOSED
                : VehicleParkingState.OPERATIONAL;

        var tags = parseTags(jsonNode, "lot_type", "address", "forecast", "state");
        tags.addAll(staticTags);

        var maybeCapacity = Optional.ofNullable(capacity);
        var bicyclePlaces = maybeCapacity.map(c -> hasPlaces(capacity.getBicycleSpaces())).orElse(false);
        var carPlaces= maybeCapacity.map(c -> hasPlaces(capacity.getCarSpaces())).orElse(true);
        var wheelChairAccessiblePlaces= maybeCapacity.map(c -> hasPlaces(capacity.getWheelchairAccessibleCarSpaces())).orElse(false);

        return VehicleParking.builder()
                .id(vehicleParkId)
                .name(new NonLocalizedString(jsonNode.path("name").asText()))
                .state(state)
                .x(x)
                .y(y)
                // TODO
                // .openingHours(parseOpeningHours(jsonNode.path("opening_hours")))
                // .feeHours(parseOpeningHours(jsonNode.path("fee_hours")))
                .detailsUrl(jsonNode.has("url") ? jsonNode.get("url").asText() : null)
                .imageUrl(jsonNode.has("image_url") ? jsonNode.get("image_url").asText() : null)
                .note(note)
                .capacity(capacity)
                .availability(availability)
                .bicyclePlaces(bicyclePlaces)
                .carPlaces(carPlaces)
                .wheelchairAccessibleCarPlaces(wheelChairAccessiblePlaces)
                .entrance(entrance)
                .tags(tags)
                .build();
    }

    abstract VehicleParkingSpaces parseCapacity(JsonNode jsonNode);

    abstract VehicleParkingSpaces parseAvailability(JsonNode jsonNode);

    protected VehicleParkingSpaces parseVehicleSpaces(
            JsonNode node,
            String bicycleTag,
            String carTag,
            String wheelchairAccessibleCarTag
    ) {
        var bicycleSpaces = parseSpacesValue(node, bicycleTag);
        var carSpaces = parseSpacesValue(node, carTag);
        var wheelchairAccessibleCarSpaces = parseSpacesValue(node, wheelchairAccessibleCarTag);

        if (bicycleSpaces == null && carSpaces == null && wheelchairAccessibleCarSpaces == null) {
            return null;
        }

        return createVehiclePlaces(carSpaces, wheelchairAccessibleCarSpaces, bicycleSpaces);
    }

    private VehicleParkingSpaces createVehiclePlaces(
            Integer carSpaces,
            Integer wheelchairAccessibleCarSpaces,
            Integer bicycleSpaces
    ) {
        return VehicleParkingSpaces.builder()
                .bicycleSpaces(bicycleSpaces)
                .carSpaces(carSpaces)
                .wheelchairAccessibleCarSpaces(wheelchairAccessibleCarSpaces)
                .build();
    }

    private boolean hasPlaces(Integer spaces) {
        return spaces != null && spaces > 0;
    }

    // TODO
    // private TimeRestriction parseOpeningHours(JsonNode jsonNode) {
    //     if (jsonNode == null || jsonNode.asText().isBlank()) {
    //         return null;
    //     }

    //     return OsmOpeningHours.parseFromOsm(jsonNode.asText());
    // }

    private Integer parseSpacesValue(JsonNode jsonNode, String fieldName) {
        if (!jsonNode.has(fieldName)) {
            return null;
        }
        return jsonNode.get(fieldName).asInt();
    }

    private FeedScopedId createIdForNode(JsonNode jsonNode) {
        String id;
        if (jsonNode.has("id")) {
            id = jsonNode.path("id").asText();
        }
        else {
            id = String.format("%s/%f/%f", jsonNode.get("name"),
                    jsonNode.path("coords").path("lng").asDouble(),
                    jsonNode.path("coords").path("lat").asDouble()
            );
        }
        return new FeedScopedId(feedId, id);
    }

    private List parseTags(JsonNode node, String... tagNames) {
        var tagList = new ArrayList();
        for (var tagName : tagNames) {
            if (node.has(tagName)) {
                tagList.add(tagName + ":" + node.get(tagName).asText());
            }
        }
        return tagList;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy