RailSignalAPI/src/main/java/nl/andrewl/railsignalapi/service/ComponentCreationService.java

105 lines
4.3 KiB
Java

package nl.andrewl.railsignalapi.service;
import lombok.RequiredArgsConstructor;
import nl.andrewl.railsignalapi.dao.ComponentRepository;
import nl.andrewl.railsignalapi.dao.RailSystemRepository;
import nl.andrewl.railsignalapi.dao.SegmentRepository;
import nl.andrewl.railsignalapi.model.component.Label;
import nl.andrewl.railsignalapi.model.RailSystem;
import nl.andrewl.railsignalapi.model.Segment;
import nl.andrewl.railsignalapi.model.component.*;
import nl.andrewl.railsignalapi.rest.dto.component.in.*;
import nl.andrewl.railsignalapi.rest.dto.component.out.ComponentResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import java.util.HashSet;
import java.util.Set;
@Service
@RequiredArgsConstructor
public class ComponentCreationService {
private final RailSystemRepository railSystemRepository;
private final ComponentRepository<Component> componentRepository;
private final SegmentRepository segmentRepository;
@Transactional
public ComponentResponse create(long rsId, ComponentPayload payload) {
RailSystem rs = railSystemRepository.findById(rsId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
String name = payload.name;
if (name == null || name.isBlank()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Missing required name.");
}
if (componentRepository.existsByNameAndRailSystem(name, rs)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Component with that name already exists.");
}
ComponentType type;
try {
type = ComponentType.valueOf(payload.type);
} catch (IllegalArgumentException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid component type.", e);
}
Component c = switch (type) {
case SIGNAL -> createSignal(rs, (SignalPayload) payload);
case SWITCH -> createSwitch(rs, (SwitchPayload) payload);
case SEGMENT_BOUNDARY -> createSegmentBoundary(rs, (SegmentBoundaryPayload) payload);
case LABEL -> createLabel(rs, (LabelPayload) payload);
};
c = componentRepository.save(c);
return ComponentResponse.of(c);
}
private Component createLabel(RailSystem rs, LabelPayload payload) {
return new Label(rs, payload.position, payload.name, payload.text);
}
private Component createSignal(RailSystem rs, SignalPayload payload) {
long segmentId = payload.segment.id;
Segment segment = segmentRepository.findById(segmentId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
return new Signal(rs, payload.position, payload.name, segment);
}
private Component createSwitch(RailSystem rs, SwitchPayload payload) {
Switch s = new Switch(rs, payload.position, payload.name, new HashSet<>(), new HashSet<>(), null);
s = componentRepository.save(s);
for (var config : payload.possibleConfigurations) {
Set<PathNode> pathNodes = new HashSet<>();
for (var node : config.nodes) {
Component c = componentRepository.findById(node.id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
if (c instanceof PathNode pathNode) {
pathNodes.add(pathNode);
s.getConnectedNodes().add(pathNode);
pathNode.getConnectedNodes().add(s);
componentRepository.save(pathNode);
} else {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Id " + node.id + " does not refer to a PathNode component.");
}
}
s.getPossibleConfigurations().add(new SwitchConfiguration(s, pathNodes));
}
if (s.getPossibleConfigurations().size() < 2) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "At least two switch configurations are needed.");
}
return s;
}
private Component createSegmentBoundary(RailSystem rs, SegmentBoundaryPayload payload) {
Set<Segment> segments = new HashSet<>();
for (var segmentP : payload.segments) {
Segment segment = segmentRepository.findById(segmentP.id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
segments.add(segment);
}
if (segments.size() < 1 || segments.size() > 2) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid number of segments.");
}
return new SegmentBoundaryNode(rs, payload.position, payload.name, new HashSet<>(), segments);
}
}