package de.rwth.idsg.bikeman.service; import com.google.common.base.Optional; import de.rwth.idsg.bikeman.domain.Pedelec; import de.rwth.idsg.bikeman.domain.Station; import de.rwth.idsg.bikeman.domain.StationSlot; import de.rwth.idsg.bikeman.ixsi.service.AvailabilityPushService; import de.rwth.idsg.bikeman.psinterface.Utils; import de.rwth.idsg.bikeman.psinterface.dto.OperationState; import de.rwth.idsg.bikeman.psinterface.dto.request.PedelecStatusDTO; import de.rwth.idsg.bikeman.psinterface.dto.request.SlotDTO; import de.rwth.idsg.bikeman.psinterface.dto.request.StationStatusDTO; import de.rwth.idsg.bikeman.repository.PedelecRepository; import de.rwth.idsg.bikeman.repository.StationRepository; import de.rwth.idsg.bikeman.repository.StationSlotRepository; import de.rwth.idsg.bikeman.web.rest.dto.modify.CreateEditStationDTO; import org.joda.time.DateTime; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import xjc.schema.ixsi.TimePeriodType; import javax.inject.Inject; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; /** * Created by Wolfgang Kluth on 03/09/15. */ @Service @Transactional public class OperationStateService { @Inject private PedelecRepository pedelecRepository; @Inject private StationRepository stationRepository; @Inject private StationSlotRepository stationSlotRepository; @Inject private AvailabilityPushService availabilityPushService; public void pushStationChange(CreateEditStationDTO dto) { switch (dto.getState()) { case OPERATIVE: pushStationAvailability(dto.getManufacturerId()); break; case INOPERATIVE: pushStationInavailability(dto.getManufacturerId()); break; case DELETED: break; } } public void pushSlotChange(StationSlot slot) { switch (slot.getState()) { case OPERATIVE: pushSlotAvailability(slot.getStation().getManufacturerId(), slot.getManufacturerId()); break; case INOPERATIVE: pushSlotInavailability(slot.getStation().getManufacturerId(), slot.getManufacturerId()); break; case DELETED: break; } } // ------------------------------------------------------------------------- // PUSH INAVAILABILITY // ------------------------------------------------------------------------- private void pushStationInavailability(String stationManufacturerId) { List<String> pedelecManufacturerIds = pedelecRepository.findManufacturerIdsByStation(stationManufacturerId); pushInavailability(stationManufacturerId, pedelecManufacturerIds); } private void pushSlotInavailability(String stationManufacturerId, String slotManufacturerId) { Optional<Pedelec> pedelec = pedelecRepository.findPedelecsByStationSlot(stationManufacturerId, slotManufacturerId); if (pedelec.isPresent()) { pushInavailability(pedelec.get()); } } public void pushPedelecInavailability(String pedelecManufacturerId) { Pedelec pedelec = pedelecRepository.findByManufacturerId(pedelecManufacturerId); if (pedelec.getStationSlot() != null) { pushInavailability(pedelec); } } public void pushInavailability(StationStatusDTO dto) { if (isInoperative(dto.getStationState())) { pushStationInavailability(dto.getStationManufacturerId()); return; } if (Utils.isEmpty(dto.getSlots())) { return; } // For all inoperative slots, if there is a pedelec, get it's id List<String> pedelecManufacturerIds = dto.getSlots() .parallelStream() .filter(s -> isInoperative(s.getSlotState())) .map(s -> pedelecRepository.findPedelecsByStationSlot(dto.getStationManufacturerId(), s.getSlotManufacturerId())) .filter(Optional::isPresent) .map(s -> s.get().getManufacturerId()) .collect(Collectors.toList()); pushInavailability(dto.getStationManufacturerId(), pedelecManufacturerIds); } public void pushInavailability(PedelecStatusDTO dto) { if (isInoperative(dto.getPedelecState())) { pushPedelecInavailability(dto.getPedelecManufacturerId()); } } // ------------------------------------------------------------------------- // PUSH AVAILABILITY // ------------------------------------------------------------------------- private void pushStationAvailability(String stationManufacturerId) { List<Pedelec> pedelecs = pedelecRepository.findByStation(stationManufacturerId); List<String> pedelecManufacturerIds = pedelecs.parallelStream() .filter(this::shouldSendAvailability) .map(Pedelec::getManufacturerId) .collect(Collectors.toList()); pushAvailability(stationManufacturerId, pedelecManufacturerIds); } private void pushSlotAvailability(String stationManufacturerId, String slotManufacturerId) { Optional<Pedelec> pedelec = pedelecRepository.findPedelecsByStationSlot(stationManufacturerId, slotManufacturerId); if (pedelec.isPresent() && shouldSendAvailability(pedelec.get())) { pushAvailability(pedelec.get()); } } public void pushPedelecAvailability(String pedelecManufacturerId) { Pedelec pedelec = pedelecRepository.findByManufacturerId(pedelecManufacturerId); if (shouldSendAvailability(pedelec)) { pushAvailability(pedelec); } } public void pushAvailability(StationStatusDTO dto) { Station station = stationRepository.findByManufacturerId(dto.getStationManufacturerId()); if (becameOperative(station.getState(), dto.getStationState())) { pushStationAvailability(station.getManufacturerId()); return; } if (Utils.isEmpty(dto.getSlots())) { return; } // For all slots, that changed from inoperative to operative, if there is an operative pedelec, get it's id List<String> pedelecManufacturerIds = dto.getSlots() .parallelStream() .map(s -> getPedelecToPush(station, s)) .filter(Optional::isPresent) .map(p -> p.get().getManufacturerId()) .collect(Collectors.toList()); pushAvailability(dto.getStationManufacturerId(), pedelecManufacturerIds); } public void pushAvailability(PedelecStatusDTO dto) { if (isOperative(dto.getPedelecState())) { pushPedelecAvailability(dto.getPedelecManufacturerId()); } } // ------------------------------------------------------------------------- // Private helpers, mainly for DRY // ------------------------------------------------------------------------- private boolean shouldSendAvailability(Pedelec p) { return p.getStationSlot() != null && isOperative(p.getStationSlot().getState()) && isOperative(p.getStationSlot().getStation().getState()); } private boolean shouldSendAvailability(StationSlot slot, SlotDTO.StationStatus dto) { return slot.getPedelec() != null && becameOperative(slot.getState(), dto.getSlotState()); } private boolean becameOperative(de.rwth.idsg.bikeman.domain.OperationState oldState, OperationState newState) { return !isOperative(oldState) && isOperative(newState); } private boolean isOperative(de.rwth.idsg.bikeman.domain.OperationState os) { return os == de.rwth.idsg.bikeman.domain.OperationState.OPERATIVE; } private boolean isOperative(OperationState os) { return os == OperationState.OPERATIVE; } private boolean isInoperative(OperationState os) { return os == OperationState.INOPERATIVE; } private Optional<Pedelec> getPedelecToPush(Station station, SlotDTO.StationStatus dto) { StationSlot slot = stationSlotRepository.findByManufacturerId(dto.getSlotManufacturerId(), station.getManufacturerId()); if (shouldSendAvailability(slot, dto)) { return Optional.of(slot.getPedelec()); } else { return Optional.absent(); } } private void pushAvailability(Pedelec pedelec) { pushAvailability( pedelec.getStationSlot().getStation().getManufacturerId(), Collections.singletonList(pedelec.getManufacturerId()) ); } private void pushInavailability(Pedelec pedelec) { pushInavailability( pedelec.getStationSlot().getStation().getManufacturerId(), Collections.singletonList(pedelec.getManufacturerId()) ); } private TimePeriodType buildTimePeriod() { DateTime now = DateTime.now(); return new TimePeriodType() .withBegin(now) .withEnd(now.plusDays(90)); } // ------------------------------------------------------------------------- // Main methods for IXSI calls // // TODO: instead of pushing each pedelec on it's own, push a list // ------------------------------------------------------------------------- private void pushInavailability(String stationManufacturerId, List<String> idList) { if (Utils.isEmpty(idList)) { return; } TimePeriodType timePeriodType = buildTimePeriod(); idList.parallelStream() .forEach(s -> availabilityPushService.placedBooking(s, stationManufacturerId, timePeriodType)); } private void pushAvailability(String stationManufacturerId, List<String> idList) { if (Utils.isEmpty(idList)) { return; } TimePeriodType timePeriodType = buildTimePeriod(); idList.parallelStream() .forEach(s -> availabilityPushService.cancelledBooking(s, stationManufacturerId, timePeriodType)); } }