// Copyright © 2015 HSL <https://www.hsl.fi> // This program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses. package fi.hsl.parkandride.core.service.reporting; import fi.hsl.parkandride.back.RegionRepository; import fi.hsl.parkandride.core.back.UtilizationRepository; import fi.hsl.parkandride.core.domain.*; import fi.hsl.parkandride.core.service.*; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import static fi.hsl.parkandride.core.domain.CapacityType.*; import static fi.hsl.parkandride.core.domain.DayType.*; import static java.lang.String.join; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; public class HubsAndFacilitiesReportService extends AbstractReportService { private static final String REPORT_NAME = "HubsAndFacilities"; public HubsAndFacilitiesReportService(FacilityService facilityService, OperatorService operatorService, ContactService contactService, HubService hubService, UtilizationRepository utilizationRepository, RegionRepository regionRepository, TranslationService translationService, FacilityHistoryService facilityHistoryService) { super(REPORT_NAME, facilityService, operatorService, contactService, hubService, utilizationRepository, translationService, regionRepository, facilityHistoryService); } @Override protected Excel generateReport(ReportContext ctx, ReportParameters params) { Excel excel = new Excel(); addRegionsSheet(excel, new ArrayList<>(ctx.hubs.values()), ctx); addFacilitiesSheet(excel, new ArrayList<>(ctx.facilities.values()), ctx); excel.addSheet(excelUtil.getMessage("reports.hf.sheets.legend"), excelUtil.getMessage("reports.hf.legend").split("\n")); return excel; } private void addFacilitiesSheet(Excel excel, List<Facility> facilities, ReportContext ctx) { excel.addSheet(excelUtil.getMessage("reports.hf.sheets.facilities"), facilities, asList( excelUtil.tcol("reports.hf.facility.facilityName", (Facility f) -> f.name), excelUtil.tcol("reports.hf.facility.aliases", (Facility f) -> join(", ", f.aliases)), excelUtil.tcol("reports.hf.facility.hubs", (Facility f) -> ctx.hubsByFacilityId.getOrDefault(f.id, emptyList()).stream().map((Hub h) -> h.name.fi).collect(joining(", "))), excelUtil.tcol("reports.hf.facility.operator", (Facility f) -> ctx.operators.get(f.operatorId).name), excelUtil.tcol("reports.hf.facility.status", (Facility f) -> translationService.translate(f.status)), excelUtil.tcol("reports.hf.facility.statusDescription", (Facility f) -> f.statusDescription), excelUtil.tcol("reports.hf.facility.locX", (Facility f) -> f.location.getCentroid().getX()), excelUtil.tcol("reports.hf.facility.locY", (Facility f) -> f.location.getCentroid().getY()), excelUtil.tcol("reports.hf.facility.openingHoursbusinessDay", (Facility f) -> ExcelUtil.time(f.openingHours.byDayType.get(BUSINESS_DAY))), excelUtil.tcol("reports.hf.facility.openingHoursSaturday", (Facility f) -> ExcelUtil.time(f.openingHours.byDayType.get(SATURDAY))), excelUtil.tcol("reports.hf.facility.openingHoursSunday", (Facility f) -> ExcelUtil.time(f.openingHours.byDayType.get(SUNDAY))), excelUtil.tcol("reports.hf.facility.openingHoursInfo", (Facility f) -> f.openingHours.info), excelUtil.tcol("reports.hf.facility.motorCapacity", (Facility f) -> capacitySum(f.builtCapacity, motorCapacityList)), excelUtil.tcol("reports.hf.facility.bicycleCapacity", (Facility f) -> capacitySum(f.builtCapacity, bicycleCapacityList)), excelUtil.tcol("reports.hf.facility.car", (Facility f) -> f.builtCapacity.getOrDefault(CAR, 0)), excelUtil.tcol("reports.hf.facility.disabled", (Facility f) -> f.builtCapacity.getOrDefault(DISABLED, 0)), excelUtil.tcol("reports.hf.facility.electricCar", (Facility f) -> f.builtCapacity.getOrDefault(ELECTRIC_CAR, 0)), excelUtil.tcol("reports.hf.facility.motorcycle", (Facility f) -> f.builtCapacity.getOrDefault(MOTORCYCLE, 0)), excelUtil.tcol("reports.hf.facility.bicycle", (Facility f) -> f.builtCapacity.getOrDefault(BICYCLE, 0)), excelUtil.tcol("reports.hf.facility.bicycleSecure", (Facility f) -> f.builtCapacity.getOrDefault(BICYCLE_SECURE_SPACE, 0)), excelUtil.tcol("reports.hf.facility.pricing", (Facility f) -> f.pricing.stream().map((p) -> translationService.translate(p.usage)).distinct().collect(joining(", "))), excelUtil.tcol("reports.hf.facility.paymentMethod", (Facility f) -> f.paymentInfo.paymentMethods.stream().map(m -> translationService.translate(m)).collect(joining(", "))), excelUtil.tcol("reports.hf.facility.paymentMethodInfo", (Facility f) -> f.paymentInfo.detail), excelUtil.tcol("reports.hf.facility.services", (Facility f) -> f.services.stream().map(s -> translationService.translate(s)).collect(joining(", "))), excelUtil.tcol("reports.hf.facility.emergencyContact", (Facility f) -> contactText(f.contacts.emergency)), excelUtil.tcol("reports.hf.facility.operatorContact", (Facility f) -> contactText(f.contacts.operator)), excelUtil.tcol("reports.hf.facility.serviceContact", (Facility f) -> contactText(f.contacts.service)) )); } private void addRegionsSheet(Excel excel, List<Hub> hubs, ReportContext ctx) { excel.addSheet(excelUtil.getMessage("reports.hf.sheets.hubs"), hubs, asList( excelUtil.tcol("reports.hf.hub.name", (Hub h) -> h.name), excelUtil.tcol("reports.hf.hub.address", (Hub h) -> addressText(h.address)), excelUtil.tcol("reports.hf.hub.locX", (Hub h) -> h.location.getX()), excelUtil.tcol("reports.hf.hub.locY", (Hub h) -> h.location.getY()), excelUtil.tcol("reports.hf.hub.motorCapacity", (Hub h) -> capacitySum(ctx, h.id, motorCapacities)), excelUtil.tcol("reports.hf.hub.bicycleCapacity", (Hub h) -> capacitySum(ctx, h.id, bicycleCapacities)), excelUtil.tcol("reports.hf.hub.car", (Hub h) -> capacitySum(ctx, h.id, CAR)), excelUtil.tcol("reports.hf.hub.disabled", (Hub h) -> capacitySum(ctx, h.id, DISABLED)), excelUtil.tcol("reports.hf.hub.electicCar", (Hub h) -> capacitySum(ctx, h.id, ELECTRIC_CAR)), excelUtil.tcol("reports.hf.hub.motorcycle", (Hub h) -> capacitySum(ctx, h.id, MOTORCYCLE)), excelUtil.tcol("reports.hf.hub.bicycle", (Hub h) -> capacitySum(ctx, h.id, BICYCLE)), excelUtil.tcol("reports.hf.hub.bicycleSecure", (Hub h) -> capacitySum(ctx, h.id, BICYCLE_SECURE_SPACE)), excelUtil.tcol("reports.hf.hub.facilities", (Hub h) -> ctx.facilitiesByHubId.getOrDefault(h.id, emptyList()).stream().map((Facility f) -> f.name.fi).collect(toList())) )); } private static <T> StringBuilder appendIfNotNull(StringBuilder sb, T toAppend, Function<T, Object> fn, boolean separator) { if (toAppend != null) { if (separator) { sb.append(", "); } sb.append(fn.apply(toAppend)); } return sb; } private static <T> StringBuilder appendIfNotNull(StringBuilder sb, T toAppend, Function<T, Object> fn) { return appendIfNotNull(sb, toAppend, fn, true); } private static <T> StringBuilder appendIfNotNull(StringBuilder sb, T toAppend) { return appendIfNotNull(sb, toAppend, a -> a); } private static CharSequence addressText(Address address) { if (address == null) { return null; } StringBuilder sb = new StringBuilder(); MultilingualString street = address.getStreetAddress(); appendIfNotNull(sb, street, st -> st.fi, false); appendIfNotNull(sb, address.postalCode); appendIfNotNull(sb, address.city, city -> city.fi); return sb; } private CharSequence contactText(Long contactId) { if (contactId == null) { return null; } Contact contact = contactService.getContact(contactId); StringBuilder sb = new StringBuilder(); sb.append(contact.name.fi); appendIfNotNull(sb, contact.phone); appendIfNotNull(sb, contact.email); appendIfNotNull(sb, contact.address, addr -> addressText(addr)); appendIfNotNull(sb, contact.openingHours, oh -> oh.fi); appendIfNotNull(sb, contact.info, info -> info.fi); return sb; } private int capacitySum(ReportContext ctx, long hubId, CapacityType... types) { List<Facility> facilities = ctx.facilitiesByHubId.getOrDefault(hubId, emptyList()); return facilities.stream() .mapToInt(f -> capacitySum(f.builtCapacity, asList(types))) .sum(); } private static int capacitySum(Map<CapacityType, Integer> capacityValues, List<CapacityType> capacityTypes) { return capacityTypes.stream().mapToInt(type -> capacityValues.getOrDefault(type, 0)).sum(); } }