package de.ph87.electro.circuit; import de.ph87.electro.circuit.calculation.Calculation; import de.ph87.electro.circuit.part.Part; import de.ph87.electro.circuit.part.PartDto; import de.ph87.electro.circuit.part.node.Node; import de.ph87.electro.circuit.wire.Wire; import de.ph87.electro.circuit.wire.WireDto; import lombok.Getter; import lombok.NonNull; import lombok.Setter; import java.awt.*; import java.io.File; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Stream; import static de.ph87.electro.CONFIG.ALIGN; public class Circuit { @Getter private final String created; @Getter private final List parts = new ArrayList<>(); private final List wires = new ArrayList<>(); @Setter @Getter private File file = null; public Circuit() { this.created = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); } @SuppressWarnings("unused") public Circuit(final File file, final CircuitDto dto) { this.created = dto.getCreated(); for (PartDto partDto : dto.getParts()) { final Part part = Part.fromDto(partDto); verifyFree(part.getPosition()); parts.add(part); } for (final WireDto wire : dto.getWires()) { final Node a = findNodeByUuid(wire.getA()).orElseThrow(); final Node b = findNodeByUuid(wire.getB()).orElseThrow(); wires.add(new Wire(a, b)); } } public Wire connect(final Node a, final Node b) { final Wire wire = new Wire(a, b); wires.add(wire); return wire; } public void disconnect(final Wire wire) { if (!wires.contains(wire)) { throw new RuntimeException(); } wires.remove(wire); wire.getA().getWires().remove(wire); wire.getB().getWires().remove(wire); } public T addPart(final T part) { if (parts.contains(part)) { throw new RuntimeException(); } verifyFree(part.getPosition()); parts.add(part); return part; } public void removePart(final Part part) { if (parts.remove(part)) { part.getNodes().stream().flatMap(node -> node.getWires().stream()).toList().forEach(this::disconnect); // jep, first toList(), then forEach (due to concurrent modification) } else { throw new RuntimeException(); } } public void verifyFree(final Point position) { if (isOccupied(position)) { throw new RuntimeException(); } } public boolean isOccupied(final Point position) { final Point aligned = ALIGN(position); return parts.stream().anyMatch(part -> part.getPosition().equals(aligned)); } public Stream streamParts() { return parts.stream(); } public Stream streamWires() { return wires.stream(); } public int getPartCount() { return parts.size(); } public Optional findPartByPosition(final Point position) { final Point aligned = ALIGN(position); return streamParts().filter(p -> p.getPosition().equals(aligned)).findFirst(); } public Optional findNodeByUuid(@NonNull final String nodeUuid) { return parts.stream().map(part -> part.findNodeByUuid(nodeUuid)).filter(Optional::isPresent).map(Optional::get).findFirst(); } public Optional findWireByPosition(final Point position) { return wires.stream().filter(wire -> wire.intersects(position)).findFirst(); } public File getPreviewFile() { if (file == null) { return null; } return new File(file.getAbsolutePath().replaceAll("\\.json$", ".png")); } public void evaluate() { Calculation.calculate(this); } }